Compare commits

...

238 Commits

Author SHA1 Message Date
Brett Rowan
b790ad58a7 version: bump version number. 2024-03-23 20:27:42 -06:00
Brett Rowan
354ab793a2 bug: fix vnish MAC not working on some versions. 2024-03-23 20:25:26 -06:00
Upstream Data
59346d641f version: bump version number. 2024-03-22 15:12:35 -06:00
Upstream Data
11d770771b feature: fix vnish not having the shutdown flag. 2024-03-22 15:12:20 -06:00
Upstream Data
1b6db7ed45 feature: add antminer new API. 2024-03-22 13:42:10 -06:00
Upstream Data
55c4e10fae tests: Update tests, and fix some bugs. 2024-03-22 13:19:44 -06:00
Upstream Data
77c06dad61 version: bump version number. 2024-03-19 14:24:54 -06:00
Upstream Data
68d250d2f2 bug: fix K pro naming. 2024-03-19 14:24:31 -06:00
Upstream Data
094a17ac68 version: bump version number. 2024-03-19 14:17:21 -06:00
Upstream Data
dbcdeaa3de feature: add support for S19K Pro. 2024-03-19 14:16:57 -06:00
Upstream Data
872cac811a version: bump version number. 2024-03-19 12:41:57 -06:00
Upstream Data
d324c2fee9 feature: add stock S21 support. 2024-03-19 12:41:37 -06:00
Upstream Data
4b54cf67ba version: bump version number. 2024-03-12 16:16:40 -06:00
Upstream Data
0e00fe3114 feature: add antminer mode as str setting. 2024-03-12 16:16:15 -06:00
wilfredallyn
15d1dc5bb6 feature: add install docs (#117) 2024-03-10 09:09:06 -06:00
Brett Rowan
2af0003843 version: bump version number. 2024-03-06 21:56:10 -07:00
Brett Rowan
3c227be170 bug: update httpx to use compatible versioning. 2024-03-06 21:53:14 -07:00
Brett Rowan
e889780bad version: bump version number. 2024-03-03 11:16:16 -07:00
Brett Rowan
cc3d4fa805 feature: add S19 Hydro and S19 Pro+ Hydro. 2024-03-03 11:15:44 -07:00
Brett Rowan
227e1e2d2d version: bump version number. 2024-02-25 13:10:11 -07:00
Brett Rowan
d6c8ff0910 feature: add support for more S21 LUXOS. 2024-02-25 13:08:25 -07:00
Brett Rowan
bd20e051b0 feature: add support for more LuxOS models. 2024-02-25 13:02:52 -07:00
UpstreamData
2eb6697e9a version: bump version number 2024-02-21 13:23:38 -07:00
UpstreamData
c5817fcc36 docs: Update docs. 2024-02-21 13:22:40 -07:00
Brett Rowan
f2391bcb2d Merge pull request #110 from jpcomps/add_blockminer_support
ePIC: Add Blockminer support
2024-02-21 13:21:45 -07:00
Brett Rowan
bc3bd9e5da Fix issue with possible type hint incompatability. 2024-02-21 13:20:41 -07:00
UpstreamData
3f0959d75e docs: Update docs. 2024-02-21 12:43:46 -07:00
UpstreamData
31f7b56724 docs: Update docs. 2024-02-21 12:39:40 -07:00
UpstreamData
072954d755 docs: Update docs. 2024-02-21 12:39:08 -07:00
UpstreamData
d271e0f9c8 version: bump version number. 2024-02-21 12:33:21 -07:00
UpstreamData
8f1408ce17 bug: fix sending privileged commands on BTMiner using timeout as the port, and capture positional arguments in _send_bytes to prevent this. 2024-02-21 12:32:56 -07:00
John-Paul Compagnone
825d1f4cfb fix checks 2024-02-20 20:39:22 -05:00
John-Paul Compagnone
c6bcd7e05a fix capitalization 2024-02-20 20:33:30 -05:00
John-Paul Compagnone
5d80051f3b more missing i 2024-02-20 18:15:40 -05:00
John-Paul Compagnone
b71c448199 add missing i 2024-02-20 18:12:19 -05:00
JP Compagnone
c82148412c Merge branch 'UpstreamData:master' into add_blockminer_support 2024-02-20 18:01:16 -05:00
UpstreamData
a582ee63a0 bug: use force apply to fix DPS bug with setting wattage. 2024-02-20 10:11:57 -07:00
UpstreamData
db7c19c486 feature: add some miner support. 2024-02-20 09:47:28 -07:00
JP Compagnone
599f71da19 Merge branch 'UpstreamData:master' into add_blockminer_support 2024-02-19 19:04:32 -05:00
UpstreamData
0995744d90 version: bump version number. 2024-02-14 13:48:07 -07:00
UpstreamData
4073a27aba bug: update miner handling with unknown models, but known makes. 2024-02-14 13:47:34 -07:00
UpstreamData
bec9c31c97 docs: Update supported miners location. 2024-02-12 10:38:22 -07:00
UpstreamData
acdd615c53 docs: update docs location. 2024-02-12 10:37:33 -07:00
UpstreamData
8091617ee2 feature: add supports_power_modes flag. 2024-02-12 09:26:09 -07:00
John-Paul Compagnone
c25ff6fcef add ePIC Blockminer 520i support 2024-02-11 10:55:49 -05:00
John-Paul Compagnone
ab0dcd607b make ePIC api calls more reliable 2024-02-10 21:59:08 -05:00
Brett Rowan
ce288e472f version: bump version number. 2024-02-10 17:51:12 -07:00
Brett Rowan
02d8f25daf Merge pull request #108 from jpcomps/master
add ePIC UMC S21 support, fix HB generation by using capabilities
2024-02-10 17:50:37 -07:00
John-Paul Compagnone
a76d1c6149 add ePIC UMC S21 support, fix HB generation by using capabilities 2024-02-10 19:36:07 -05:00
Brett Rowan
17f5eade19 version: bump version number. 2024-02-10 16:45:49 -07:00
Brett Rowan
b6a2a5054b bug: fix goldshell sleep mode again. 2024-02-10 16:45:29 -07:00
Brett Rowan
5984338c64 version: bump version number. 2024-02-10 15:47:25 -07:00
Brett Rowan
07d1c48e33 bug: fix goldshell config/power modes. 2024-02-10 15:46:55 -07:00
Brett Rowan
d2abae947c version: bump version number. 2024-02-10 15:39:34 -07:00
Brett Rowan
e4a0f2451a Attempt to fix goldshell mode issues. 2024-02-10 15:39:00 -07:00
b-rowan
880c598b1a version: bump version number. 2024-02-10 14:26:09 -07:00
b-rowan
3632c2c4d8 feature: add support for goldshell shutdown. 2024-02-10 14:25:42 -07:00
b-rowan
09bc9686ae feature: add support for goldshell mode settings. 2024-02-10 14:23:17 -07:00
b-rowan
34584ab098 feature: add support for KDBoxPro and KDBoxII. 2024-02-10 13:56:00 -07:00
UpstreamData
554d99ca08 bug: update API unlocker format. 2024-02-09 14:25:14 -07:00
UpstreamData
5c5d688ffa Update api opener. 2024-02-09 13:39:48 -07:00
b-rowan
c50d55e87c version: bump version number. 2024-02-07 20:16:26 -07:00
b-rowan
5e5516bfb3 bug: fix serial numbers for antminer. 2024-02-07 20:15:38 -07:00
UpstreamData
4b068c57c5 version: bump version number. 2024-02-07 11:17:29 -07:00
UpstreamData
203f199aec feature: add wmt.pyasic.org. 2024-02-07 11:09:27 -07:00
b-rowan
895f17aaf9 version: bump version number. 2024-02-03 00:36:44 -07:00
b-rowan
8a64ff3559 bug: swap to asyncio.read() in base RPC to try to handle possible missed messages. 2024-02-03 00:36:03 -07:00
UpstreamData
4c45d356c4 version: bump version number. 2024-02-02 10:07:08 -07:00
UpstreamData
4dec329f11 bug: Try to return something when checking vnish fw version. 2024-02-02 10:06:33 -07:00
UpstreamData
b563ed118e bug: fix vnish firmware version bug. 2024-02-02 10:05:34 -07:00
UpstreamData
75b2ec40b1 bug: fix ePIC config parsing to use hashrate tuning instead of power tuning. 2024-01-31 09:21:32 -07:00
b-rowan
d9adaf6667 version: bump version number. 2024-01-30 21:41:49 -07:00
b-rowan
9343308f41 feature: Add support for new whatsminers, and try to handle whatsminer errors when receiving data. 2024-01-30 21:41:10 -07:00
UpstreamData
88769e40ae version: bump version number. 2024-01-30 13:34:24 -07:00
UpstreamData
be45eb7400 bug: fix issues with bosminer multicommand, and update X17 to use BOSMiner instead of BOSer. 2024-01-30 13:34:00 -07:00
b-rowan
2f719a03a4 version: bump version number. 2024-01-29 20:57:01 -07:00
b-rowan
64196f9754 bug: update whatsminer set_target_freq to match docs. 2024-01-29 20:56:36 -07:00
UpstreamData
49a77f1b79 version: bump version number. 2024-01-29 12:47:54 -07:00
UpstreamData
3838c4f2f9 bug: fix missing validation import for BTMiner. 2024-01-29 12:47:30 -07:00
UpstreamData
80d89c95b5 version: bump version number. 2024-01-29 12:33:07 -07:00
UpstreamData
30cd8b5cfe bug: fix some issues with rpc renaming. 2024-01-29 12:32:54 -07:00
b-rowan
c443170f78 refactor: improve epic web send_command implementation. 2024-01-27 09:42:35 -07:00
b-rowan
a2c2aa2377 version: bump version number. 2024-01-27 09:26:13 -07:00
b-rowan
4f0eb49a02 bug: fix some issues with epic send config. 2024-01-27 09:25:20 -07:00
b-rowan
a821357b4f Merge pull request #102 from jpcomps/master
fix send_config for ePIC
2024-01-27 09:05:23 -07:00
John-Paul Compagnone
3c7679a22d fix send_config for ePIC 2024-01-27 10:50:37 -05:00
UpstreamData
a52737e236 refactor: add some type hints for epic config. 2024-01-26 13:58:08 -07:00
UpstreamData
7c96bbe153 version: bump version number. 2024-01-26 13:56:15 -07:00
UpstreamData
e8bbf22aa7 bug: fix a bug with epic mining mode configs. 2024-01-26 13:55:54 -07:00
UpstreamData
5ac8b27cb6 version: bump version number. 2024-01-26 12:49:45 -07:00
UpstreamData
6c14902484 Add ePIC send_config and config.as_epic (#101)
* feature: Add epic send_config.

* feature: remove UID from epic config.

* feature: add default for temp configs in epic.
2024-01-26 12:47:19 -07:00
UpstreamData
96aa346f00 refactor: rename miner.api to miner.rpc. Add miner.api property linked to miner.rpc. 2024-01-26 10:15:20 -07:00
UpstreamData
c2b6cc7468 refactor: improve validate_command_output, and move it out of the miner rpc api. 2024-01-26 09:51:09 -07:00
UpstreamData
ac7f41be44 refactor: move bind addr to init in MinerListener. 2024-01-25 16:34:46 -07:00
UpstreamData
718b87fd12 refactor: rename overwritten method. 2024-01-25 16:32:33 -07:00
UpstreamData
5ad23c6cd0 refactor: remove unused imports. 2024-01-25 16:31:19 -07:00
UpstreamData
66be443dc3 refactor: re-arrange some imports. 2024-01-25 16:25:25 -07:00
UpstreamData
a9135e21d4 docs: update docs. 2024-01-25 14:35:31 -07:00
UpstreamData
dd4c087749 refactor: move base classes to base.py in their directories, move data locations to miners.data, and rename types to models. 2024-01-25 14:26:53 -07:00
UpstreamData
aa1d7c1b6f refactor: make web handlers much more consistent across types, remove graphql, and make luci and grpc the dedicated web apis for BOSer and BOSMiner respectively. 2024-01-25 13:50:04 -07:00
UpstreamData
b328a27f04 refactor: Update config to use future annotations and move merge_dicts to misc. 2024-01-25 11:32:03 -07:00
UpstreamData
c5eed797ec refactor: update type annotations in config. 2024-01-25 10:07:19 -07:00
b-rowan
4fd2199435 version: bump version number. 2024-01-24 18:39:50 -07:00
b-rowan
3226d47846 Merge branch 'dev_fluxos' 2024-01-24 18:39:12 -07:00
b-rowan
6c1931fe7e bug: fix some naming issues with auradine, and add chip count for AT1500. 2024-01-24 18:37:29 -07:00
b-rowan
1dd87ac102 feature: add expected chips for M50S++VK10 2024-01-24 18:32:50 -07:00
b-rowan
95d1e40b4f bug: fix auradine fan config parsing. 2024-01-24 18:28:10 -07:00
b-rowan
31682b7fae bug: fix auradine fan data and config parsing. 2024-01-24 18:22:28 -07:00
b-rowan
e6523fc7d5 bug: fix auradine wattage data. 2024-01-24 18:18:11 -07:00
b-rowan
91de12467b bug: add multicommand flag to auradine multicommand output. 2024-01-24 18:08:22 -07:00
b-rowan
d81e3e9f88 bug: fix auradine multicommand format for get_data. 2024-01-24 18:05:32 -07:00
b-rowan
49fc0f3c54 bug: fix auradine hashboards. 2024-01-24 17:55:47 -07:00
b-rowan
4b36044e56 bug: fix auradine web api token format. 2024-01-24 17:45:42 -07:00
b-rowan
90fb67f586 bug: fix auradine web api token. 2024-01-24 17:38:49 -07:00
b-rowan
edf31ae7df bug: fix auradine identification. 2024-01-24 17:33:41 -07:00
b-rowan
af354fd8e2 feature: add auradine to web selection options. 2024-01-24 17:17:03 -07:00
UpstreamData
6a2a3e836d bug: fix auradine selection. 2024-01-24 16:23:25 -07:00
b-rowan
41709e4706 feature: add auradine data functions. 2024-01-23 16:15:34 -07:00
b-rowan
b60c7a55d4 feature: add auradine control functions. 2024-01-23 15:28:37 -07:00
b-rowan
eed1973345 feature: add auradine models. 2024-01-23 14:23:57 -07:00
b-rowan
64774d2017 feature: add basic auradine miner framework. 2024-01-23 14:06:54 -07:00
b-rowan
e9751d6cd1 version: bump version number. 2024-01-22 19:54:52 -07:00
b-rowan
e2b0a76e67 bug: fix unneeded error handling when getting hostname fails. 2024-01-22 19:40:07 -07:00
b-rowan
1c5c39fa97 version: bump version number. 2024-01-22 18:43:34 -07:00
b-rowan
27c48764a8 refactor: remove miner factory cache. 2024-01-22 18:41:19 -07:00
UpstreamData
5e01f7517b version: bump version number. 2024-01-22 13:39:52 -07:00
b-rowan
569f659fac Merge pull request #96 from fdeh75/fix-vnish-wattage-dimension
Fix vnish wattage dimension
2024-01-22 13:38:27 -07:00
fdeh
dd9c6f1f63 Fix vnish wattage dimension
Update backend vnish.py
2024-01-22 23:17:27 +03:00
b-rowan
0958f47cfe version: bump version number. 2024-01-21 14:39:35 -07:00
b-rowan
3820b40f44 bug: Fix DataLocations defaulting to all get_config. 2024-01-21 14:39:01 -07:00
b-rowan
cce1917c00 version: bump version number. 2024-01-21 12:28:44 -07:00
b-rowan
2ee19f47e7 bug: fix failing configuration on BOSminer. 2024-01-21 12:28:11 -07:00
b-rowan
ff526a3273 version: bump version number. 2024-01-21 10:39:48 -07:00
b-rowan
7811245ec9 Merge pull request #95 from UpstreamData/dev_quality
Improve overall code quality, move ssh to `miner.ssh`, remove `pwd` for miners.
2024-01-21 10:39:01 -07:00
b-rowan
cbab76847a refactor: remove BBB check for BOSMiner. 2024-01-21 10:15:44 -07:00
upstreamdata
ce981d1787 refactor: reformat. 2024-01-18 15:47:52 -07:00
upstreamdata
4b5314a8f6 refactor: move ssh to miner.ssh 2024-01-18 15:32:09 -07:00
UpstreamData
3be3086a38 docs: fix issues with docs. 2024-01-16 15:55:01 -07:00
UpstreamData
a0c76fe24f refactor: remove unused imports. 2024-01-16 15:36:55 -07:00
UpstreamData
acdcfd04cd refactor: remove unneeded lambda and remove pass. 2024-01-16 15:34:06 -07:00
UpstreamData
91a5998b4e refactor: remove unneeded lambda. 2024-01-16 15:31:31 -07:00
UpstreamData
7292af450c refactor: improve RPC handlers. 2024-01-16 15:26:32 -07:00
UpstreamData
307926afbb refactor: use protocol for BaseMiner and update attributes to be part of the class rather than a __init__ method. 2024-01-16 14:47:43 -07:00
UpstreamData
10293ae24a refactor: add default values for data locations to reduce duplication. 2024-01-16 09:31:23 -07:00
UpstreamData
f820372532 refactor: remove some duplicated code in rpc APIs. 2024-01-16 08:57:46 -07:00
UpstreamData
22965ffefa refactor: fix not x is None 2024-01-16 08:40:47 -07:00
UpstreamData
34ca5ba68f refactor: shorten some lines. 2024-01-16 08:39:15 -07:00
UpstreamData
468134e754 refactor: fix some not x in y and not x not in y 2024-01-16 08:36:31 -07:00
UpstreamData
5327b3fe3d refactor: remove unused variables. 2024-01-16 08:16:21 -07:00
UpstreamData
68b85aa7da refactor: remove some useless logging statements, and remove some unused imports. 2024-01-16 08:15:24 -07:00
UpstreamData
b78652b279 refactor: remove some unused variables. 2024-01-15 16:23:54 -07:00
UpstreamData
832a276f4b refactor: remove some unused pass statements. 2024-01-15 16:16:08 -07:00
UpstreamData
2b82b29690 refactor: remove some duplicate classes, and rename UnknownMiner get methods. 2024-01-15 16:03:40 -07:00
UpstreamData
56dd1c80b5 refactor: remove and fix some hardcoded passwords. 2024-01-15 15:53:10 -07:00
UpstreamData
d686cdacc8 refactor: change some if statements to if is not None. 2024-01-15 15:43:31 -07:00
UpstreamData
aab8825997 refactor: rename API to rpc, and classes from {X}API to {X}RPCAPI to clarify naming. 2024-01-15 15:09:51 -07:00
UpstreamData
4ed49c2321 version: bump version number. 2024-01-15 14:59:29 -07:00
UpstreamData
c069468803 bug: fix some bugs with epic, update miner repr, and remove get_model from braiinsOS. 2024-01-15 14:58:54 -07:00
UpstreamData
707cf8b848 version: bump version number. 2024-01-15 14:29:04 -07:00
UpstreamData
170843aae7 bug: add handler for failed get_data calls to make errors more verbose. 2024-01-15 14:28:39 -07:00
UpstreamData
f5acf9ec62 Merge branch 'dev_boser'
# Conflicts:
#	pyasic/miners/antminer/hiveon/X9/T9.py
#	pyasic/miners/backends/bosminer_old.py
#	pyasic/miners/backends/braiins_os.py
#	pyasic/miners/backends/btminer.py
#	pyasic/miners/backends/cgminer_avalon.py
#	pyasic/miners/backends/epic.py
#	pyasic/miners/backends/hiveon.py
#	pyasic/miners/backends/innosilicon.py
#	pyasic/miners/base.py
#	tests/miners_tests/__init__.py
2024-01-15 14:25:02 -07:00
UpstreamData
edaf89c73a refactor: fix some formatting issues and bugs. 2024-01-15 14:18:41 -07:00
UpstreamData
ce34dfdde8 bug: fix fault_light check for boser. 2024-01-15 14:00:51 -07:00
UpstreamData
e45e51ce65 refactor: fix merge. 2024-01-15 13:09:23 -07:00
UpstreamData
f1501718a3 feature: finish get_data functions for bosminer 2024-01-15 10:48:03 -07:00
UpstreamData
831d6ee955 feature: add boser fault light functions. 2024-01-15 10:48:02 -07:00
UpstreamData
7be6596fdd refactor: swap except (KeyError, ValueError) to except LookupError. 2024-01-15 10:48:02 -07:00
b-rowan
928e0dd028 feature: start refactoring BOSer and BOSMiner into separate classes. 2024-01-15 10:48:00 -07:00
UpstreamData
672e753afb bug: add test to cross check function arguments, and fix some method implementations and naming. 2024-01-15 10:47:56 -07:00
UpstreamData
269e6aac14 bug: add more tests and finish renaming methods. 2024-01-15 10:47:40 -07:00
UpstreamData
1a4f3f7dc7 bug: make sure all data locations are accurate. 2024-01-15 10:47:40 -07:00
UpstreamData
b0337e8417 refactor: swap (KeyError, IndexError) for LookupError. 2024-01-15 10:47:40 -07:00
UpstreamData
60f3687d02 refactor: optimize imports. 2024-01-15 10:47:39 -07:00
UpstreamData
a8c45cb95d refactor: remove parameters from get_{x} functions and move them to _get_{x}(**params). Add miner.fw_str, and miner.raw_model. Remove model from get_data exclude. Swap fan_count to expected_fans. 2024-01-15 10:47:39 -07:00
UpstreamData
aa9ba66f8e bug: add test to cross check function arguments, and fix some method implementations and naming. 2024-01-15 10:47:39 -07:00
UpstreamData
06cc84f16d refactor: remove parameters from get_{x} functions and move them to _get_{x}(**params). Add miner.fw_str, and miner.raw_model. Remove model from get_data exclude. Swap fan_count to expected_fans. 2024-01-15 10:47:38 -07:00
fdeh
067d5c98f5 Fix VNish get_hashrate and get_fans errors
Update vnish.py. Fix data locations according to the method arguments
2024-01-15 10:47:38 -07:00
UpstreamData
b4b84c773f refactor: remove bad function. 2024-01-15 10:47:38 -07:00
UpstreamData
cd1768aae9 refactor: swap (KeyError, IndexError) for LookupError. 2024-01-15 10:47:37 -07:00
UpstreamData
2ef85d3868 refactor: optimize imports. 2024-01-15 10:47:36 -07:00
UpstreamData
6f64cc5e0d refactor: remove parameters from get_{x} functions and move them to _get_{x}(**params). Add miner.fw_str, and miner.raw_model. Remove model from get_data exclude. Swap fan_count to expected_fans. 2024-01-15 10:47:33 -07:00
b-rowan
d44907435c Merge pull request #91 from UpstreamData/dev_get_params
Move parameters to private methods for `get_{x}` methods
2024-01-15 10:43:08 -07:00
b-rowan
04ca75d00e Merge branch 'master' into dev_get_params 2024-01-15 10:42:37 -07:00
UpstreamData
b56e94ce8c bug: add more tests and finish renaming methods. 2024-01-15 10:35:15 -07:00
UpstreamData
e7d30aad84 bug: make sure all data locations are accurate. 2024-01-15 10:29:39 -07:00
UpstreamData
194fb539a1 refactor: swap (KeyError, IndexError) for LookupError. 2024-01-15 10:23:58 -07:00
UpstreamData
416ea2964b refactor: optimize imports. 2024-01-15 10:23:57 -07:00
UpstreamData
3234f7e06f refactor: remove parameters from get_{x} functions and move them to _get_{x}(**params). Add miner.fw_str, and miner.raw_model. Remove model from get_data exclude. Swap fan_count to expected_fans. 2024-01-15 10:23:57 -07:00
UpstreamData
8fb357544b bug: add test to cross check function arguments, and fix some method implementations and naming. 2024-01-15 10:23:55 -07:00
UpstreamData
34006941ad bug: add test to cross check function arguments, and fix some method implementations and naming. 2024-01-15 10:16:47 -07:00
UpstreamData
3c3c34c54b Merge branch 'master' into dev_get_params 2024-01-15 08:10:46 -07:00
b-rowan
5a61a87766 docs: update docs. 2024-01-14 12:59:13 -07:00
b-rowan
ef9a026ee8 docs: update docs. 2024-01-14 12:58:11 -07:00
b-rowan
71c85e0603 bug: fix a possible failed authentication when using gRPC. 2024-01-14 12:09:29 -07:00
UpstreamData
c5224b808e refactor: remove parameters from get_{x} functions and move them to _get_{x}(**params). Add miner.fw_str, and miner.raw_model. Remove model from get_data exclude. Swap fan_count to expected_fans. 2024-01-14 10:02:50 -07:00
b-rowan
e4c6d751a1 version: bump version number. 2024-01-14 10:02:38 -07:00
fdeh
ff4dfa124b Fix VNish get_hashrate and get_fans errors
Update vnish.py. Fix data locations according to the method arguments
2024-01-14 10:02:38 -07:00
b-rowan
d0eb5119aa version: bump version number. 2024-01-14 10:00:15 -07:00
fdeh
cfa51623c4 Fix VNish get_hashrate and get_fans errors
Update vnish.py. Fix data locations according to the method arguments
2024-01-14 10:00:15 -07:00
b-rowan
96bb56ebd1 version: bump version number. 2024-01-14 09:59:06 -07:00
b-rowan
cdd7beccbe Merge pull request #92 from fdeh75/fix-vnish-data-gathering
Fix VNish get_hashrate and get_fans errors
2024-01-14 09:58:16 -07:00
fdeh
1a544851df Fix VNish get_hashrate and get_fans errors
Update vnish.py. Fix data locations according to the method arguments
2024-01-14 19:53:47 +03:00
UpstreamData
aa2dc5a53d feature: update some gRPC functions, and add as_boser for some of the MinerConfig values. 2024-01-12 15:06:44 -07:00
UpstreamData
361d6e07cc feature: finish get_data functions for bosminer 2024-01-12 13:29:46 -07:00
UpstreamData
53a018f526 feature: add boser fault light functions. 2024-01-12 11:58:26 -07:00
UpstreamData
6c9a378eee feature: add boser config parsing. 2024-01-12 11:54:17 -07:00
UpstreamData
be67ef3471 refactor: remove bad function. 2024-01-11 15:29:29 -07:00
UpstreamData
a094d28a36 refactor: swap (KeyError, IndexError) for LookupError. 2024-01-11 15:20:33 -07:00
UpstreamData
4156f93c0d refactor: optimize imports. 2024-01-11 15:00:48 -07:00
UpstreamData
ed6eb11653 bug: fix being unable to get fw version as part of multicommand. 2024-01-11 13:57:48 -07:00
snyk-bot
39299f2cfa fix: docs/requirements.txt to reduce vulnerabilities
The following vulnerabilities are fixed by pinning transitive dependencies:
- https://snyk.io/vuln/SNYK-PYTHON-JINJA2-6150717
2024-01-11 11:37:01 -07:00
snyk-bot
c80ca1415a fix: docs/requirements.txt to reduce vulnerabilities
The following vulnerabilities are fixed by pinning transitive dependencies:
- https://snyk.io/vuln/SNYK-PYTHON-JINJA2-6150717
2024-01-11 11:36:05 -07:00
UpstreamData
a8428a2739 refactor: remove parameters from get_{x} functions and move them to _get_{x}(**params). Add miner.fw_str, and miner.raw_model. Remove model from get_data exclude. Swap fan_count to expected_fans. 2024-01-11 11:33:44 -07:00
UpstreamData
895fb1b43e refactor: swap except (KeyError, ValueError) to except LookupError. 2024-01-11 10:20:18 -07:00
UpstreamData
014896ae1b bug: fix data passed by get_version to BOSminer. 2024-01-11 09:53:06 -07:00
snyk-bot
84ac991685 fix: docs/requirements.txt to reduce vulnerabilities
The following vulnerabilities are fixed by pinning transitive dependencies:
- https://snyk.io/vuln/SNYK-PYTHON-JINJA2-6150717
2024-01-11 16:00:03 +00:00
b-rowan
bb481553fa bug: fix missing message in grpc command. 2024-01-10 22:46:58 -07:00
b-rowan
7ab3d8b54e feature: improve data gathering slightly on BOSMiner. 2024-01-10 22:26:28 -07:00
b-rowan
36494f2aca bug: remove boser check in miner_factory, and fix bad syntax on comparison. 2024-01-10 22:15:31 -07:00
b-rowan
bea44a72ea feature: start refactoring BOSer and BOSMiner into separate classes. 2024-01-10 22:12:27 -07:00
b-rowan
9da7b44177 feature: add vnish config parsing. 2024-01-06 11:31:12 -07:00
UpstreamData
e7f05f7a28 version: bump version number. 2024-01-05 16:22:03 -07:00
UpstreamData
2d229be9fd feature: add board serial numbers to whatsminers. 2024-01-05 16:18:03 -07:00
UpstreamData
de5038e57a feature: add AntminerModern serial numbers to Hashboard data. 2024-01-05 15:57:26 -07:00
UpstreamData
8ad1b3f72a refactor: fix formatting issue. 2024-01-05 08:49:44 -07:00
b-rowan
070fb26dbc version: bump version number. 2024-01-04 20:58:44 -07:00
b-rowan
80d9d7df1d bug: fix possible empty command when getting small data points. 2024-01-04 20:58:15 -07:00
UpstreamData
928c24f56f version: bump version number. 2024-01-04 13:07:13 -07:00
UpstreamData
6e7442f90d Update data locations to be typed with dataclasses and enums. (#82)
* feature: swap AntminerModern to new data location style.

* bug: fix a bunch of missed instances of `nominal_` naming.

* feature: add support for S19 Pro Hydro.

* version: bump version number.

* dependencies: bump httpx version

* version: bump version number.

* feature: implement data locations for all remaining miners.

* refactor: remove some unused docstrings.

* feature: swap AntminerModern to new data location style.

* feature: implement data locations for all remaining miners.

* refactor: remove some unused docstrings.

* bug: fix misnamed data locations, and update base miner get_data to use new data locations.

* bug: fix include/exclude implementation on get_data.

* bug: swap ePIC to BaseMiner subclass.

* feature: add DataOptions to __all__

* tests: update data tests with new data locations method.

* bug: remove bad command from bosminer commands.

* dependencies: update dependencies.

* bug: fix some typing issues with python 3.8, and remove useless semaphore and scan threads.

* bug: fix KeyError when pools rpc command returns broken data.
2024-01-04 13:03:45 -07:00
b-rowan
936474ed3b Merge pull request #84 from jpcomps/master 2023-12-23 13:07:47 -07:00
John-Paul Compagnone
2e28060e05 fixes, changes, and formatting 2023-12-23 15:01:42 -05:00
John-Paul Compagnone
07f92557c6 cover chiptune case 2023-12-22 23:35:13 -05:00
John-Paul Compagnone
6f6f5743cf add get_config to ePIC backend 2023-12-22 23:35:13 -05:00
Upstream Data
b89ea1fa92 version: bump version number. 2023-12-22 16:29:03 -07:00
Upstream Data
3588197741 dependencies: bump httpx version 2023-12-22 16:28:46 -07:00
Upstream Data
8adc3d2adf version: bump version number. 2023-12-22 15:47:25 -07:00
Upstream Data
040c0b6842 feature: add support for S19 Pro Hydro. 2023-12-22 15:40:23 -07:00
Upstream Data
550b4a97a1 bug: fix a bunch of missed instances of nominal_ naming. 2023-12-22 15:32:01 -07:00
408 changed files with 10234 additions and 10722 deletions

View File

@@ -1,16 +1,16 @@
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0 rev: v4.5.0
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
- id: check-yaml - id: check-yaml
- id: check-added-large-files - id: check-added-large-files
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 22.6.0 rev: 24.3.0
hooks: hooks:
- id: black - id: black
- repo: https://github.com/pycqa/isort - repo: https://github.com/pycqa/isort
rev: 5.10.1 rev: 5.13.2
hooks: hooks:
- id: isort - id: isort
name: isort (python) name: isort (python)

View File

@@ -9,7 +9,7 @@
[![Commit Activity - master](https://img.shields.io/github/commit-activity/y/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/commits/master/) [![Commit Activity - master](https://img.shields.io/github/commit-activity/y/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/commits/master/)
[![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)
[![Read The Docs - Docs](https://img.shields.io/readthedocs/pyasic)](https://pyasic.readthedocs.io/en/latest/) [![Read The Docs - Docs](https://img.shields.io/readthedocs/pyasic)](https://docs.pyasic.org)
[![License - Apache 2.0](https://img.shields.io/github/license/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt) [![License - Apache 2.0](https://img.shields.io/github/license/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)
--- ---
@@ -17,7 +17,24 @@
Welcome to `pyasic`! `pyasic` uses an asynchronous method of communicating with ASIC miners on your network, which makes it super fast. Welcome to `pyasic`! `pyasic` uses an asynchronous method of communicating with ASIC miners on your network, which makes it super fast.
[Click here to view supported miner types](miners/supported_types.md) [Click here to view supported miner types](https://docs.pyasic.org/en/latest/miners/supported_types/)
---
## Installation
It is recommended to install `pyasic` in a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/#what-other-popular-options-exist-aside-from-venv) to isolate it from the rest of your system. Options include:
- [venv](https://docs.python.org/3/library/venv.html): included in Python standard library but has fewer features than other options
- [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv): [pyenv](https://github.com/pyenv/pyenv) plugin for managing virtualenvs
```
pyenv install <python version number>
pyenv virtualenv <python version number> <env name>
pyenv activate <env name>
```
- [conda](https://docs.conda.io/en/latest/)
##### Installing `pyasic`
`python -m pip install .` or `poetry install`
--- ---
## Getting started ## Getting started

View File

@@ -1,27 +0,0 @@
# pyasic
## Miner APIs
Each miner has a unique API that is used to communicate with it.
Each of these API types has commands that differ between them, and some commands have data that others do not.
Each miner that is a subclass of [`BaseMiner`][pyasic.miners.BaseMiner] should have an API linked to it as `Miner.api`.
All API implementations inherit from [`BaseMinerAPI`][pyasic.API.BaseMinerAPI], which implements the basic communications protocols.
[`BaseMinerAPI`][pyasic.API.BaseMinerAPI] should never be used unless inheriting to create a new miner API class for a new type of miner (which should be exceedingly rare).
[`BaseMinerAPI`][pyasic.API.BaseMinerAPI] cannot be instantiated directly, it will raise a `TypeError`.
Use these instead -
#### [BFGMiner API][pyasic.API.bfgminer.BFGMinerAPI]
#### [BMMiner API][pyasic.API.bmminer.BMMinerAPI]
#### [BOSMiner API][pyasic.API.bosminer.BOSMinerAPI]
#### [BTMiner API][pyasic.API.btminer.BTMinerAPI]
#### [CGMiner API][pyasic.API.cgminer.CGMinerAPI]
#### [LUXMiner API][pyasic.API.luxminer.LUXMinerAPI]
#### [Unknown API][pyasic.API.unknown.UnknownAPI]
<br>
## BaseMinerAPI
::: pyasic.API.BaseMinerAPI
handler: python
options:
heading_level: 4

View File

@@ -1,6 +1,6 @@
# pyasic # pyasic
## Miner Data
## Miner Data
::: pyasic.data.MinerData ::: pyasic.data.MinerData
handler: python handler: python
options: options:
@@ -13,3 +13,10 @@
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## Fan Data
::: pyasic.data.Fan
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -3,7 +3,7 @@ import importlib
import os import os
import warnings import warnings
from pyasic.miners.miner_factory import MINER_CLASSES, MinerTypes from pyasic.miners.factory import MINER_CLASSES, MinerTypes
warnings.filterwarnings("ignore") warnings.filterwarnings("ignore")
@@ -27,6 +27,8 @@ def backend_str(backend: MinerTypes) -> str:
match backend: match backend:
case MinerTypes.ANTMINER: case MinerTypes.ANTMINER:
return "Stock Firmware Antminers" return "Stock Firmware Antminers"
case MinerTypes.AURADINE:
return "Stock Firmware Auradine Miners"
case MinerTypes.AVALONMINER: case MinerTypes.AVALONMINER:
return "Stock Firmware Avalonminers" return "Stock Firmware Avalonminers"
case MinerTypes.VNISH: case MinerTypes.VNISH:
@@ -45,6 +47,8 @@ def backend_str(backend: MinerTypes) -> str:
return "Stock Firmware Goldshells" return "Stock Firmware Goldshells"
case MinerTypes.LUX_OS: case MinerTypes.LUX_OS:
return "LuxOS Firmware Miners" return "LuxOS Firmware Miners"
case MinerTypes.EPIC:
return "ePIC Firmware Miners"
def create_url_str(mtype: str): def create_url_str(mtype: str):

View File

@@ -18,6 +18,23 @@ Welcome to `pyasic`! `pyasic` uses an asynchronous method of communicating with
[Click here to view supported miner types](miners/supported_types.md) [Click here to view supported miner types](miners/supported_types.md)
---
## Installation
It is recommended to install `pyasic` in a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/#what-other-popular-options-exist-aside-from-venv) to isolate it from the rest of your system. Options include:
- [venv](https://docs.python.org/3/library/venv.html): included in Python standard library but has fewer features than other options
- [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv): [pyenv](https://github.com/pyenv/pyenv) plugin for managing virtualenvs
```
pyenv install <python version number>
pyenv virtualenv <python version number> <env name>
pyenv activate <env name>
```
- [conda](https://docs.conda.io/en/latest/)
##### Installing `pyasic`
`python -m pip install .` or `poetry install`
--- ---
## Getting started ## Getting started
--- ---
@@ -47,7 +64,7 @@ if __name__ == "__main__":
--- ---
##### 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.get_miner]. If you already know the IP address of your miner or miners, you can use the [`MinerFactory`][pyasic.miners.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.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
@@ -122,24 +139,24 @@ if __name__ == "__main__":
## Miner control ## Miner control
--- ---
`pyasic` exposes a standard interface for each miner using control functions. `pyasic` exposes a standard interface for each miner using control functions.
Every miner class in `pyasic` must implement all the control functions defined in [`BaseMiner`][pyasic.miners.BaseMiner]. Every miner class in `pyasic` must implement all the control functions defined in [`MinerProtocol`][pyasic.miners.base.MinerProtocol].
These functions are These functions are
[`check_light`][pyasic.miners.BaseMiner.check_light], [`check_light`][pyasic.miners.base.MinerProtocol.check_light],
[`fault_light_off`][pyasic.miners.BaseMiner.fault_light_off], [`fault_light_off`][pyasic.miners.base.MinerProtocol.fault_light_off],
[`fault_light_on`][pyasic.miners.BaseMiner.fault_light_on], [`fault_light_on`][pyasic.miners.base.MinerProtocol.fault_light_on],
[`get_config`][pyasic.miners.BaseMiner.get_config], [`get_config`][pyasic.miners.base.MinerProtocol.get_config],
[`get_data`][pyasic.miners.BaseMiner.get_data], [`get_data`][pyasic.miners.base.MinerProtocol.get_data],
[`get_errors`][pyasic.miners.BaseMiner.get_errors], [`get_errors`][pyasic.miners.base.MinerProtocol.get_errors],
[`get_hostname`][pyasic.miners.BaseMiner.get_hostname], [`get_hostname`][pyasic.miners.base.MinerProtocol.get_hostname],
[`get_model`][pyasic.miners.BaseMiner.get_model], [`get_model`][pyasic.miners.base.MinerProtocol.get_model],
[`reboot`][pyasic.miners.BaseMiner.reboot], [`reboot`][pyasic.miners.base.MinerProtocol.reboot],
[`restart_backend`][pyasic.miners.BaseMiner.restart_backend], [`restart_backend`][pyasic.miners.base.MinerProtocol.restart_backend],
[`stop_mining`][pyasic.miners.BaseMiner.stop_mining], [`stop_mining`][pyasic.miners.base.MinerProtocol.stop_mining],
[`resume_mining`][pyasic.miners.BaseMiner.resume_mining], [`resume_mining`][pyasic.miners.base.MinerProtocol.resume_mining],
[`is_mining`][pyasic.miners.BaseMiner.is_mining], [`is_mining`][pyasic.miners.base.MinerProtocol.is_mining],
[`send_config`][pyasic.miners.BaseMiner.send_config], and [`send_config`][pyasic.miners.base.MinerProtocol.send_config], and
[`set_power_limit`][pyasic.miners.BaseMiner.set_power_limit]. [`set_power_limit`][pyasic.miners.base.MinerProtocol.set_power_limit].
##### Usage ##### Usage
```python ```python
@@ -236,6 +253,7 @@ settings.update("default_antminer_password", "my_pwd")
"factory_get_timeout": 3, "factory_get_timeout": 3,
"get_data_retries": 1, "get_data_retries": 1,
"api_function_timeout": 5, "api_function_timeout": 5,
"antminer_mining_mode_as_str": False,
"default_whatsminer_password": "admin", "default_whatsminer_password": "admin",
"default_innosilicon_password": "admin", "default_innosilicon_password": "admin",
"default_antminer_password": "root", "default_antminer_password": "root",

View File

@@ -50,49 +50,49 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S17 (BOS) ## S17 (BOS+)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17 ::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S17+ (BOS) ## S17+ (BOS+)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Plus ::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Plus
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S17 Pro (BOS) ## S17 Pro (BOS+)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Pro ::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Pro
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S17e (BOS) ## S17e (BOS+)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17e ::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17e
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## T17 (BOS) ## T17 (BOS+)
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17 ::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## T17+ (BOS) ## T17+ (BOS+)
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17Plus ::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17Plus
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## T17e (BOS) ## T17e (BOS+)
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17e ::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17e
handler: python handler: python
options: options:

View File

@@ -85,6 +85,34 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19 Hydro
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19Hydro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 Pro Hydro
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProHydro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 Pro+ Hydro
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19ProPlusHydro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 Pro+ Hydro
::: pyasic.miners.antminer.bmminer.X19.S19.BMMinerS19KPro
handler: python
options:
show_root_heading: false
heading_level: 4
## T19 ## T19
::: pyasic.miners.antminer.bmminer.X19.T19.BMMinerT19 ::: pyasic.miners.antminer.bmminer.X19.T19.BMMinerT19
handler: python handler: python
@@ -92,49 +120,91 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19 (BOS) ## S19
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19 ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19 Pro (BOS) ## S19+
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Plus
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 Pro
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Pro ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19Pro
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19j (BOS) ## S19a
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19a
handler: python
options:
show_root_heading: false
heading_level: 4
## S19a Pro
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19aPro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19j
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19j ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19j
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19j No PIC (BOS) ## S19j No PIC
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jNoPIC ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jNoPIC
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19j Pro (BOS) ## S19j Pro
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jPro ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jPro
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19j Pro (BOS) ## S19j Pro
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jPro ::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jPro
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## T19 (BOS) ## S19j Pro+
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19jProPlus
handler: python
options:
show_root_heading: false
heading_level: 4
## S19k Pro No PIC
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19kProNoPIC
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 XP
::: pyasic.miners.antminer.bosminer.X19.S19.BOSMinerS19XP
handler: python
options:
show_root_heading: false
heading_level: 4
## T19
::: pyasic.miners.antminer.bosminer.X19.T19.BOSMinerT19 ::: pyasic.miners.antminer.bosminer.X19.T19.BOSMinerT19
handler: python handler: python
options: options:
@@ -225,6 +295,20 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19j Pro+ (ePIC)
::: pyasic.miners.antminer.epic.X19.S19.ePICS19jProPlus
handler: python
options:
show_root_heading: false
heading_level: 4
## S19k Pro (ePIC)
::: pyasic.miners.antminer.epic.X19.S19.ePICS19kPro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 XP (ePIC) ## S19 XP (ePIC)
::: pyasic.miners.antminer.epic.X19.S19.ePICS19XP ::: pyasic.miners.antminer.epic.X19.S19.ePICS19XP
handler: python handler: python
@@ -232,3 +316,52 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S19 (LuxOS)
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 Pro (LuxOS)
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19Pro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19j Pro (LuxOS)
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19jPro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19j Pro+ (LuxOS)
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19jProPlus
handler: python
options:
show_root_heading: false
heading_level: 4
## S19k Pro (LuxOS)
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19kPro
handler: python
options:
show_root_heading: false
heading_level: 4
## S19 XP (LuxOS)
::: pyasic.miners.antminer.luxos.X19.S19.LUXMinerS19XP
handler: python
options:
show_root_heading: false
heading_level: 4
## T19 (LuxOS)
::: pyasic.miners.antminer.luxos.X19.T19.LUXMinerT19
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,24 @@
# pyasic
## X21 Models
## S21
::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21
handler: python
options:
show_root_heading: false
heading_level: 4
## S21 (ePIC)
::: pyasic.miners.antminer.epic.X21.S21.ePICS21
handler: python
options:
show_root_heading: false
heading_level: 4
## S21 (LuxOS)
::: pyasic.miners.antminer.luxos.X21.S21.LUXMinerS21
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -29,3 +29,10 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## L3+ (VNish)
::: pyasic.miners.antminer.vnish.X3.L3.VnishL3Plus
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -8,3 +8,10 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## L7 (VNish)
::: pyasic.miners.antminer.vnish.X7.L7.VnishL7
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -36,14 +36,14 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## S9 (BOS) ## S9 (BOS+)
::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9 ::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## T9 (Hiveon) ## T9 (Hive)
::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9 ::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9
handler: python handler: python
options: options:

View File

@@ -0,0 +1,24 @@
# pyasic
## AD Models
## AT1500
::: pyasic.miners.auradine.flux.AD.AT1.AuradineFluxAT1500
handler: python
options:
show_root_heading: false
heading_level: 4
## AT2860
::: pyasic.miners.auradine.flux.AD.AT2.AuradineFluxAT2860
handler: python
options:
show_root_heading: false
heading_level: 4
## AT2880
::: pyasic.miners.auradine.flux.AD.AT2.AuradineFluxAT2880
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,17 @@
# pyasic
## AI Models
## AI2500
::: pyasic.miners.auradine.flux.AI.AI2.AuradineFluxAI2500
handler: python
options:
show_root_heading: false
heading_level: 4
## AI3680
::: pyasic.miners.auradine.flux.AI.AI3.AuradineFluxAI3680
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -0,0 +1,17 @@
# pyasic
## AT Models
## AD2500
::: pyasic.miners.auradine.flux.AT.AD2.AuradineFluxAD2500
handler: python
options:
show_root_heading: false
heading_level: 4
## AD3500
::: pyasic.miners.auradine.flux.AT.AD3.AuradineFluxAD3500
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,7 +1,15 @@
# pyasic # pyasic
## BOSMiner Backend ## BOSMiner Backend
::: pyasic.miners.backends.bosminer.BOSMiner ::: pyasic.miners.backends.braiins_os.BOSMiner
handler: python
options:
show_root_heading: false
heading_level: 4
## BOSer Backend
::: pyasic.miners.backends.braiins_os.BOSer
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,10 +1,17 @@
# pyasic # pyasic
## Base Miner ## Base Miner
[`BaseMiner`][pyasic.miners.BaseMiner] is the basis for all miner classes, they all subclass (usually indirectly) from this class. [`BaseMiner`][pyasic.miners.base.BaseMiner] is the basis for all miner classes, they all subclass (usually indirectly) from this class.
You may not instantiate this class on its own, only subclass from it. Trying to instantiate an instance of this class will raise `TypeError`. This class inherits from the [`MinerProtocol`][pyasic.miners.base.MinerProtocol], which outlines functionality for miners.
::: pyasic.miners.BaseMiner You may not instantiate this class on its own, only subclass from it.
::: pyasic.miners.base.BaseMiner
handler: python
options:
heading_level: 4
::: pyasic.miners.base.MinerProtocol
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4

View File

@@ -1,91 +1,91 @@
## Control functionality ## Control functionality
### Check Light ### Check Light
::: pyasic.miners.BaseMiner.check_light ::: pyasic.miners.base.MinerProtocol.check_light
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Fault Light Off ### Fault Light Off
::: pyasic.miners.BaseMiner.fault_light_off ::: pyasic.miners.base.MinerProtocol.fault_light_off
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Fault Light On ### Fault Light On
::: pyasic.miners.BaseMiner.fault_light_on ::: pyasic.miners.base.MinerProtocol.fault_light_on
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Get Config ### Get Config
::: pyasic.miners.BaseMiner.get_config ::: pyasic.miners.base.MinerProtocol.get_config
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Get Data ### Get Data
::: pyasic.miners.BaseMiner.get_data ::: pyasic.miners.base.MinerProtocol.get_data
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Get Errors ### Get Errors
::: pyasic.miners.BaseMiner.get_errors ::: pyasic.miners.base.MinerProtocol.get_errors
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Get Hostname ### Get Hostname
::: pyasic.miners.BaseMiner.get_hostname ::: pyasic.miners.base.MinerProtocol.get_hostname
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Get Model ### Get Model
::: pyasic.miners.BaseMiner.get_model ::: pyasic.miners.base.MinerProtocol.get_model
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Reboot ### Reboot
::: pyasic.miners.BaseMiner.reboot ::: pyasic.miners.base.MinerProtocol.reboot
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Restart Backend ### Restart Backend
::: pyasic.miners.BaseMiner.restart_backend ::: pyasic.miners.base.MinerProtocol.restart_backend
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Stop Mining ### Stop Mining
::: pyasic.miners.BaseMiner.stop_mining ::: pyasic.miners.base.MinerProtocol.stop_mining
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Resume Mining ### Resume Mining
::: pyasic.miners.BaseMiner.resume_mining ::: pyasic.miners.base.MinerProtocol.resume_mining
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Is Mining ### Is Mining
::: pyasic.miners.BaseMiner.is_mining ::: pyasic.miners.base.MinerProtocol.is_mining
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Send Config ### Send Config
::: pyasic.miners.BaseMiner.send_config ::: pyasic.miners.base.MinerProtocol.send_config
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4
### Set Power Limit ### Set Power Limit
::: pyasic.miners.BaseMiner.set_power_limit ::: pyasic.miners.base.MinerProtocol.set_power_limit
handler: python handler: python
options: options:
heading_level: 4 heading_level: 4

View File

@@ -2,21 +2,21 @@
## X5 Models ## X5 Models
## CK5 ## CK5
::: pyasic.miners.goldshell.bfgminer.X5.CK5.BFGMinerCK5 ::: pyasic.miners.goldshell.bfgminer.X5.CK5.GoldshellCK5
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## HS5 ## HS5
::: pyasic.miners.goldshell.bfgminer.X5.HS5.BFGMinerHS5 ::: pyasic.miners.goldshell.bfgminer.X5.HS5.GoldshellHS5
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## KD5 ## KD5
::: pyasic.miners.goldshell.bfgminer.X5.KD5.BFGMinerKD5 ::: pyasic.miners.goldshell.bfgminer.X5.KD5.GoldshellKD5
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -0,0 +1,17 @@
# pyasic
## XBox Models
## KD Box II
::: pyasic.miners.goldshell.bfgminer.XBox.KDBox.GoldshellKDBoxII
handler: python
options:
show_root_heading: false
heading_level: 4
## KD Box Pro
::: pyasic.miners.goldshell.bfgminer.XBox.KDBox.GoldshellKDBoxPro
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -2,7 +2,7 @@
## XMax Models ## XMax Models
## KD Max ## KD Max
::: pyasic.miners.goldshell.bfgminer.XMax.KDMax.BFGMinerKDMax ::: pyasic.miners.goldshell.bfgminer.XMax.KDMax.GoldshellKDMax
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -2,7 +2,7 @@
## A10X Models ## A10X Models
## A10X ## A10X
::: pyasic.miners.innosilicon.cgminer.A10X.A10X.CGMinerA10X ::: pyasic.miners.innosilicon.cgminer.A10X.A10X.InnosiliconA10X
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -2,7 +2,7 @@
## T3X Models ## T3X Models
## T3H+ ## T3H+
::: pyasic.miners.innosilicon.cgminer.T3X.T3H.CGMinerT3HPlus ::: pyasic.miners.innosilicon.cgminer.T3X.T3H.InnosiliconT3HPlus
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,7 +1,7 @@
# 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. [`MinerFactory`][pyasic.MinerFactory] is the way to create miner types in `pyasic`. The most important method is [`get_miner()`][pyasic.get_miner], which is mapped to [`pyasic.get_miner()`][pyasic.get_miner], and should be used from there.
The instance used for [`pyasic.get_miner()`][pyasic.get_miner] is `pyasic.miner_factory`. The instance used for [`pyasic.get_miner()`][pyasic.get_miner] is `pyasic.miner_factory`.
@@ -9,7 +9,7 @@ The instance used for [`pyasic.get_miner()`][pyasic.get_miner] is `pyasic.miner_
Finally, there is functionality to get multiple miners without using `asyncio.gather()` explicitly. Use `pyasic.miner_factory.get_multiple_miners()` with a list of IPs as strings to get a list of miner instances. You can also get multiple miners with an `AsyncGenerator` by using `pyasic.miner_factory.get_miner_generator()`. Finally, there is functionality to get multiple miners without using `asyncio.gather()` explicitly. Use `pyasic.miner_factory.get_multiple_miners()` with a list of IPs as strings to get a list of miner instances. You can also get multiple miners with an `AsyncGenerator` by using `pyasic.miner_factory.get_miner_generator()`.
::: pyasic.miners.miner_factory.MinerFactory ::: pyasic.miners.factory.MinerFactory
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
@@ -25,12 +25,12 @@ Finally, there is functionality to get multiple miners without using `asyncio.ga
<br> <br>
## AnyMiner ## AnyMiner
::: pyasic.miners.miner_factory.AnyMiner ::: pyasic.miners.base.AnyMiner
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
[`AnyMiner`][pyasic.miners.miner_factory.AnyMiner] is a placeholder type variable used for typing returns of functions. [`AnyMiner`][pyasic.miners.base.AnyMiner] is a placeholder type variable used for typing returns of functions.
A function returning [`AnyMiner`][pyasic.miners.miner_factory.AnyMiner] will always return a subclass of [`BaseMiner`][pyasic.miners.BaseMiner], A function returning [`AnyMiner`][pyasic.miners.base.AnyMiner] will always return a subclass of [`BaseMiner`][pyasic.miners.BaseMiner],
and is used to specify a function returning some arbitrary type of miner class instance. and is used to specify a function returning some arbitrary type of miner class instance.

View File

@@ -78,9 +78,19 @@ details {
<li><a href="../antminer/X19#s19-xp">S19 XP</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">S19a</a></li>
<li><a href="../antminer/X19#s19a-pro">S19a Pro</a></li> <li><a href="../antminer/X19#s19a-pro">S19a Pro</a></li>
<li><a href="../antminer/X19#s19-hydro">S19 Hydro</a></li>
<li><a href="../antminer/X19#s19-pro-hydro">S19 Pro Hydro</a></li>
<li><a href="../antminer/X19#s19-pro_1-hydro">S19 Pro+ Hydro</a></li>
<li><a href="../antminer/X19#s19-pro_1-hydro">S19 Pro+ Hydro</a></li>
<li><a href="../antminer/X19#t19">T19</a></li> <li><a href="../antminer/X19#t19">T19</a></li>
</ul> </ul>
</details> </details>
<details>
<summary>X21 Series:</summary>
<ul>
<li><a href="../antminer/X21#s21">S21</a></li>
</ul>
</details>
</ul> </ul>
</details> </details>
<details> <details>
@@ -286,13 +296,39 @@ details {
<li><a href="../whatsminer/M5X#m50s_1_1-vk30">M50S++ VK30</a></li> <li><a href="../whatsminer/M5X#m50s_1_1-vk30">M50S++ VK30</a></li>
<li><a href="../whatsminer/M5X#m53-vh30">M53 VH30</a></li> <li><a href="../whatsminer/M5X#m53-vh30">M53 VH30</a></li>
<li><a href="../whatsminer/M5X#m53s-vh30">M53S VH30</a></li> <li><a href="../whatsminer/M5X#m53s-vh30">M53S VH30</a></li>
<li><a href="../whatsminer/M5X#m53s-vj40">M53S VJ40</a></li>
<li><a href="../whatsminer/M5X#m53s_1-vj30">M53S+ VJ30</a></li> <li><a href="../whatsminer/M5X#m53s_1-vj30">M53S+ VJ30</a></li>
<li><a href="../whatsminer/M5X#m53s_1_1-vk10">M53S++ VK10</a></li>
<li><a href="../whatsminer/M5X#m56-vh30">M56 VH30</a></li> <li><a href="../whatsminer/M5X#m56-vh30">M56 VH30</a></li>
<li><a href="../whatsminer/M5X#m56s-vh30">M56S VH30</a></li> <li><a href="../whatsminer/M5X#m56s-vh30">M56S VH30</a></li>
<li><a href="../whatsminer/M5X#m56s_1-vj30">M56S+ VJ30</a></li> <li><a href="../whatsminer/M5X#m56s_1-vj30">M56S+ VJ30</a></li>
<li><a href="../whatsminer/M5X#m59-vh30">M59 VH30</a></li> <li><a href="../whatsminer/M5X#m59-vh30">M59 VH30</a></li>
</ul> </ul>
</details> </details>
<details>
<summary>M6X Series:</summary>
<ul>
<li><a href="../whatsminer/M6X#m60-vk10">M60 VK10</a></li>
<li><a href="../whatsminer/M6X#m60-vk20">M60 VK20</a></li>
<li><a href="../whatsminer/M6X#m60-vk30">M60 VK30</a></li>
<li><a href="../whatsminer/M6X#m60-vk40">M60 VK40</a></li>
<li><a href="../whatsminer/M6X#m60s-vk10">M60S VK10</a></li>
<li><a href="../whatsminer/M6X#m60s-vk20">M60S VK20</a></li>
<li><a href="../whatsminer/M6X#m60s-vk30">M60S VK30</a></li>
<li><a href="../whatsminer/M6X#m60s-vk40">M60S VK40</a></li>
<li><a href="../whatsminer/M6X#m63-vk10">M63 VK10</a></li>
<li><a href="../whatsminer/M6X#m63-vk20">M63 VK20</a></li>
<li><a href="../whatsminer/M6X#m63-vk30">M63 VK30</a></li>
<li><a href="../whatsminer/M6X#m63s-vk10">M63S VK10</a></li>
<li><a href="../whatsminer/M6X#m63s-vk20">M63S VK20</a></li>
<li><a href="../whatsminer/M6X#m63s-vk30">M63S VK30</a></li>
<li><a href="../whatsminer/M6X#m66-vk20">M66 VK20</a></li>
<li><a href="../whatsminer/M6X#m66-vk30">M66 VK30</a></li>
<li><a href="../whatsminer/M6X#m66s-vk20">M66S VK20</a></li>
<li><a href="../whatsminer/M6X#m66s-vk30">M66S VK30</a></li>
<li><a href="../whatsminer/M6X#m66s-vk40">M66S VK40</a></li>
</ul>
</details>
</ul> </ul>
</details> </details>
<details> <details>
@@ -376,6 +412,13 @@ details {
<li><a href="../goldshell/XMax#kd-max">KD Max</a></li> <li><a href="../goldshell/XMax#kd-max">KD Max</a></li>
</ul> </ul>
</details> </details>
<details>
<summary>XBox Series:</summary>
<ul>
<li><a href="../goldshell/XBox#kd-box-ii">KD Box II</a></li>
<li><a href="../goldshell/XBox#kd-box-pro">KD Box Pro</a></li>
</ul>
</details>
</ul> </ul>
</details> </details>
<details> <details>
@@ -384,31 +427,37 @@ details {
<details> <details>
<summary>X9 Series:</summary> <summary>X9 Series:</summary>
<ul> <ul>
<li><a href="../antminer/X9#s9-bos">S9 (BOS)</a></li> <li><a href="../antminer/X9#s9-bos_1">S9 (BOS+)</a></li>
</ul> </ul>
</details> </details>
<details> <details>
<summary>X17 Series:</summary> <summary>X17 Series:</summary>
<ul> <ul>
<li><a href="../antminer/X17#s17-bos">S17 (BOS)</a></li> <li><a href="../antminer/X17#s17-bos_1">S17 (BOS+)</a></li>
<li><a href="../antminer/X17#s17_1-bos">S17+ (BOS)</a></li> <li><a href="../antminer/X17#s17_1-bos_1">S17+ (BOS+)</a></li>
<li><a href="../antminer/X17#s17-pro-bos">S17 Pro (BOS)</a></li> <li><a href="../antminer/X17#s17-pro-bos_1">S17 Pro (BOS+)</a></li>
<li><a href="../antminer/X17#s17e-bos">S17e (BOS)</a></li> <li><a href="../antminer/X17#s17e-bos_1">S17e (BOS+)</a></li>
<li><a href="../antminer/X17#t17-bos">T17 (BOS)</a></li> <li><a href="../antminer/X17#t17-bos_1">T17 (BOS+)</a></li>
<li><a href="../antminer/X17#t17_1-bos">T17+ (BOS)</a></li> <li><a href="../antminer/X17#t17_1-bos_1">T17+ (BOS+)</a></li>
<li><a href="../antminer/X17#t17e-bos">T17e (BOS)</a></li> <li><a href="../antminer/X17#t17e-bos_1">T17e (BOS+)</a></li>
</ul> </ul>
</details> </details>
<details> <details>
<summary>X19 Series:</summary> <summary>X19 Series:</summary>
<ul> <ul>
<li><a href="../antminer/X19#s19-bos">S19 (BOS)</a></li> <li><a href="../antminer/X19#s19">S19</a></li>
<li><a href="../antminer/X19#s19-pro-bos">S19 Pro (BOS)</a></li> <li><a href="../antminer/X19#s19_1">S19+</a></li>
<li><a href="../antminer/X19#s19j-bos">S19j (BOS)</a></li> <li><a href="../antminer/X19#s19-pro">S19 Pro</a></li>
<li><a href="../antminer/X19#s19j-no-pic-bos">S19j No PIC (BOS)</a></li> <li><a href="../antminer/X19#s19a">S19a</a></li>
<li><a href="../antminer/X19#s19j-pro-bos">S19j Pro (BOS)</a></li> <li><a href="../antminer/X19#s19a-pro">S19a Pro</a></li>
<li><a href="../antminer/X19#s19j-pro-bos">S19j Pro (BOS)</a></li> <li><a href="../antminer/X19#s19j">S19j</a></li>
<li><a href="../antminer/X19#t19-bos">T19 (BOS)</a></li> <li><a href="../antminer/X19#s19j-no-pic">S19j No PIC</a></li>
<li><a href="../antminer/X19#s19j-pro">S19j Pro</a></li>
<li><a href="../antminer/X19#s19j-pro">S19j Pro</a></li>
<li><a href="../antminer/X19#s19j-pro_1">S19j Pro+</a></li>
<li><a href="../antminer/X19#s19k-pro-no-pic">S19k Pro No PIC</a></li>
<li><a href="../antminer/X19#s19-xp">S19 XP</a></li>
<li><a href="../antminer/X19#t19">T19</a></li>
</ul> </ul>
</details> </details>
</ul> </ul>
@@ -420,6 +469,13 @@ details {
<summary>X3 Series:</summary> <summary>X3 Series:</summary>
<ul> <ul>
<li><a href="../antminer/X3#l3_1-vnish">L3+ (VNish)</a></li> <li><a href="../antminer/X3#l3_1-vnish">L3+ (VNish)</a></li>
<li><a href="../antminer/X3#l3_1-vnish">L3+ (VNish)</a></li>
</ul>
</details>
<details>
<summary>X7 Series:</summary>
<ul>
<li><a href="../antminer/X7#l7-vnish">L7 (VNish)</a></li>
</ul> </ul>
</details> </details>
<details> <details>
@@ -454,9 +510,23 @@ details {
<li><a href="../antminer/X19#s19-pro-epic">S19 Pro (ePIC)</a></li> <li><a href="../antminer/X19#s19-pro-epic">S19 Pro (ePIC)</a></li>
<li><a href="../antminer/X19#s19j-epic">S19j (ePIC)</a></li> <li><a href="../antminer/X19#s19j-epic">S19j (ePIC)</a></li>
<li><a href="../antminer/X19#s19j-pro-epic">S19j Pro (ePIC)</a></li> <li><a href="../antminer/X19#s19j-pro-epic">S19j Pro (ePIC)</a></li>
<li><a href="../antminer/X19#s19j-pro_1-epic">S19j Pro+ (ePIC)</a></li>
<li><a href="../antminer/X19#s19k-pro-epic">S19k Pro (ePIC)</a></li>
<li><a href="../antminer/X19#s19-xp-epic">S19 XP (ePIC)</a></li> <li><a href="../antminer/X19#s19-xp-epic">S19 XP (ePIC)</a></li>
</ul> </ul>
</details> </details>
<details>
<summary>X21 Series:</summary>
<ul>
<li><a href="../antminer/X21#s21-epic">S21 (ePIC)</a></li>
</ul>
</details>
<details>
<summary>blockminer Series:</summary>
<ul>
<li><a href="../blockminer/blockminer#blockminer-520i-epic">BlockMiner 520i (ePIC)</a></li>
</ul>
</details>
</ul> </ul>
</details> </details>
<details> <details>
@@ -465,7 +535,7 @@ details {
<details> <details>
<summary>X9 Series:</summary> <summary>X9 Series:</summary>
<ul> <ul>
<li><a href="../antminer/X9#t9-hiveon">T9 (Hiveon)</a></li> <li><a href="../antminer/X9#t9-hive">T9 (Hive)</a></li>
</ul> </ul>
</details> </details>
</ul> </ul>
@@ -479,5 +549,50 @@ details {
<li><a href="../antminer/X9#s9-luxos">S9 (LuxOS)</a></li> <li><a href="../antminer/X9#s9-luxos">S9 (LuxOS)</a></li>
</ul> </ul>
</details> </details>
<details>
<summary>X19 Series:</summary>
<ul>
<li><a href="../antminer/X19#s19-luxos">S19 (LuxOS)</a></li>
<li><a href="../antminer/X19#s19-pro-luxos">S19 Pro (LuxOS)</a></li>
<li><a href="../antminer/X19#s19j-pro-luxos">S19j Pro (LuxOS)</a></li>
<li><a href="../antminer/X19#s19j-pro_1-luxos">S19j Pro+ (LuxOS)</a></li>
<li><a href="../antminer/X19#s19k-pro-luxos">S19k Pro (LuxOS)</a></li>
<li><a href="../antminer/X19#s19-xp-luxos">S19 XP (LuxOS)</a></li>
<li><a href="../antminer/X19#t19-luxos">T19 (LuxOS)</a></li>
</ul>
</details>
<details>
<summary>X21 Series:</summary>
<ul>
<li><a href="../antminer/X21#s21-luxos">S21 (LuxOS)</a></li>
</ul>
</details>
</ul>
</details>
<details>
<summary>Stock Firmware Auradine Miners:</summary>
<ul>
<details>
<summary>AD Series:</summary>
<ul>
<li><a href="../auradine/AD#at1500">AT1500</a></li>
<li><a href="../auradine/AD#at2860">AT2860</a></li>
<li><a href="../auradine/AD#at2880">AT2880</a></li>
</ul>
</details>
<details>
<summary>AI Series:</summary>
<ul>
<li><a href="../auradine/AI#ai2500">AI2500</a></li>
<li><a href="../auradine/AI#ai3680">AI3680</a></li>
</ul>
</details>
<details>
<summary>AT Series:</summary>
<ul>
<li><a href="../auradine/AT#ad2500">AD2500</a></li>
<li><a href="../auradine/AT#ad3500">AD3500</a></li>
</ul>
</details>
</ul> </ul>
</details> </details>

View File

@@ -211,6 +211,13 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## M53S VJ40
::: pyasic.miners.whatsminer.btminer.M5X.M53S.BTMinerM53SVJ40
handler: python
options:
show_root_heading: false
heading_level: 4
## M53S+ VJ30 ## M53S+ VJ30
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30 ::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus.BTMinerM53SPlusVJ30
handler: python handler: python
@@ -218,6 +225,13 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## M53S++ VK10
::: pyasic.miners.whatsminer.btminer.M5X.M53S_Plus_Plus.BTMinerM53SPlusPlusVK10
handler: python
options:
show_root_heading: false
heading_level: 4
## M56 VH30 ## M56 VH30
::: pyasic.miners.whatsminer.btminer.M5X.M56.BTMinerM56VH30 ::: pyasic.miners.whatsminer.btminer.M5X.M56.BTMinerM56VH30
handler: python handler: python

View File

@@ -0,0 +1,136 @@
# pyasic
## M6X Models
## M60 VK10
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK10
handler: python
options:
show_root_heading: false
heading_level: 4
## M60 VK20
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK20
handler: python
options:
show_root_heading: false
heading_level: 4
## M60 VK30
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK30
handler: python
options:
show_root_heading: false
heading_level: 4
## M60 VK40
::: pyasic.miners.whatsminer.btminer.M6X.M60.BTMinerM60VK40
handler: python
options:
show_root_heading: false
heading_level: 4
## M60S VK10
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK10
handler: python
options:
show_root_heading: false
heading_level: 4
## M60S VK20
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK20
handler: python
options:
show_root_heading: false
heading_level: 4
## M60S VK30
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK30
handler: python
options:
show_root_heading: false
heading_level: 4
## M60S VK40
::: pyasic.miners.whatsminer.btminer.M6X.M60S.BTMinerM60SVK40
handler: python
options:
show_root_heading: false
heading_level: 4
## M63 VK10
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK10
handler: python
options:
show_root_heading: false
heading_level: 4
## M63 VK20
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK20
handler: python
options:
show_root_heading: false
heading_level: 4
## M63 VK30
::: pyasic.miners.whatsminer.btminer.M6X.M63.BTMinerM63VK30
handler: python
options:
show_root_heading: false
heading_level: 4
## M63S VK10
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK10
handler: python
options:
show_root_heading: false
heading_level: 4
## M63S VK20
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK20
handler: python
options:
show_root_heading: false
heading_level: 4
## M63S VK30
::: pyasic.miners.whatsminer.btminer.M6X.M63S.BTMinerM63SVK30
handler: python
options:
show_root_heading: false
heading_level: 4
## M66 VK20
::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VK20
handler: python
options:
show_root_heading: false
heading_level: 4
## M66 VK30
::: pyasic.miners.whatsminer.btminer.M6X.M66.BTMinerM66VK30
handler: python
options:
show_root_heading: false
heading_level: 4
## M66S VK20
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK20
handler: python
options:
show_root_heading: false
heading_level: 4
## M66S VK30
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK30
handler: python
options:
show_root_heading: false
heading_level: 4
## M66S VK40
::: pyasic.miners.whatsminer.btminer.M6X.M66S.BTMinerM66SVK40
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,3 +1,3 @@
jinja2<3.1.0 jinja2<3.1.3
mkdocs mkdocs
mkdocstrings[python] mkdocstrings[python]

27
docs/rpc/api.md Normal file
View File

@@ -0,0 +1,27 @@
# pyasic
## Miner APIs
Each miner has a unique API that is used to communicate with it.
Each of these API types has commands that differ between them, and some commands have data that others do not.
Each miner that is a subclass of [`BaseMiner`][pyasic.miners.BaseMiner] should have an API linked to it as `Miner.api`.
All API implementations inherit from [`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI], which implements the basic communications protocols.
[`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI] should never be used unless inheriting to create a new miner API class for a new type of miner (which should be exceedingly rare).
[`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI] cannot be instantiated directly, it will raise a `TypeError`.
Use these instead -
#### [BFGMiner API][pyasic.rpc.bfgminer.BFGMinerRPCAPI]
#### [BMMiner API][pyasic.rpc.bmminer.BMMinerRPCAPI]
#### [BOSMiner API][pyasic.rpc.bosminer.BOSMinerRPCAPI]
#### [BTMiner API][pyasic.rpc.btminer.BTMinerRPCAPI]
#### [CGMiner API][pyasic.rpc.cgminer.CGMinerRPCAPI]
#### [LUXMiner API][pyasic.rpc.luxminer.LUXMinerRPCAPI]
#### [Unknown API][pyasic.rpc.unknown.UnknownRPCAPI]
<br>
## BaseMinerRPCAPI
::: pyasic.rpc.base.BaseMinerRPCAPI
handler: python
options:
heading_level: 4

View File

@@ -1,6 +1,6 @@
# pyasic # pyasic
## BFGMinerAPI ## BFGMinerRPCAPI
::: pyasic.API.bfgminer.BFGMinerAPI ::: pyasic.rpc.bfgminer.BFGMinerRPCAPI
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,6 +1,6 @@
# pyasic # pyasic
## BMMinerAPI ## BMMinerRPCAPI
::: pyasic.API.bmminer.BMMinerAPI ::: pyasic.rpc.bmminer.BMMinerRPCAPI
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,6 +1,6 @@
# pyasic # pyasic
## BOSMinerAPI ## BOSMinerRPCAPI
::: pyasic.API.bosminer.BOSMinerAPI ::: pyasic.rpc.bosminer.BOSMinerRPCAPI
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,6 +1,6 @@
# pyasic # pyasic
## BTMinerAPI ## BTMinerRPCAPI
::: pyasic.API.btminer.BTMinerAPI ::: pyasic.rpc.btminer.BTMinerRPCAPI
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,6 +1,6 @@
# pyasic # pyasic
## CGMinerAPI ## CGMinerRPCAPI
::: pyasic.API.cgminer.CGMinerAPI ::: pyasic.rpc.cgminer.CGMinerRPCAPI
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,6 +1,6 @@
# pyasic # pyasic
## LUXMinerAPI ## LUXMinerRPCAPI
::: pyasic.API.luxminer.LUXMinerAPI ::: pyasic.rpc.luxminer.LUXMinerRPCAPI
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -1,6 +1,6 @@
# pyasic # pyasic
## UnknownAPI ## UnknownRPCAPI
::: pyasic.API.unknown.UnknownAPI ::: pyasic.rpc.unknown.UnknownRPCAPI
handler: python handler: python
options: options:
show_root_heading: false show_root_heading: false

View File

@@ -4,6 +4,7 @@
All settings here are global settings for all of pyasic. Set these settings with `update(key, value)`. All settings here are global settings for all of pyasic. Set these settings with `update(key, value)`.
Settings options: Settings options:
- `network_ping_retries` - `network_ping_retries`
- `network_ping_timeout` - `network_ping_timeout`
- `network_scan_threads` - `network_scan_threads`
@@ -11,6 +12,7 @@ Settings options:
- `factory_get_timeout` - `factory_get_timeout`
- `get_data_retries` - `get_data_retries`
- `api_function_timeout` - `api_function_timeout`
- `antminer_mining_mode_as_str`
- `default_whatsminer_password` - `default_whatsminer_password`
- `default_innosilicon_password` - `default_innosilicon_password`
- `default_antminer_password` - `default_antminer_password`

View File

@@ -13,15 +13,15 @@ nav:
- Error Codes: "data/error_codes.md" - Error Codes: "data/error_codes.md"
- Miner Config: "config/miner_config.md" - Miner Config: "config/miner_config.md"
- Advanced: - Advanced:
- Miner APIs: - RPC APIs:
- Intro: "API/api.md" - Intro: "rpc/api.md"
- BFGMiner: "API/bfgminer.md" - BFGMiner: "rpc/bfgminer.md"
- BMMiner: "API/bmminer.md" - BMMiner: "rpc/bmminer.md"
- BOSMiner: "API/bosminer.md" - BOSMiner: "rpc/bosminer.md"
- BTMiner: "API/btminer.md" - BTMiner: "rpc/btminer.md"
- CGMiner: "API/cgminer.md" - CGMiner: "rpc/cgminer.md"
- LUXMiner: "API/luxminer.md" - LUXMiner: "rpc/luxminer.md"
- Unknown: "API/unknown.md" - Unknown: "rpc/unknown.md"
- Backends: - Backends:
- BMMiner: "miners/backends/bmminer.md" - BMMiner: "miners/backends/bmminer.md"
- BOSMiner: "miners/backends/bosminer.md" - BOSMiner: "miners/backends/bosminer.md"
@@ -40,6 +40,7 @@ nav:
- Antminer X15: "miners/antminer/X15.md" - Antminer X15: "miners/antminer/X15.md"
- Antminer X17: "miners/antminer/X17.md" - Antminer X17: "miners/antminer/X17.md"
- Antminer X19: "miners/antminer/X19.md" - Antminer X19: "miners/antminer/X19.md"
- Antminer X21: "miners/antminer/X21.md"
- Avalon 7X: "miners/avalonminer/A7X.md" - Avalon 7X: "miners/avalonminer/A7X.md"
- Avalon 8X: "miners/avalonminer/A8X.md" - Avalon 8X: "miners/avalonminer/A8X.md"
- Avalon 9X: "miners/avalonminer/A9X.md" - Avalon 9X: "miners/avalonminer/A9X.md"

View File

@@ -1,674 +0,0 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import logging
from pyasic.API import APIError, BaseMinerAPI
class BFGMinerAPI(BaseMinerAPI):
"""An abstraction of the BFGMiner API.
Each method corresponds to an API command in BFGMiner.
[BFGMiner API documentation](https://github.com/luke-jr/bfgminer/blob/bfgminer/README.RPC)
This class abstracts use of the BFGMiner 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):
super().__init__(ip, port)
self.api_ver = api_ver
async def multicommand(self, *commands: str, allow_warning: bool = True) -> dict:
# make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2"
# doesn't work for S19 which uses the backup _x19_multicommand
command = "+".join(commands)
try:
data = await self.send_command(command, allow_warning=allow_warning)
except APIError:
logging.debug(f"{self} - (Multicommand) - Handling X19 multicommand.")
data = await self._x19_multicommand(*command.split("+"))
data["multicommand"] = True
return data
async def _x19_multicommand(self, *commands) -> dict:
tasks = []
# send all commands individually
for cmd in commands:
tasks.append(
asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
)
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data
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 config(self) -> dict:
"""Get some basic configuration info.
<details>
<summary>Expand</summary>
Returns:
## Some miner configuration information:
* ASC Count <- the number of ASCs
* PGA Count <- the number of PGAs
* Pool Count <- the number of Pools
* Strategy <- the current pool strategy
* Log Interval <- the interval of logging
* Device Code <- list of compiled device drivers
* OS <- the current operating system
* Failover-Only <- failover-only setting
* Scan Time <- scan-time setting
* Queue <- queue setting
* Expiry <- expiry setting
</details>
"""
return await self.send_command("config")
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 pools(self) -> dict:
"""Get pool information.
<details>
<summary>Expand</summary>
Returns:
Miner pool information.
</details>
"""
return await self.send_command("pools")
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 procs(self) -> dict:
"""Get data on each processor with their details.
<details>
<summary>Expand</summary>
Returns:
Data on each processor with their details.
</details>
"""
return await self.send_command("procs")
async def devscan(self, info: str = "") -> dict:
"""Get data on each processor with their details.
<details>
<summary>Expand</summary>
Parameters:
info: Info to scan for device by.
Returns:
Data on each processor with their details.
</details>
"""
return await self.send_command("devscan", parameters=info)
async def pga(self, n: int) -> dict:
"""Get data from PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA number to get data from.
Returns:
Data on the PGA n.
</details>
"""
return await self.send_command("pga", parameters=n)
async def proc(self, n: int = 0) -> dict:
"""Get data processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to get data on.
Returns:
Data on processor n.
</details>
"""
return await self.send_command("proc", parameters=n)
async def pgacount(self) -> dict:
"""Get data fon all PGAs.
<details>
<summary>Expand</summary>
Returns:
Data on the PGAs connected.
</details>
"""
return await self.send_command("pgacount")
async def proccount(self) -> dict:
"""Get data fon all processors.
<details>
<summary>Expand</summary>
Returns:
Data on the processors connected.
</details>
"""
return await self.send_command("proccount")
async def switchpool(self, n: int) -> dict:
"""Switch pools to pool n.
<details>
<summary>Expand</summary>
Parameters:
n: The pool to switch to.
Returns:
A confirmation of switching to pool n.
</details>
"""
return await self.send_command("switchpool", parameters=n)
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 addpool(self, url: str, username: str, password: str) -> dict:
"""Add a pool to the miner.
<details>
<summary>Expand</summary>
Parameters:
url: The URL of the new pool to add.
username: The users username on the new pool.
password: The worker password on the new pool.
Returns:
A confirmation of adding the pool.
</details>
"""
return await self.send_command(
"addpool", parameters=f"{url},{username},{password}"
)
async def poolpriority(self, *n: int) -> dict:
"""Set pool priority.
<details>
<summary>Expand</summary>
Parameters:
*n: Pools in order of priority.
Returns:
A confirmation of setting pool priority.
</details>
"""
pools = f"{','.join([str(item) for item in n])}"
return await self.send_command("poolpriority", parameters=pools)
async def poolquota(self, n: int, q: int) -> dict:
"""Set pool quota.
<details>
<summary>Expand</summary>
Parameters:
n: Pool number to set quota on.
q: Quota to set the pool to.
Returns:
A confirmation of setting pool quota.
</details>
"""
return await self.send_command("poolquota", parameters=f"{n},{q}")
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 removepool(self, n: int) -> dict:
"""Remove a pool.
<details>
<summary>Expand</summary>
Parameters:
n: Pool to remove.
Returns:
A confirmation of removing the pool.
</details>
"""
return await self.send_command("removepool", parameters=n)
async def save(self, filename: str = None) -> dict:
"""Save the config.
<details>
<summary>Expand</summary>
Parameters:
filename: Filename to save the config as.
Returns:
A confirmation of saving the config.
</details>
"""
if filename:
return await self.send_command("save", parameters=filename)
else:
return await self.send_command("save")
async def quit(self) -> dict:
"""Quit CGMiner.
<details>
<summary>Expand</summary>
Returns:
A single "BYE" before CGMiner quits.
</details>
"""
return await self.send_command("quit")
async def notify(self) -> dict:
"""Notify the user of past errors.
<details>
<summary>Expand</summary>
Returns:
The last status and count of each devices problem(s).
</details>
"""
return await self.send_command("notify")
async def privileged(self) -> dict:
"""Check if you have privileged access.
<details>
<summary>Expand</summary>
Returns:
The STATUS section with an error if you have no privileged access, or success if you have privileged access.
</details>
"""
return await self.send_command("privileged")
async def pgaenable(self, n: int) -> dict:
"""Enable PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to enable.
Returns:
A confirmation of enabling PGA n.
</details>
"""
return await self.send_command("pgaenable", parameters=n)
async def pgadisable(self, n: int) -> dict:
"""Disable PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to disable.
Returns:
A confirmation of disabling PGA n.
</details>
"""
return await self.send_command("pgadisable", parameters=n)
async def pgarestart(self, n: int) -> dict:
"""Restart PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to restart.
Returns:
A confirmation of restarting PGA n.
</details>
"""
return await self.send_command("pgadisable", parameters=n)
async def pgaidentify(self, n: int) -> dict:
"""Identify PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to identify.
Returns:
A confirmation of identifying PGA n.
</details>
"""
return await self.send_command("pgaidentify", parameters=n)
async def procenable(self, n: int) -> dict:
"""Enable processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to enable.
Returns:
A confirmation of enabling processor n.
</details>
"""
return await self.send_command("procenable", parameters=n)
async def procdisable(self, n: int) -> dict:
"""Disable processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to disable.
Returns:
A confirmation of disabling processor n.
</details>
"""
return await self.send_command("procdisable", parameters=n)
async def procrestart(self, n: int) -> dict:
"""Restart processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to restart.
Returns:
A confirmation of restarting processor n.
</details>
"""
return await self.send_command("procdisable", parameters=n)
async def procidentify(self, n: int) -> dict:
"""Identify processor n.
<details>
<summary>Expand</summary>
Parameters:
n: The processor to identify.
Returns:
A confirmation of identifying processor n.
</details>
"""
return await self.send_command("procidentify", parameters=n)
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 restart(self) -> dict:
"""Restart CGMiner using the API.
<details>
<summary>Expand</summary>
Returns:
A reply informing of the restart.
</details>
"""
return await self.send_command("restart")
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 check(self, command: str) -> dict:
"""Check if the command command exists in CGMiner.
<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 failover_only(self, failover: bool) -> dict:
"""Set failover-only.
<details>
<summary>Expand</summary>
Parameters:
failover: What to set failover-only to.
Returns:
Confirmation of setting failover-only.
</details>
"""
return await self.send_command("failover-only", parameters=failover)
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 debug(self, setting: str) -> dict:
"""Set a debug setting.
<details>
<summary>Expand</summary>
Parameters:
setting: Which setting to switch to.
## Options are:
* Silent
* Quiet
* Verbose
* Debug
* RPCProto
* PerDevice
* WorkTime
* Normal
Returns:
Data on which debug setting was enabled or disabled.
</details>
"""
return await self.send_command("debug", parameters=setting)
async def setconfig(self, name: str, n: int) -> dict:
"""Set config of name to value n.
<details>
<summary>Expand</summary>
Parameters:
name: The name of the config setting to set.
## Options are:
* queue
* scantime
* expiry
n: The value to set the 'name' setting to.
Returns:
The results of setting config of name to n.
</details>
"""
return await self.send_command("setconfig", parameters=f"{name},{n}")
async def pgaset(self, n: int, opt: str, val: int = None) -> dict:
"""Set PGA option opt to val on PGA n.
<details>
<summary>Expand</summary>
Options:
```
MMQ -
opt: clock
val: 2 - 250 (multiple of 2)
XBS -
opt: clock
val: 2 - 250 (multiple of 2)
```
Parameters:
n: The PGA to set the options on.
opt: The option to set. Setting this to 'help' returns a help message.
val: The value to set the option to.
Returns:
Confirmation of setting PGA n with opt[,val].
</details>
"""
if val:
return await self.send_command("pgaset", parameters=f"{n},{opt},{val}")
else:
return await self.send_command("pgaset", parameters=f"{n},{opt}")
async def pprocset(self, n: int, opt: str, val: int = None) -> dict:
"""Set processor option opt to val on processor n.
<details>
<summary>Expand</summary>
Options:
```
MMQ -
opt: clock
val: 2 - 250 (multiple of 2)
XBS -
opt: clock
val: 2 - 250 (multiple of 2)
```
Parameters:
n: The PGA to set the options on.
opt: The option to set. Setting this to 'help' returns a help message.
val: The value to set the option to.
Returns:
Confirmation of setting PGA n with opt[,val].
</details>
"""
if val:
return await self.send_command("pgaset", parameters=f"{n},{opt},{val}")
else:
return await self.send_command("pgaset", parameters=f"{n},{opt}")
async def zero(self, which: str, summary: bool) -> dict:
"""Zero a device.
<details>
<summary>Expand</summary>
Parameters:
which: Which device to zero. Setting this to 'all' zeros all devices. Setting this to 'bestshare' zeros only the bestshare values for each pool and global.
summary: Whether or not to show a full summary.
Returns:
the STATUS section with info on the zero and optional summary.
</details>
"""
return await self.send_command("zero", parameters=f"{which},{summary}")

View File

@@ -1,731 +0,0 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import asyncio
import logging
from pyasic.API import APIError, BaseMinerAPI
class BMMinerAPI(BaseMinerAPI):
"""An abstraction of the BMMiner API.
Each method corresponds to an API command in BMMiner.
[BMMiner API documentation](https://github.com/jameshilliard/bmminer/blob/master/API-README)
This class abstracts use of the BMMiner 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 multicommand(self, *commands: str, allow_warning: bool = True) -> dict:
# make sure we can actually run each command, otherwise they will fail
commands = self._check_commands(*commands)
# standard multicommand format is "command1+command2"
# doesn't work for S19 which uses the backup _x19_multicommand
command = "+".join(commands)
try:
data = await self.send_command(command, allow_warning=allow_warning)
except APIError:
logging.debug(f"{self} - (Multicommand) - Handling X19 multicommand.")
data = await self._x19_multicommand(
*command.split("+"), allow_warning=allow_warning
)
data["multicommand"] = True
return data
async def _x19_multicommand(self, *commands, allow_warning: bool = True) -> dict:
tasks = []
# send all commands individually
for cmd in commands:
tasks.append(
asyncio.create_task(self._handle_multicommand(cmd, allow_warning=True))
)
all_data = await asyncio.gather(*tasks)
data = {}
for item in all_data:
data.update(item)
return data
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 config(self) -> dict:
"""Get some basic configuration info.
<details>
<summary>Expand</summary>
Returns:
## Some miner configuration information:
* ASC Count <- the number of ASCs
* PGA Count <- the number of PGAs
* Pool Count <- the number of Pools
* Strategy <- the current pool strategy
* Log Interval <- the interval of logging
* Device Code <- list of compiled device drivers
* OS <- the current operating system
* Failover-Only <- failover-only setting
* Scan Time <- scan-time setting
* Queue <- queue setting
* Expiry <- expiry setting
</details>
"""
return await self.send_command("config")
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 pools(self) -> dict:
"""Get pool information.
<details>
<summary>Expand</summary>
Returns:
Miner pool information.
</details>
"""
return await self.send_command("pools")
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 edevs(self, old: bool = False) -> dict:
"""Get data on each PGA/ASC with their details, ignoring blacklisted and zombie devices.
<details>
<summary>Expand</summary>
Parameters:
old: Include zombie devices that became zombies less than 'old' seconds ago
Returns:
Data on each PGA/ASC with their details.
</details>
"""
if old:
return await self.send_command("edevs", parameters=old)
else:
return await self.send_command("edevs")
async def pga(self, n: int) -> dict:
"""Get data from PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA number to get data from.
Returns:
Data on the PGA n.
</details>
"""
return await self.send_command("pga", parameters=n)
async def pgacount(self) -> dict:
"""Get data fon all PGAs.
<details>
<summary>Expand</summary>
Returns:
Data on the PGAs connected.
</details>
"""
return await self.send_command("pgacount")
async def switchpool(self, n: int) -> dict:
"""Switch pools to pool n.
<details>
<summary>Expand</summary>
Parameters:
n: The pool to switch to.
Returns:
A confirmation of switching to pool n.
</details>
"""
return await self.send_command("switchpool", parameters=n)
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 addpool(self, url: str, username: str, password: str) -> dict:
"""Add a pool to the miner.
<details>
<summary>Expand</summary>
Parameters:
url: The URL of the new pool to add.
username: The users username on the new pool.
password: The worker password on the new pool.
Returns:
A confirmation of adding the pool.
</details>
"""
return await self.send_command(
"addpool", parameters=f"{url},{username},{password}"
)
async def poolpriority(self, *n: int) -> dict:
"""Set pool priority.
<details>
<summary>Expand</summary>
Parameters:
*n: Pools in order of priority.
Returns:
A confirmation of setting pool priority.
</details>
"""
pools = f"{','.join([str(item) for item in n])}"
return await self.send_command("poolpriority", parameters=pools)
async def poolquota(self, n: int, q: int) -> dict:
"""Set pool quota.
<details>
<summary>Expand</summary>
Parameters:
n: Pool number to set quota on.
q: Quota to set the pool to.
Returns:
A confirmation of setting pool quota.
</details>
"""
return await self.send_command("poolquota", parameters=f"{n},{q}")
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 removepool(self, n: int) -> dict:
"""Remove a pool.
<details>
<summary>Expand</summary>
Parameters:
n: Pool to remove.
Returns:
A confirmation of removing the pool.
</details>
"""
return await self.send_command("removepool", parameters=n)
async def save(self, filename: str = None) -> dict:
"""Save the config.
<details>
<summary>Expand</summary>
Parameters:
filename: Filename to save the config as.
Returns:
A confirmation of saving the config.
</details>
"""
if filename:
return await self.send_command("save", parameters=filename)
else:
return await self.send_command("save")
async def quit(self) -> dict:
"""Quit BMMiner.
<details>
<summary>Expand</summary>
Returns:
A single "BYE" before BMMiner quits.
</details>
"""
return await self.send_command("quit")
async def notify(self) -> dict:
"""Notify the user of past errors.
<details>
<summary>Expand</summary>
Returns:
The last status and count of each devices problem(s).
</details>
"""
return await self.send_command("notify")
async def privileged(self) -> dict:
"""Check if you have privileged access.
<details>
<summary>Expand</summary>
Returns:
The STATUS section with an error if you have no privileged access, or success if you have privileged access.
</details>
"""
return await self.send_command("privileged")
async def pgaenable(self, n: int) -> dict:
"""Enable PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to enable.
Returns:
A confirmation of enabling PGA n.
</details>
"""
return await self.send_command("pgaenable", parameters=n)
async def pgadisable(self, n: int) -> dict:
"""Disable PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to disable.
Returns:
A confirmation of disabling PGA n.
</details>
"""
return await self.send_command("pgadisable", parameters=n)
async def pgaidentify(self, n: int) -> dict:
"""Identify PGA n.
<details>
<summary>Expand</summary>
Parameters:
n: The PGA to identify.
Returns:
A confirmation of identifying PGA n.
</details>
"""
return await self.send_command("pgaidentify", parameters=n)
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 restart(self) -> dict:
"""Restart BMMiner using the API.
<details>
<summary>Expand</summary>
Returns:
A reply informing of the restart.
</details>
"""
return await self.send_command("restart")
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 estats(self, old: bool = False) -> dict:
"""Get stats of each device/pool with more than 1 getwork, ignoring zombie devices.
<details>
<summary>Expand</summary>
Parameters:
old: Include zombie devices that became zombies less than 'old' seconds ago.
Returns:
Stats of each device/pool with more than 1 getwork, ignoring zombie devices.
</details>
"""
if old:
return await self.send_command("estats", parameters=old)
else:
return await self.send_command("estats")
async def check(self, command: str) -> dict:
"""Check if the command command exists in BMMiner.
<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 failover_only(self, failover: bool) -> dict:
"""Set failover-only.
<details>
<summary>Expand</summary>
Parameters:
failover: What to set failover-only to.
Returns:
Confirmation of setting failover-only.
</details>
"""
return await self.send_command("failover-only", parameters=failover)
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 debug(self, setting: str) -> dict:
"""Set a debug setting.
<details>
<summary>Expand</summary>
Parameters:
setting: Which setting to switch to.
## Options are:
* Silent
* Quiet
* Verbose
* Debug
* RPCProto
* PerDevice
* WorkTime
* Normal
Returns:
Data on which debug setting was enabled or disabled.
</details>
"""
return await self.send_command("debug", parameters=setting)
async def setconfig(self, name: str, n: int) -> dict:
"""Set config of name to value n.
<details>
<summary>Expand</summary>
Parameters:
name: The name of the config setting to set.
## Options are:
* queue
* scantime
* expiry
n: The value to set the 'name' setting to.
Returns:
The results of setting config of name to n.
</details>
"""
return await self.send_command("setconfig", parameters=f"{name},{n}")
async def usbstats(self) -> dict:
"""Get stats of all USB devices except ztex.
<details>
<summary>Expand</summary>
Returns:
The stats of all USB devices except ztex.
</details>
"""
return await self.send_command("usbstats")
async def pgaset(self, n: int, opt: str, val: int = None) -> dict:
"""Set PGA option opt to val on PGA n.
<details>
<summary>Expand</summary>
Options:
```
MMQ -
opt: clock
val: 160 - 230 (multiple of 2)
CMR -
opt: clock
val: 100 - 220
```
Parameters:
n: The PGA to set the options on.
opt: The option to set. Setting this to 'help' returns a help message.
val: The value to set the option to.
Returns:
Confirmation of setting PGA n with opt[,val].
</details>
"""
if val:
return await self.send_command("pgaset", parameters=f"{n},{opt},{val}")
else:
return await self.send_command("pgaset", parameters=f"{n},{opt}")
async def zero(self, which: str, summary: bool) -> dict:
"""Zero a device.
<details>
<summary>Expand</summary>
Parameters:
which: Which device to zero. Setting this to 'all' zeros all devices. Setting this to 'bestshare' zeros only the bestshare values for each pool and global.
summary: Whether or not to show a full summary.
Returns:
the STATUS section with info on the zero and optional summary.
</details>
"""
return await self.send_command("zero", parameters=f"{which},{summary}")
async def hotplug(self, n: int) -> dict:
"""Enable hotplug.
<details>
<summary>Expand</summary>
Parameters:
n: The device number to set hotplug on.
Returns:
Information on hotplug status.
</details>
"""
return await self.send_command("hotplug", parameters=n)
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 ascenable(self, n: int) -> dict:
"""Enable ASC device n.
<details>
<summary>Expand</summary>
Parameters:
n: The device to enable.
Returns:
Confirmation of enabling ASC device n.
</details>
"""
return await self.send_command("ascenable", parameters=n)
async def ascdisable(self, n: int) -> dict:
"""Disable ASC device n.
<details>
<summary>Expand</summary>
Parameters:
n: The device to disable.
Returns:
Confirmation of disabling ASC device n.
</details>
"""
return await self.send_command("ascdisable", parameters=n)
async def ascidentify(self, n: int) -> dict:
"""Identify ASC device n.
<details>
<summary>Expand</summary>
Parameters:
n: The device to identify.
Returns:
Confirmation of identifying ASC device n.
</details>
"""
return await self.send_command("ascidentify", 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 ascset(self, n: int, opt: str, val: int = None) -> dict:
"""Set ASC n option opt to value val.
<details>
<summary>Expand</summary>
Sets an option on the ASC n to a value. Allowed options are:
```
AVA+BTB -
opt: freq
val: 256 - 1024 (chip frequency)
BTB -
opt: millivolts
val: 1000 - 1400 (core voltage)
MBA -
opt: reset
val: 0 - # of chips (reset a chip)
opt: freq
val: 0 - # of chips, 100 - 1400 (chip frequency)
opt: ledcount
val: 0 - 100 (chip count for LED)
opt: ledlimit
val: 0 - 200 (LED off below GH/s)
opt: spidelay
val: 0 - 9999 (SPI per I/O delay)
opt: spireset
val: i or s, 0 - 9999 (SPI regular reset)
opt: spisleep
val: 0 - 9999 (SPI reset sleep in ms)
BMA -
opt: volt
val: 0 - 9
opt: clock
val: 0 - 15
```
Parameters:
n: The ASC to set the options on.
opt: The option to set. Setting this to 'help' returns a help message.
val: The value to set the option to.
Returns:
Confirmation of setting option opt to value val.
</details>
"""
if val:
return await self.send_command("ascset", parameters=f"{n},{opt},{val}")
else:
return await self.send_command("ascset", parameters=f"{n},{opt}")
async def lcd(self) -> dict:
"""Get a general all-in-one status summary of the miner.
<details>
<summary>Expand</summary>
Returns:
An all-in-one status summary of the miner.
</details>
"""
return await self.send_command("lcd")
async def lockstats(self) -> dict:
"""Write lockstats to STDERR.
<details>
<summary>Expand</summary>
Returns:
The result of writing the lock stats to STDERR.
</details>
"""
return await self.send_command("lockstats")

View File

@@ -14,45 +14,11 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic import settings from pyasic import settings
from pyasic.API.bmminer import BMMinerAPI
from pyasic.API.bosminer import BOSMinerAPI
from pyasic.API.btminer import BTMinerAPI
from pyasic.API.cgminer import CGMinerAPI
from pyasic.API.unknown import UnknownAPI
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.data import ( from pyasic.data import MinerData
BraiinsOSError,
InnosiliconError,
MinerData,
WhatsminerError,
X19Error,
)
from pyasic.errors import APIError, APIWarning from pyasic.errors import APIError, APIWarning
from pyasic.miners import get_miner from pyasic.miners import *
from pyasic.miners.base import AnyMiner
from pyasic.miners.miner_factory import MinerFactory, miner_factory
from pyasic.miners.miner_listener import MinerListener
from pyasic.network import MinerNetwork from pyasic.network import MinerNetwork
from pyasic.rpc import *
__all__ = [ from pyasic.ssh import *
"BMMinerAPI", from pyasic.web import *
"BOSMinerAPI",
"BTMinerAPI",
"CGMinerAPI",
"UnknownAPI",
"MinerConfig",
"MinerData",
"BraiinsOSError",
"InnosiliconError",
"WhatsminerError",
"X19Error",
"APIError",
"APIWarning",
"get_miner",
"AnyMiner",
"MinerFactory",
"miner_factory",
"MinerListener",
"MinerNetwork",
"settings",
]

View File

@@ -13,14 +13,14 @@
# 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 copy import deepcopy
from dataclasses import asdict, dataclass, field from dataclasses import asdict, dataclass, field
from pyasic.config.fans import FanModeConfig from pyasic.config.fans import FanModeConfig
from pyasic.config.mining import MiningModeConfig from pyasic.config.mining import MiningModeConfig
from pyasic.config.pools import PoolConfig from pyasic.config.pools import PoolConfig
from pyasic.config.power_scaling import PowerScalingConfig, PowerScalingShutdown from pyasic.config.power_scaling import PowerScalingConfig
from pyasic.config.temperature import TemperatureConfig from pyasic.config.temperature import TemperatureConfig
from pyasic.misc import merge_dicts
@dataclass @dataclass
@@ -93,30 +93,38 @@ class MinerConfig:
def as_bosminer(self, user_suffix: str = None) -> dict: def as_bosminer(self, user_suffix: str = None) -> dict:
return { return {
**merge(self.fan_mode.as_bosminer(), self.temperature.as_bosminer()), **merge_dicts(self.fan_mode.as_bosminer(), self.temperature.as_bosminer()),
**self.mining_mode.as_bosminer(), **self.mining_mode.as_bosminer(),
**self.pools.as_bosminer(user_suffix=user_suffix), **self.pools.as_bosminer(user_suffix=user_suffix),
**self.power_scaling.as_bosminer(), **self.power_scaling.as_bosminer(),
} }
def as_bos_grpc(self, user_suffix: str = None) -> dict: def as_boser(self, user_suffix: str = None) -> dict:
return { return {
**self.fan_mode.as_bos_grpc(), **self.fan_mode.as_boser(),
**self.temperature.as_bos_grpc(), **self.temperature.as_boser(),
**self.mining_mode.as_bos_grpc(), **self.mining_mode.as_boser(),
**self.pools.as_bos_grpc(user_suffix=user_suffix), **self.pools.as_boser(user_suffix=user_suffix),
**self.power_scaling.as_bos_grpc(), **self.power_scaling.as_boser(),
} }
def as_epic(self, user_suffix: str = None) -> dict: def as_epic(self, user_suffix: str = None) -> dict:
return { return {
**self.fan_mode.as_epic(), **merge_dicts(self.fan_mode.as_epic(), self.temperature.as_epic()),
**self.temperature.as_epic(),
**self.mining_mode.as_epic(), **self.mining_mode.as_epic(),
**self.pools.as_epic(user_suffix=user_suffix), **self.pools.as_epic(user_suffix=user_suffix),
**self.power_scaling.as_epic(), **self.power_scaling.as_epic(),
} }
def as_auradine(self, user_suffix: str = None) -> dict:
return {
**self.fan_mode.as_auradine(),
**self.temperature.as_auradine(),
**self.mining_mode.as_auradine(),
**self.pools.as_auradine(user_suffix=user_suffix),
**self.power_scaling.as_auradine(),
}
@classmethod @classmethod
def from_dict(cls, dict_conf: dict) -> "MinerConfig": def from_dict(cls, dict_conf: dict) -> "MinerConfig":
return cls( return cls(
@@ -161,13 +169,38 @@ class MinerConfig:
power_scaling=PowerScalingConfig.from_bosminer(toml_conf), power_scaling=PowerScalingConfig.from_bosminer(toml_conf),
) )
@classmethod
def from_boser(cls, grpc_miner_conf: dict) -> "MinerConfig":
return cls(
pools=PoolConfig.from_boser(grpc_miner_conf),
mining_mode=MiningModeConfig.from_boser(grpc_miner_conf),
fan_mode=FanModeConfig.from_boser(grpc_miner_conf),
temperature=TemperatureConfig.from_boser(grpc_miner_conf),
power_scaling=PowerScalingConfig.from_boser(grpc_miner_conf),
)
def merge(a: dict, b: dict) -> dict: @classmethod
result = deepcopy(a) def from_epic(cls, web_conf: dict) -> "MinerConfig":
for b_key, b_val in b.items(): return cls(
a_val = result.get(b_key) pools=PoolConfig.from_epic(web_conf),
if isinstance(a_val, dict) and isinstance(b_val, dict): fan_mode=FanModeConfig.from_epic(web_conf),
result[b_key] = merge(a_val, b_val) temperature=TemperatureConfig.from_epic(web_conf),
else: mining_mode=MiningModeConfig.from_epic(web_conf),
result[b_key] = deepcopy(b_val) )
return result
@classmethod
def from_vnish(cls, web_settings: dict) -> "MinerConfig":
return cls(
pools=PoolConfig.from_vnish(web_settings),
fan_mode=FanModeConfig.from_vnish(web_settings),
temperature=TemperatureConfig.from_vnish(web_settings),
mining_mode=MiningModeConfig.from_vnish(web_settings),
)
@classmethod
def from_auradine(cls, web_conf: dict) -> "MinerConfig":
return cls(
pools=PoolConfig.from_api(web_conf["pools"]),
fan_mode=FanModeConfig.from_auradine(web_conf["fan"]),
mining_mode=MiningModeConfig.from_auradine(web_conf["mode"]),
)

View File

@@ -13,14 +13,15 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import asdict, dataclass from dataclasses import asdict, dataclass
from enum import Enum from enum import Enum
from typing import Union
class MinerConfigOption(Enum): class MinerConfigOption(Enum):
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
return cls.default() return cls.default()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -44,12 +45,18 @@ class MinerConfigOption(Enum):
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
return self.value.as_bosminer() return self.value.as_bosminer()
def as_bos_grpc(self) -> dict: def as_boser(self) -> dict:
return self.value.as_bos_grpc() return self.value.as_boser()
def as_epic(self) -> dict: def as_epic(self) -> dict:
return self.value.as_epic() return self.value.as_epic()
def as_vnish(self) -> dict:
return self.value.as_vnish()
def as_auradine(self) -> dict:
return self.value.as_auradine()
def __call__(self, *args, **kwargs): def __call__(self, *args, **kwargs):
return self.value(*args, **kwargs) return self.value(*args, **kwargs)
@@ -61,10 +68,10 @@ class MinerConfigOption(Enum):
@dataclass @dataclass
class MinerConfigValue: class MinerConfigValue:
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
return cls() return cls()
def as_dict(self): def as_dict(self) -> dict:
return asdict(self) return asdict(self)
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
@@ -88,8 +95,14 @@ class MinerConfigValue:
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
return {} return {}
def as_bos_grpc(self) -> dict: def as_boser(self) -> dict:
return {} return {}
def as_epic(self) -> dict: def as_epic(self) -> dict:
return {} return {}
def as_vnish(self) -> dict:
return {}
def as_auradine(self) -> dict:
return {}

View File

@@ -13,8 +13,9 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Union
from pyasic.config.base import MinerConfigOption, MinerConfigValue from pyasic.config.base import MinerConfigOption, MinerConfigValue
@@ -22,10 +23,26 @@ from pyasic.config.base import MinerConfigOption, MinerConfigValue
@dataclass @dataclass
class FanModeNormal(MinerConfigValue): class FanModeNormal(MinerConfigValue):
mode: str = field(init=False, default="normal") mode: str = field(init=False, default="normal")
minimum_fans: int = 1
minimum_speed: int = 0
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "FanModeNormal": def from_dict(cls, dict_conf: dict | None) -> "FanModeNormal":
return cls() cls_conf = {}
if dict_conf.get("minimum_fans") is not None:
cls_conf["minimum_fans"] = dict_conf["minimum_fans"]
if dict_conf.get("minimum_speed") is not None:
cls_conf["minimum_speed"] = dict_conf["minimum_speed"]
return cls(**cls_conf)
@classmethod
def from_vnish(cls, web_cooling_settings: dict) -> "FanModeNormal":
cls_conf = {}
if web_cooling_settings.get("fan_min_count") is not None:
cls_conf["minimum_fans"] = web_cooling_settings["fan_min_count"]
if web_cooling_settings.get("fan_min_duty") is not None:
cls_conf["minimum_speed"] = web_cooling_settings["fan_min_duty"]
return cls(**cls_conf)
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"} return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"}
@@ -33,6 +50,17 @@ class FanModeNormal(MinerConfigValue):
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
return {"temp_control": {"mode": "auto"}} return {"temp_control": {"mode": "auto"}}
def as_epic(self) -> dict:
return {
"fans": {
"Auto": {
"Idle Speed": (
self.minimum_speed if not self.minimum_speed == 0 else 100
)
}
}
}
@dataclass @dataclass
class FanModeManual(MinerConfigValue): class FanModeManual(MinerConfigValue):
@@ -41,7 +69,7 @@ class FanModeManual(MinerConfigValue):
minimum_fans: int = 1 minimum_fans: int = 1
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "FanModeManual": def from_dict(cls, dict_conf: dict | None) -> "FanModeManual":
cls_conf = {} cls_conf = {}
if dict_conf.get("speed") is not None: if dict_conf.get("speed") is not None:
cls_conf["speed"] = dict_conf["speed"] cls_conf["speed"] = dict_conf["speed"]
@@ -58,8 +86,17 @@ class FanModeManual(MinerConfigValue):
cls_conf["speed"] = toml_fan_conf["speed"] cls_conf["speed"] = toml_fan_conf["speed"]
return cls(**cls_conf) return cls(**cls_conf)
@classmethod
def from_vnish(cls, web_cooling_settings: dict) -> "FanModeManual":
cls_conf = {}
if web_cooling_settings.get("fan_min_count") is not None:
cls_conf["minimum_fans"] = web_cooling_settings["fan_min_count"]
if web_cooling_settings["mode"].get("param") is not None:
cls_conf["speed"] = web_cooling_settings["mode"]["param"]
return cls(**cls_conf)
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwn": str(self.speed)} return {"bitmain-fan-ctrl": True, "bitmain-fan-pwm": str(self.speed)}
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
return { return {
@@ -67,21 +104,30 @@ class FanModeManual(MinerConfigValue):
"fan_control": {"min_fans": self.minimum_fans, "speed": self.speed}, "fan_control": {"min_fans": self.minimum_fans, "speed": self.speed},
} }
def as_auradine(self) -> dict:
return {"fan": {"percentage": self.speed}}
def as_epic(self) -> dict:
return {"fans": {"Manual": {"speed": self.speed}}}
@dataclass @dataclass
class FanModeImmersion(MinerConfigValue): class FanModeImmersion(MinerConfigValue):
mode: str = field(init=False, default="immersion") mode: str = field(init=False, default="immersion")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "FanModeImmersion": def from_dict(cls, dict_conf: dict | None) -> "FanModeImmersion":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwn": "0"} return {"bitmain-fan-ctrl": True, "bitmain-fan-pwm": "0"}
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
return {"temp_control": {"mode": "disabled"}} return {"temp_control": {"mode": "disabled"}}
def as_auradine(self) -> dict:
return {"fan": {"percentage": 0}}
class FanModeConfig(MinerConfigOption): class FanModeConfig(MinerConfigOption):
normal = FanModeNormal normal = FanModeNormal
@@ -93,7 +139,7 @@ class FanModeConfig(MinerConfigOption):
return cls.normal() return cls.normal()
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
@@ -101,21 +147,35 @@ class FanModeConfig(MinerConfigOption):
if mode is None: if mode is None:
return cls.default() return cls.default()
clsattr = getattr(cls, mode) cls_attr = getattr(cls, mode)
if clsattr is not None: if cls_attr is not None:
return clsattr().from_dict(dict_conf) return cls_attr().from_dict(dict_conf)
@classmethod @classmethod
def from_am_modern(cls, web_conf: dict): def from_am_modern(cls, web_conf: dict):
if web_conf.get("bitmain-fan-ctrl") is not None: if web_conf.get("bitmain-fan-ctrl") is not None:
fan_manual = web_conf["bitmain-fan-ctrl"] fan_manual = web_conf["bitmain-fan-ctrl"]
if fan_manual: if fan_manual:
return cls.manual(speed=web_conf["bitmain-fan-pwm"]) speed = int(web_conf["bitmain-fan-pwm"])
if speed == 0:
return cls.immersion()
return cls.manual(speed=speed)
else: else:
return cls.normal() return cls.normal()
else: else:
return cls.default() return cls.default()
@classmethod
def from_epic(cls, web_conf: dict):
try:
fan_mode = web_conf["Fans"]["Fan Mode"]
if fan_mode.get("Manual") is not None:
return cls.manual(speed=fan_mode.get("Manual"))
else:
return cls.normal()
except KeyError:
return cls.default()
@classmethod @classmethod
def from_bosminer(cls, toml_conf: dict): def from_bosminer(cls, toml_conf: dict):
if toml_conf.get("temp_control") is None: if toml_conf.get("temp_control") is None:
@@ -132,3 +192,47 @@ class FanModeConfig(MinerConfigOption):
return cls.manual() return cls.manual()
elif mode == "disabled": elif mode == "disabled":
return cls.immersion() return cls.immersion()
@classmethod
def from_vnish(cls, web_settings: dict):
try:
mode = web_settings["miner"]["cooling"]["mode"]["name"]
except LookupError:
return cls.default()
if mode == "auto":
return cls.normal().from_vnish(web_settings["miner"]["cooling"])
elif mode == "manual":
return cls.manual().from_vnish(web_settings["miner"]["cooling"])
elif mode == "immers":
return cls.immersion()
@classmethod
def from_boser(cls, grpc_miner_conf: dict):
try:
temperature_conf = grpc_miner_conf["temperature"]
except LookupError:
return cls.default()
keys = temperature_conf.keys()
if "auto" in keys:
if "minimumRequiredFans" in keys:
return cls.normal(temperature_conf["minimumRequiredFans"])
return cls.normal()
if "manual" in keys:
conf = {}
if "fanSpeedRatio" in temperature_conf["manual"].keys():
conf["speed"] = int(temperature_conf["manual"]["fanSpeedRatio"])
if "minimumRequiredFans" in keys:
conf["minimum_fans"] = int(temperature_conf["minimumRequiredFans"])
return cls.manual(**conf)
@classmethod
def from_auradine(cls, web_fan: dict):
try:
fan_data = web_fan["Fan"][0]
fan_1_max = fan_data["Max"]
fan_1_target = fan_data["Target"]
return cls.manual(speed=round((fan_1_target / fan_1_max) * 100))
except LookupError:
return cls.default()

View File

@@ -13,10 +13,22 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from dataclasses import dataclass, field from __future__ import annotations
from typing import Union
from dataclasses import dataclass, field
from pyasic import settings
from pyasic.config.base import MinerConfigOption, MinerConfigValue from pyasic.config.base import MinerConfigOption, MinerConfigValue
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
HashrateTargetMode,
PerformanceMode,
Power,
PowerTargetMode,
SaveAction,
SetPerformanceModeRequest,
TeraHashrate,
TunerPerformanceMode,
)
@dataclass @dataclass
@@ -24,72 +36,147 @@ class MiningModeNormal(MinerConfigValue):
mode: str = field(init=False, default="normal") mode: str = field(init=False, default="normal")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeNormal": def from_dict(cls, dict_conf: dict | None) -> "MiningModeNormal":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"miner-mode": "0"} if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_wm(self) -> dict: def as_wm(self) -> dict:
return {"mode": self.mode} return {"mode": self.mode}
def as_auradine(self) -> dict:
return {"mode": {"mode": self.mode}}
def as_epic(self) -> dict:
return {"ptune": {"enabled": False}}
def as_goldshell(self) -> dict:
return {"settings": {"level": 0}}
@dataclass @dataclass
class MiningModeSleep(MinerConfigValue): class MiningModeSleep(MinerConfigValue):
mode: str = field(init=False, default="sleep") mode: str = field(init=False, default="sleep")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeSleep": def from_dict(cls, dict_conf: dict | None) -> "MiningModeSleep":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"miner-mode": "1"} if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "1"}
return {"miner-mode": 1}
def as_wm(self) -> dict: def as_wm(self) -> dict:
return {"mode": self.mode} return {"mode": self.mode}
def as_auradine(self) -> dict:
return {"mode": {"sleep": "on"}}
def as_epic(self) -> dict:
return {"ptune": {"algo": "Sleep", "target": 0}}
def as_goldshell(self) -> dict:
return {"settings": {"level": 3}}
@dataclass @dataclass
class MiningModeLPM(MinerConfigValue): class MiningModeLPM(MinerConfigValue):
mode: str = field(init=False, default="low") mode: str = field(init=False, default="low")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeLPM": def from_dict(cls, dict_conf: dict | None) -> "MiningModeLPM":
return cls() return cls()
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"miner-mode": "3"} if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "3"}
return {"miner-mode": 3}
def as_wm(self) -> dict: def as_wm(self) -> dict:
return {"mode": self.mode} return {"mode": self.mode}
def as_auradine(self) -> dict:
return {"mode": {"mode": "eco"}}
def as_goldshell(self) -> dict:
return {"settings": {"level": 1}}
@dataclass @dataclass
class MiningModeHPM(MinerConfigValue): class MiningModeHPM(MinerConfigValue):
mode: str = field(init=False, default="high") mode: str = field(init=False, default="high")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeHPM": def from_dict(cls, dict_conf: dict | None) -> "MiningModeHPM":
return cls() return cls()
def as_am_modern(self): def as_am_modern(self) -> dict:
return {"miner-mode": "0"} if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_wm(self) -> dict: def as_wm(self) -> dict:
return {"mode": self.mode} return {"mode": self.mode}
def as_auradine(self) -> dict:
return {"mode": {"mode": "turbo"}}
class StandardTuneAlgo(MinerConfigValue):
mode: str = field(init=False, default="standard")
def as_epic(self) -> str:
return VOptAlgo().as_epic()
class VOptAlgo(MinerConfigValue):
mode: str = field(init=False, default="standard")
def as_epic(self) -> str:
return "VoltageOptimizer"
class ChipTuneAlgo(MinerConfigValue):
mode: str = field(init=False, default="standard")
def as_epic(self) -> str:
return "ChipTune"
class TunerAlgo(MinerConfigOption):
standard = StandardTuneAlgo
voltage_optimizer = VOptAlgo
chip_tune = ChipTuneAlgo
@classmethod
def default(cls):
return cls.standard()
@dataclass @dataclass
class MiningModePowerTune(MinerConfigValue): class MiningModePowerTune(MinerConfigValue):
mode: str = field(init=False, default="power_tuning") mode: str = field(init=False, default="power_tuning")
power: int = None power: int = None
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModePowerTune": def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
return cls(dict_conf.get("power")) cls_conf = {}
if dict_conf.get("power"):
cls_conf["power"] = dict_conf["power"]
if dict_conf.get("algo"):
cls_conf["algo"] = dict_conf["algo"]
return cls(**cls_conf)
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"miner-mode": "0"} if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_wm(self) -> dict: def as_wm(self) -> dict:
if self.power is not None: if self.power is not None:
@@ -99,18 +186,60 @@ class MiningModePowerTune(MinerConfigValue):
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
return {"autotuning": {"enabled": True, "psu_power_limit": self.power}} return {"autotuning": {"enabled": True, "psu_power_limit": self.power}}
def as_boser(self) -> dict:
return {
"set_performance_mode": SetPerformanceModeRequest(
save_action=SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
mode=PerformanceMode(
tuner_mode=TunerPerformanceMode(
power_target=PowerTargetMode(
power_target=Power(watt=self.power)
)
)
),
),
}
def as_auradine(self) -> dict:
return {"mode": {"mode": "custom", "tune": "power", "power": self.power}}
@dataclass @dataclass
class MiningModeHashrateTune(MinerConfigValue): class MiningModeHashrateTune(MinerConfigValue):
mode: str = field(init=False, default="hashrate_tuning") mode: str = field(init=False, default="hashrate_tuning")
hashrate: int = None hashrate: int = None
algo: TunerAlgo = field(default_factory=TunerAlgo.default)
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeHashrateTune": def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
return cls(dict_conf.get("hashrate")) return cls(dict_conf.get("hashrate"))
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"miner-mode": "0"} if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_boser(self) -> dict:
return {
"set_performance_mode": SetPerformanceModeRequest(
save_action=SaveAction.SAVE_ACTION_SAVE_AND_APPLY,
mode=PerformanceMode(
tuner_mode=TunerPerformanceMode(
hashrate_target=HashrateTargetMode(
hashrate_target=TeraHashrate(
terahash_per_second=self.hashrate
)
)
)
),
)
}
def as_auradine(self) -> dict:
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
def as_epic(self) -> dict:
return {"ptune": {"algo": self.algo.as_epic(), "target": self.hashrate}}
@dataclass @dataclass
@@ -119,11 +248,13 @@ class ManualBoardSettings(MinerConfigValue):
volt: float volt: float
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "ManualBoardSettings": def from_dict(cls, dict_conf: dict | None) -> "ManualBoardSettings":
return cls(freq=dict_conf["freq"], volt=dict_conf["volt"]) return cls(freq=dict_conf["freq"], volt=dict_conf["volt"])
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"miner-mode": "0"} if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
@dataclass @dataclass
@@ -135,7 +266,7 @@ class MiningModeManual(MinerConfigValue):
boards: dict[int, ManualBoardSettings] = field(default_factory=dict) boards: dict[int, ManualBoardSettings] = field(default_factory=dict)
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "MiningModeManual": def from_dict(cls, dict_conf: dict | None) -> "MiningModeManual":
return cls( return cls(
global_freq=dict_conf["global_freq"], global_freq=dict_conf["global_freq"],
global_volt=dict_conf["global_volt"], global_volt=dict_conf["global_volt"],
@@ -143,7 +274,23 @@ class MiningModeManual(MinerConfigValue):
) )
def as_am_modern(self) -> dict: def as_am_modern(self) -> dict:
return {"miner-mode": "0"} if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
@classmethod
def from_vnish(cls, web_overclock_settings: dict) -> "MiningModeManual":
# will raise KeyError if it cant find the settings, values cannot be empty
voltage = web_overclock_settings["globals"]["volt"]
freq = web_overclock_settings["globals"]["freq"]
boards = {
idx: ManualBoardSettings(
freq=board["freq"],
volt=voltage if not board["freq"] == 0 else 0,
)
for idx, board in enumerate(web_overclock_settings["chains"])
}
return cls(global_freq=freq, global_volt=voltage, boards=boards)
class MiningModeConfig(MinerConfigOption): class MiningModeConfig(MinerConfigOption):
@@ -160,7 +307,7 @@ class MiningModeConfig(MinerConfigOption):
return cls.normal() return cls.normal()
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
@@ -168,9 +315,9 @@ class MiningModeConfig(MinerConfigOption):
if mode is None: if mode is None:
return cls.default() return cls.default()
clsattr = getattr(cls, mode) cls_attr = getattr(cls, mode)
if clsattr is not None: if cls_attr is not None:
return clsattr().from_dict(dict_conf) return cls_attr().from_dict(dict_conf)
@classmethod @classmethod
def from_am_modern(cls, web_conf: dict): def from_am_modern(cls, web_conf: dict):
@@ -186,6 +333,27 @@ class MiningModeConfig(MinerConfigOption):
return cls.low() return cls.low()
return cls.default() return cls.default()
@classmethod
def from_epic(cls, web_conf: dict):
try:
tuner_running = web_conf["PerpetualTune"]["Running"]
if tuner_running:
algo_info = web_conf["PerpetualTune"]["Algorithm"]
if algo_info.get("VoltageOptimizer") is not None:
return cls.hashrate_tuning(
hashrate=algo_info["VoltageOptimizer"]["Target"],
algo=TunerAlgo.voltage_optimizer,
)
else:
return cls.hashrate_tuning(
hashrate=algo_info["ChipTune"]["Target"],
algo=TunerAlgo.chip_tune,
)
else:
return cls.normal()
except KeyError:
return cls.default()
@classmethod @classmethod
def from_bosminer(cls, toml_conf: dict): def from_bosminer(cls, toml_conf: dict):
if toml_conf.get("autotuning") is None: if toml_conf.get("autotuning") is None:
@@ -211,3 +379,64 @@ class MiningModeConfig(MinerConfigOption):
if autotuning_conf.get("hashrate_target") is not None: if autotuning_conf.get("hashrate_target") is not None:
return cls.hashrate_tuning(autotuning_conf["hashrate_target"]) return cls.hashrate_tuning(autotuning_conf["hashrate_target"])
return cls.hashrate_tuning() return cls.hashrate_tuning()
@classmethod
def from_vnish(cls, web_settings: dict):
try:
mode_settings = web_settings["miner"]["overclock"]
except KeyError:
return cls.default()
if mode_settings["preset"] == "disabled":
return MiningModeManual.from_vnish(mode_settings)
else:
return cls.power_tuning(int(mode_settings["preset"]))
@classmethod
def from_boser(cls, grpc_miner_conf: dict):
try:
tuner_conf = grpc_miner_conf["tuner"]
if not tuner_conf.get("enabled", False):
return cls.default()
except LookupError:
return cls.default()
if tuner_conf.get("tunerMode") is not None:
if tuner_conf["tunerMode"] == 1:
if tuner_conf.get("powerTarget") is not None:
return cls.power_tuning(tuner_conf["powerTarget"]["watt"])
return cls.power_tuning()
if tuner_conf["tunerMode"] == 2:
if tuner_conf.get("hashrateTarget") is not None:
return cls.hashrate_tuning(
int(tuner_conf["hashrateTarget"]["terahashPerSecond"])
)
return cls.hashrate_tuning()
if tuner_conf.get("powerTarget") is not None:
return cls.power_tuning(tuner_conf["powerTarget"]["watt"])
if tuner_conf.get("hashrateTarget") is not None:
return cls.hashrate_tuning(
int(tuner_conf["hashrateTarget"]["terahashPerSecond"])
)
@classmethod
def from_auradine(cls, web_mode: dict):
try:
mode_data = web_mode["Mode"][0]
if mode_data.get("Sleep") == "on":
return cls.sleep()
if mode_data.get("Mode") == "normal":
return cls.normal()
if mode_data.get("Mode") == "eco":
return cls.low()
if mode_data.get("Mode") == "turbo":
return cls.high()
if mode_data.get("Ths") is not None:
return cls.hashrate_tuning(mode_data["Ths"])
if mode_data.get("Power") is not None:
return cls.power_tuning(mode_data["Power"])
except LookupError:
return cls.default()

View File

@@ -13,10 +13,12 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
import random import random
import string import string
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Union from typing import List
from pyasic.config.base import MinerConfigValue from pyasic.config.base import MinerConfigValue
@@ -27,7 +29,7 @@ class Pool(MinerConfigValue):
user: str user: str
password: str password: str
def as_am_modern(self, user_suffix: str = None): def as_am_modern(self, user_suffix: str = None) -> dict:
if user_suffix is not None: if user_suffix is not None:
return { return {
"url": self.url, "url": self.url,
@@ -36,7 +38,7 @@ class Pool(MinerConfigValue):
} }
return {"url": self.url, "user": self.user, "pass": self.password} return {"url": self.url, "user": self.user, "pass": self.password}
def as_wm(self, idx: int, user_suffix: str = None): def as_wm(self, idx: int = 1, user_suffix: str = None) -> dict:
if user_suffix is not None: if user_suffix is not None:
return { return {
f"pool_{idx}": self.url, f"pool_{idx}": self.url,
@@ -49,7 +51,7 @@ class Pool(MinerConfigValue):
f"passwd_{idx}": self.password, f"passwd_{idx}": self.password,
} }
def as_am_old(self, idx: int, user_suffix: str = None): def as_am_old(self, idx: int = 1, user_suffix: str = None) -> dict:
if user_suffix is not None: if user_suffix is not None:
return { return {
f"_ant_pool{idx}url": self.url, f"_ant_pool{idx}url": self.url,
@@ -62,7 +64,7 @@ class Pool(MinerConfigValue):
f"_ant_pool{idx}pw": self.password, f"_ant_pool{idx}pw": self.password,
} }
def as_goldshell(self, user_suffix: str = None): def as_goldshell(self, user_suffix: str = None) -> dict:
if user_suffix is not None: if user_suffix is not None:
return { return {
"url": self.url, "url": self.url,
@@ -71,12 +73,12 @@ class Pool(MinerConfigValue):
} }
return {"url": self.url, "user": self.user, "pass": self.password} return {"url": self.url, "user": self.user, "pass": self.password}
def as_avalon(self, user_suffix: str = None): def as_avalon(self, user_suffix: str = None) -> str:
if user_suffix is not None: if user_suffix is not None:
return ",".join([self.url, f"{self.user}{user_suffix}", self.password]) return ",".join([self.url, f"{self.user}{user_suffix}", self.password])
return ",".join([self.url, self.user, self.password]) return ",".join([self.url, self.user, self.password])
def as_inno(self, idx: int, user_suffix: str = None): def as_inno(self, idx: int = 1, user_suffix: str = None) -> dict:
if user_suffix is not None: if user_suffix is not None:
return { return {
f"Pool{idx}": self.url, f"Pool{idx}": self.url,
@@ -89,7 +91,7 @@ class Pool(MinerConfigValue):
f"Password{idx}": self.password, f"Password{idx}": self.password,
} }
def as_bosminer(self, user_suffix: str = None): def as_bosminer(self, user_suffix: str = None) -> dict:
if user_suffix is not None: if user_suffix is not None:
return { return {
"url": self.url, "url": self.url,
@@ -98,8 +100,26 @@ class Pool(MinerConfigValue):
} }
return {"url": self.url, "user": self.user, "password": self.password} return {"url": self.url, "user": self.user, "password": self.password}
def as_auradine(self, user_suffix: str = None) -> dict:
if user_suffix is not None:
return {
"url": self.url,
"user": f"{self.user}{user_suffix}",
"pass": self.password,
}
return {"url": self.url, "user": self.user, "pass": self.password}
def as_epic(self, user_suffix: str = None):
if user_suffix is not None:
return {
"pool": self.url,
"login": f"{self.user}{user_suffix}",
"password": self.password,
}
return {"pool": self.url, "login": self.user, "password": self.password}
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "Pool": def from_dict(cls, dict_conf: dict | None) -> "Pool":
return cls( return cls(
url=dict_conf["url"], user=dict_conf["user"], password=dict_conf["password"] url=dict_conf["url"], user=dict_conf["user"], password=dict_conf["password"]
) )
@@ -108,6 +128,12 @@ class Pool(MinerConfigValue):
def from_api(cls, api_pool: dict) -> "Pool": def from_api(cls, api_pool: dict) -> "Pool":
return cls(url=api_pool["URL"], user=api_pool["User"], password="x") return cls(url=api_pool["URL"], user=api_pool["User"], password="x")
@classmethod
def from_epic(cls, api_pool: dict) -> "Pool":
return cls(
url=api_pool["pool"], user=api_pool["login"], password=api_pool["password"]
)
@classmethod @classmethod
def from_am_modern(cls, web_pool: dict) -> "Pool": def from_am_modern(cls, web_pool: dict) -> "Pool":
return cls( return cls(
@@ -135,6 +161,22 @@ class Pool(MinerConfigValue):
password=toml_pool_conf["password"], password=toml_pool_conf["password"],
) )
@classmethod
def from_vnish(cls, web_pool: dict) -> "Pool":
return cls(
url=web_pool["url"],
user=web_pool["user"],
password=web_pool["pass"],
)
@classmethod
def from_boser(cls, grpc_pool: dict) -> "Pool":
return cls(
url=grpc_pool["url"],
user=grpc_pool["user"],
password=grpc_pool["password"],
)
@dataclass @dataclass
class PoolGroup(MinerConfigValue): class PoolGroup(MinerConfigValue):
@@ -188,7 +230,7 @@ class PoolGroup(MinerConfigValue):
def as_goldshell(self, user_suffix: str = None) -> list: def as_goldshell(self, user_suffix: str = None) -> list:
return [pool.as_goldshell(user_suffix) for pool in self.pools] return [pool.as_goldshell(user_suffix) for pool in self.pools]
def as_avalon(self, user_suffix: str = None) -> dict: def as_avalon(self, user_suffix: str = None) -> str:
if len(self.pools) > 0: if len(self.pools) > 0:
return self.pools[0].as_avalon(user_suffix=user_suffix) return self.pools[0].as_avalon(user_suffix=user_suffix)
return Pool("", "", "").as_avalon() return Pool("", "", "").as_avalon()
@@ -219,8 +261,14 @@ class PoolGroup(MinerConfigValue):
return conf return conf
return {"name": "Group", "pool": []} return {"name": "Group", "pool": []}
def as_auradine(self, user_suffix: str = None) -> list:
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
def as_epic(self, user_suffix: str = None) -> dict:
return [p.as_epic(user_suffix=user_suffix) for p in self.pools]
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PoolGroup": def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
cls_conf = {} cls_conf = {}
if dict_conf.get("quota") is not None: if dict_conf.get("quota") is not None:
@@ -237,6 +285,13 @@ class PoolGroup(MinerConfigValue):
pools.append(Pool.from_api(pool)) pools.append(Pool.from_api(pool))
return cls(pools=pools) return cls(pools=pools)
@classmethod
def from_epic(cls, api_pool_list: list) -> "PoolGroup":
pools = []
for pool in api_pool_list:
pools.append(Pool.from_epic(pool))
return cls(pools=pools)
@classmethod @classmethod
def from_am_modern(cls, web_pool_list: list) -> "PoolGroup": def from_am_modern(cls, web_pool_list: list) -> "PoolGroup":
pools = [] pools = []
@@ -262,24 +317,43 @@ class PoolGroup(MinerConfigValue):
) )
return cls() return cls()
@classmethod
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
return cls([Pool.from_vnish(p) for p in web_settings_pools])
@classmethod
def from_boser(cls, grpc_pool_group: dict) -> "PoolGroup":
try:
return cls(
pools=[Pool.from_boser(p) for p in grpc_pool_group["pools"]],
name=grpc_pool_group["name"],
quota=(
grpc_pool_group["quota"]["value"]
if grpc_pool_group.get("quota") is not None
else 1
),
)
except LookupError:
return cls()
@dataclass @dataclass
class PoolConfig(MinerConfigValue): class PoolConfig(MinerConfigValue):
groups: list[PoolGroup] = field(default_factory=list) groups: List[PoolGroup] = field(default_factory=list)
@classmethod @classmethod
def default(cls) -> "PoolConfig": def default(cls) -> "PoolConfig":
return cls() return cls()
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PoolConfig": def from_dict(cls, dict_conf: dict | None) -> "PoolConfig":
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]]) return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]])
@classmethod @classmethod
def simple(cls, pools: list[Union[Pool, dict[str, str]]]) -> "PoolConfig": def simple(cls, pools: list[Pool | dict[str, str]]) -> "PoolConfig":
group_pools = [] group_pools = []
for pool in pools: for pool in pools:
if isinstance(pool, dict): if isinstance(pool, dict):
@@ -324,16 +398,50 @@ class PoolConfig(MinerConfigValue):
} }
return {"group": [PoolGroup().as_bosminer()]} return {"group": [PoolGroup().as_bosminer()]}
def as_bos_grpc(self, user_suffix: str = None) -> dict: def as_boser(self, user_suffix: str = None) -> dict:
return {} return {}
def as_auradine(self, user_suffix: str = None) -> dict:
if len(self.groups) > 0:
return {
"updatepools": {
"pools": self.groups[0].as_auradine(user_suffix=user_suffix)
}
}
return {"updatepools": {"pools": PoolGroup().as_auradine()}}
def as_epic(self, user_suffix: str = None) -> dict:
if len(self.groups) > 0:
return {
"pools": {
"coin": "Btc",
"stratum_configs": self.groups[0].as_epic(user_suffix=user_suffix),
"unique_id": False,
}
}
return {
"pools": {
"coin": "Btc",
"stratum_configs": [PoolGroup().as_epic()],
"unique_id": False,
}
}
@classmethod @classmethod
def from_api(cls, api_pools: dict) -> "PoolConfig": def from_api(cls, api_pools: dict) -> "PoolConfig":
pool_data = api_pools["POOLS"] try:
pool_data = api_pools["POOLS"]
except KeyError:
return PoolConfig.default()
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"])) pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
return cls([PoolGroup.from_api(pool_data)]) return cls([PoolGroup.from_api(pool_data)])
@classmethod
def from_epic(cls, web_conf: dict) -> "PoolConfig":
pool_data = web_conf["StratumConfigs"]
return cls([PoolGroup.from_epic(pool_data)])
@classmethod @classmethod
def from_am_modern(cls, web_conf: dict) -> "PoolConfig": def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
pool_data = web_conf["pools"] pool_data = web_conf["pools"]
@@ -354,3 +462,22 @@ class PoolConfig(MinerConfigValue):
return cls() return cls()
return cls([PoolGroup.from_bosminer(g) for g in toml_conf["group"]]) return cls([PoolGroup.from_bosminer(g) for g in toml_conf["group"]])
@classmethod
def from_vnish(cls, web_settings: dict) -> "PoolConfig":
try:
return cls([PoolGroup.from_vnish(web_settings["miner"]["pools"])])
except LookupError:
return cls()
@classmethod
def from_boser(cls, grpc_miner_conf: dict) -> "PoolConfig":
try:
return cls(
groups=[
PoolGroup.from_boser(group)
for group in grpc_miner_conf["poolGroups"]
]
)
except LookupError:
return cls()

View File

@@ -13,11 +13,17 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Union
from pyasic.config.base import MinerConfigOption, MinerConfigValue from pyasic.config.base import MinerConfigOption, MinerConfigValue
from pyasic.web.bosminer.proto.braiins.bos.v1 import DpsPowerTarget, DpsTarget, Hours from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
DpsPowerTarget,
DpsTarget,
Power,
SetDpsRequest,
)
@dataclass @dataclass
@@ -26,7 +32,7 @@ class PowerScalingShutdownEnabled(MinerConfigValue):
duration: int = None duration: int = None
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PowerScalingShutdownEnabled": def from_dict(cls, dict_conf: dict | None) -> "PowerScalingShutdownEnabled":
return cls(duration=dict_conf.get("duration")) return cls(duration=dict_conf.get("duration"))
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
@@ -37,13 +43,8 @@ class PowerScalingShutdownEnabled(MinerConfigValue):
return cfg return cfg
def as_bos_grpc(self) -> dict: def as_boser(self) -> dict:
cfg = {"enable_shutdown ": True} return {"enable_shutdown": True, "shutdown_duration": self.duration}
if self.duration is not None:
cfg["shutdown_duration"] = Hours(self.duration)
return cfg
@dataclass @dataclass
@@ -51,13 +52,13 @@ class PowerScalingShutdownDisabled(MinerConfigValue):
mode: str = field(init=False, default="disabled") mode: str = field(init=False, default="disabled")
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PowerScalingShutdownDisabled": def from_dict(cls, dict_conf: dict | None) -> "PowerScalingShutdownDisabled":
return cls() return cls()
def as_bosminer(self) -> dict: def as_bosminer(self) -> dict:
return {"shutdown_enabled": False} return {"shutdown_enabled": False}
def as_bos_grpc(self) -> dict: def as_boser(self) -> dict:
return {"enable_shutdown ": False} return {"enable_shutdown ": False}
@@ -66,7 +67,7 @@ class PowerScalingShutdown(MinerConfigOption):
disabled = PowerScalingShutdownDisabled disabled = PowerScalingShutdownDisabled
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
@@ -88,15 +89,26 @@ class PowerScalingShutdown(MinerConfigOption):
return cls.disabled() return cls.disabled()
return None return None
@classmethod
def from_boser(cls, power_scaling_conf: dict):
sd_enabled = power_scaling_conf.get("shutdownEnabled")
if sd_enabled is not None:
if sd_enabled:
try:
return cls.enabled(power_scaling_conf["shutdownDuration"]["hours"])
except KeyError:
return cls.enabled()
else:
return cls.disabled()
return None
@dataclass @dataclass
class PowerScalingEnabled(MinerConfigValue): class PowerScalingEnabled(MinerConfigValue):
mode: str = field(init=False, default="enabled") mode: str = field(init=False, default="enabled")
power_step: int = None power_step: int = None
minimum_power: int = None minimum_power: int = None
shutdown_enabled: Union[ shutdown_enabled: PowerScalingShutdownEnabled | PowerScalingShutdownDisabled = None
PowerScalingShutdownEnabled, PowerScalingShutdownDisabled
] = None
@classmethod @classmethod
def from_bosminer(cls, power_scaling_conf: dict) -> "PowerScalingEnabled": def from_bosminer(cls, power_scaling_conf: dict) -> "PowerScalingEnabled":
@@ -109,7 +121,7 @@ class PowerScalingEnabled(MinerConfigValue):
) )
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "PowerScalingEnabled": def from_dict(cls, dict_conf: dict | None) -> "PowerScalingEnabled":
cls_conf = { cls_conf = {
"power_step": dict_conf.get("power_step"), "power_step": dict_conf.get("power_step"),
"minimum_power": dict_conf.get("minimum_power"), "minimum_power": dict_conf.get("minimum_power"),
@@ -133,20 +145,19 @@ class PowerScalingEnabled(MinerConfigValue):
return {"power_scaling": cfg} return {"power_scaling": cfg}
def as_bos_grpc(self) -> dict: def as_boser(self) -> dict:
cfg = {"enable": True} return {
target_conf = {} "set_dps": SetDpsRequest(
if self.power_step is not None: enable=True,
target_conf["power_step"] = self.power_step **self.shutdown_enabled.as_boser(),
if self.minimum_power is not None: target=DpsTarget(
target_conf["min_power_target"] = self.minimum_power power_target=DpsPowerTarget(
power_step=Power(self.power_step),
cfg["target"] = DpsTarget(power_target=DpsPowerTarget(**target_conf)) min_power_target=Power(self.minimum_power),
)
if self.shutdown_enabled is not None: ),
cfg = {**cfg, **self.shutdown_enabled.as_bos_grpc()} ),
}
return {"dps": cfg}
@dataclass @dataclass
@@ -163,7 +174,7 @@ class PowerScalingConfig(MinerConfigOption):
return cls.disabled() return cls.disabled()
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]): def from_dict(cls, dict_conf: dict | None):
if dict_conf is None: if dict_conf is None:
return cls.default() return cls.default()
@@ -187,3 +198,20 @@ class PowerScalingConfig(MinerConfigOption):
return cls.disabled() return cls.disabled()
return cls.default() return cls.default()
@classmethod
def from_boser(cls, grpc_miner_conf: dict):
try:
dps_conf = grpc_miner_conf["dps"]
if not dps_conf.get("enabled", False):
return cls.disabled()
except LookupError:
return cls.default()
conf = {"shutdown_enabled": PowerScalingShutdown.from_boser(dps_conf)}
if dps_conf.get("minPowerTarget") is not None:
conf["minimum_power"] = dps_conf["minPowerTarget"]["watt"]
if dps_conf.get("powerStep") is not None:
conf["power_step"] = dps_conf["powerStep"]["watt"]
return cls.enabled(**conf)

View File

@@ -13,8 +13,9 @@
# See the License for the specific language governing permissions and - # See the License for the specific language governing permissions and -
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from typing import Union
from pyasic.config.base import MinerConfigValue from pyasic.config.base import MinerConfigValue
@@ -39,8 +40,18 @@ class TemperatureConfig(MinerConfigValue):
temp_cfg["dangerous_temp"] = self.danger temp_cfg["dangerous_temp"] = self.danger
return {"temp_control": temp_cfg} return {"temp_control": temp_cfg}
def as_epic(self) -> dict:
temps_config = {"temps": {}, "fans": {"Auto": {}}}
if self.target is not None:
temps_config["fans"]["Auto"]["Target Temperature"] = self.target
else:
temps_config["fans"]["Auto"]["Target Temperature"] = 60
if self.danger is not None:
temps_config["temps"]["shutdown"] = self.danger
return temps_config
@classmethod @classmethod
def from_dict(cls, dict_conf: Union[dict, None]) -> "TemperatureConfig": def from_dict(cls, dict_conf: dict | None) -> "TemperatureConfig":
return cls( return cls(
target=dict_conf.get("target"), target=dict_conf.get("target"),
hot=dict_conf.get("hot"), hot=dict_conf.get("hot"),
@@ -56,3 +67,57 @@ class TemperatureConfig(MinerConfigValue):
hot=temp_control.get("hot_temp"), hot=temp_control.get("hot_temp"),
danger=temp_control.get("dangerous_temp"), danger=temp_control.get("dangerous_temp"),
) )
@classmethod
def from_epic(cls, web_conf: dict) -> "TemperatureConfig":
try:
dangerous_temp = web_conf["Misc"]["Shutdown Temp"]
except KeyError:
dangerous_temp = None
# Need to do this in two blocks to avoid KeyError if one is missing
try:
target_temp = web_conf["Fans"]["Fan Mode"]["Auto"]["Target Temperature"]
except KeyError:
target_temp = None
return cls(target=target_temp, danger=dangerous_temp)
@classmethod
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":
try:
if web_settings["miner"]["cooling"]["mode"]["name"] == "auto":
return cls(target=web_settings["miner"]["cooling"]["mode"]["param"])
except KeyError:
pass
return cls()
@classmethod
def from_boser(cls, grpc_miner_conf: dict) -> "TemperatureConfig":
try:
temperature_conf = grpc_miner_conf["temperature"]
except KeyError:
return cls.default()
root_key = None
for key in ["auto", "manual", "disabled"]:
if key in temperature_conf.keys():
root_key = key
break
if root_key is None:
return cls.default()
conf = {}
keys = temperature_conf[root_key].keys()
if "targetTemperature" in keys:
conf["target"] = int(
temperature_conf[root_key]["targetTemperature"]["degreeC"]
)
if "hotTemperature" in keys:
conf["hot"] = int(temperature_conf[root_key]["hotTemperature"]["degreeC"])
if "dangerousTemperature" in keys:
conf["danger"] = int(
temperature_conf[root_key]["dangerousTemperature"]["degreeC"]
)
return cls(**conf)
return cls.default()

View File

@@ -16,7 +16,6 @@
import copy import copy
import json import json
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
@@ -25,71 +24,9 @@ from typing import Any, List, Union
from pyasic.config import MinerConfig from pyasic.config import MinerConfig
from pyasic.config.mining import MiningModePowerTune from pyasic.config.mining import MiningModePowerTune
from .boards import HashBoard
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
from .fans import Fan
@dataclass
class HashBoard:
"""A Dataclass to standardize hashboard data.
Attributes:
slot: The slot of the board as an int.
hashrate: The hashrate of the board in TH/s as a float.
temp: The temperature of the PCB as an int.
chip_temp: The temperature of the chips as an int.
chips: The chip count of the board as an int.
expected_chips: The expected chip count of the board as an int.
missing: Whether the board is returned from the miners data as a bool.
"""
slot: int = 0
hashrate: float = None
temp: int = None
chip_temp: int = None
chips: int = None
expected_chips: int = None
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
class Fan:
"""A Dataclass to standardize fan data.
Attributes:
speed: The speed of the fan.
"""
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
@@ -109,7 +46,7 @@ class MinerData:
hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically. hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically.
_hashrate: Backup for hashrate found via API instead of hashboards. _hashrate: Backup for hashrate found via API instead of hashboards.
expected_hashrate: The factory nominal hashrate of the miner in TH/s as a float. expected_hashrate: The factory nominal hashrate of the miner in TH/s as a float.
hashboards: A list of hashboards on the miner with their statistics. hashboards: A list of [`HashBoard`][pyasic.data.HashBoard]s on the miner with their statistics.
temperature_avg: The average temperature across the boards. Calculated automatically. temperature_avg: The average temperature across the boards. Calculated automatically.
env_temp: The environment temps as a float. env_temp: The environment temps as a float.
wattage: Current power draw of the miner as an int. wattage: Current power draw of the miner as an int.
@@ -122,11 +59,7 @@ class MinerData:
percent_expected_hashrate: The percent of total hashrate out of the expected hashrate. Calculated automatically. percent_expected_hashrate: The percent of total hashrate out of the expected hashrate. Calculated automatically.
percent_expected_wattage: The percent of total wattage out of the expected wattage. Calculated automatically. percent_expected_wattage: The percent of total wattage out of the expected wattage. Calculated automatically.
nominal: Whether the number of chips in the miner is nominal. Calculated automatically. nominal: Whether the number of chips in the miner is nominal. Calculated automatically.
pool_split: The pool split as a str. config: The parsed config of the miner, using [`MinerConfig`][pyasic.config.MinerConfig].
pool_1_url: The first pool url on the miner as a str.
pool_1_user: The first pool user 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.
errors: A list of errors on the miner. errors: A list of errors on the miner.
fault_light: Whether the fault light is on as a boolean. fault_light: Whether the fault light is on as a boolean.
efficiency: Efficiency of the miner in J/TH (Watts per TH/s). Calculated automatically. efficiency: Efficiency of the miner in J/TH (Watts per TH/s). Calculated automatically.
@@ -161,9 +94,7 @@ class MinerData:
percent_expected_wattage: float = field(init=False) percent_expected_wattage: float = field(init=False)
nominal: bool = field(init=False) nominal: bool = field(init=False)
config: MinerConfig = None config: MinerConfig = None
errors: List[ errors: List[Union[WhatsminerError, BraiinsOSError, X19Error, InnosiliconError]] = field(default_factory=list)
Union[WhatsminerError, BraiinsOSError, X19Error, InnosiliconError]
] = 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 is_mining: bool = True
@@ -353,7 +284,6 @@ class MinerData:
pass pass
def asdict(self) -> dict: def asdict(self) -> dict:
logging.debug(f"MinerData - (To Dict) - Dumping Dict data")
return asdict(self, dict_factory=self.dict_factory) return asdict(self, dict_factory=self.dict_factory)
def as_dict(self) -> dict: def as_dict(self) -> dict:
@@ -370,7 +300,6 @@ class MinerData:
Returns: Returns:
A JSON version of this class. A JSON version of this class.
""" """
logging.debug(f"MinerData - (To JSON) - Dumping JSON data")
data = self.asdict() data = self.asdict()
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple()))) data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
return json.dumps(data) return json.dumps(data)
@@ -381,7 +310,6 @@ class MinerData:
Returns: Returns:
A CSV version of this class with no headers. A CSV version of this class with no headers.
""" """
logging.debug(f"MinerData - (To CSV) - Dumping CSV data")
data = self.asdict() data = self.asdict()
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple()))) data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
errs = [] errs = []
@@ -400,7 +328,6 @@ class MinerData:
Returns: Returns:
A influxdb line protocol version of this class. A influxdb line protocol version of this class.
""" """
logging.debug(f"MinerData - (To InfluxDB) - Dumping InfluxDB data")
tag_data = [measurement_name] tag_data = [measurement_name]
field_data = [] field_data = []

View File

@@ -14,39 +14,45 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import warnings from dataclasses import dataclass
from typing import Any
from pyasic.miners.makes import WhatsMiner
class M33SPlusVG20(WhatsMiner): # noqa - ignore ABC method implementation @dataclass
def __init__(self, ip: str, api_ver: str = "0.0.0"): class HashBoard:
super().__init__(ip, api_ver) """A Dataclass to standardize hashboard data.
self.ip = ip
self.model = "M33S+ VG20"
self.expected_hashboards = 4
self.expected_chips = 112
self.fan_count = 0
Attributes:
slot: The slot of the board as an int.
hashrate: The hashrate of the board in TH/s as a float.
temp: The temperature of the PCB as an int.
chip_temp: The temperature of the chips as an int.
chips: The chip count of the board as an int.
expected_chips: The expected chip count of the board as an int.
serial_number: The serial number of the board.
missing: Whether the board is returned from the miners data as a bool.
"""
class M33SPlusVH20(WhatsMiner): # noqa - ignore ABC method implementation slot: int = 0
def __init__(self, ip: str, api_ver: str = "0.0.0"): hashrate: float = None
super().__init__(ip, api_ver) temp: int = None
self.ip = ip chip_temp: int = None
self.model = "M33S+ VH20" chips: int = None
self.expected_hashboards = 4 expected_chips: int = None
self.expected_chips = 100 serial_number: str = None
self.fan_count = 0 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
class M33SPlusVH30(WhatsMiner): # noqa - ignore ABC method implementation def __getitem__(self, item: str):
def __init__(self, ip: str, api_ver: str = "0.0.0"): try:
super().__init__(ip, api_ver) return getattr(self, item)
self.ip = ip except AttributeError:
self.model = "M33S+ VH30" raise KeyError(f"{item}")
self.expected_hashboards = 4
self.expected_chips = 0 # slot1 116, slot2 106, slot3 116, slot4 106
warnings.warn(
"Unknown chip count for miner type M30S+ VH30, please open an issue on GitHub (https://github.com/UpstreamData/pyasic)."
)
self.fan_count = 0

View File

@@ -14,24 +14,31 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import warnings from dataclasses import dataclass
from typing import Any
from pyasic.miners.makes import WhatsMiner
class M31V10(WhatsMiner): # noqa - ignore ABC method implementation @dataclass
def __init__(self, ip: str, api_ver: str = "0.0.0"): class Fan:
super().__init__(ip, api_ver) """A Dataclass to standardize fan data.
self.ip = ip
self.model = "M31 V10"
self.expected_chips = 70
self.fan_count = 2
Attributes:
speed: The speed of the fan.
"""
class M31V20(WhatsMiner): # noqa - ignore ABC method implementation speed: int = None
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver) def get(self, __key: str, default: Any = None):
self.ip = ip try:
self.model = "M31 V20" val = self.__getitem__(__key)
self.nominal_chips = 74 if val is None:
self.fan_count = 2 return default
return val
except KeyError:
return default
def __getitem__(self, item: str):
try:
return getattr(self, item)
except AttributeError:
raise KeyError(f"{item}")

View File

@@ -20,7 +20,7 @@ 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 AntminerModern, BOSMiner, BTMiner from pyasic.miners.backends import AntminerModern, BOSMiner, BTMiner
from pyasic.miners.types import S9, S17, T17, S17e, S17Plus, S17Pro, T17e, T17Plus from pyasic.miners.models import S9, S17, T17, S17e, S17Plus, S17Pro, T17e, T17Plus
FAN_USAGE = 50 # 50 W per fan FAN_USAGE = 50 # 50 W per fan
@@ -66,14 +66,14 @@ class _MinerPhaseBalancer:
str(miner.ip): { str(miner.ip): {
"miner": miner, "miner": miner,
"set": 0, "set": 0,
"min": miner.fan_count * FAN_USAGE, "min": miner.expected_fans * FAN_USAGE,
} }
for miner in miners for miner in miners
} }
for miner in miners: for miner in miners:
if ( if (
isinstance(miner, BTMiner) isinstance(miner, BTMiner)
and not (miner.model.startswith("M2") if miner.model else True) and not (miner.raw_model.startswith("M2") if miner.raw_model else True)
) or isinstance(miner, BOSMiner): ) or isinstance(miner, BOSMiner):
if isinstance(miner, S9): if isinstance(miner, S9):
self.miners[str(miner.ip)]["tune"] = True self.miners[str(miner.ip)]["tune"] = True
@@ -98,8 +98,8 @@ class _MinerPhaseBalancer:
self.miners[str(miner.ip)]["tune"] = False self.miners[str(miner.ip)]["tune"] = False
self.miners[str(miner.ip)]["shutdown"] = True self.miners[str(miner.ip)]["shutdown"] = True
self.miners[str(miner.ip)]["max"] = 3600 self.miners[str(miner.ip)]["max"] = 3600
if miner.model: if miner.raw_model:
if miner.model.startswith("M2"): if miner.raw_model.startswith("M2"):
self.miners[str(miner.ip)]["tune"] = False self.miners[str(miner.ip)]["tune"] = False
self.miners[str(miner.ip)]["shutdown"] = True self.miners[str(miner.ip)]["shutdown"] = True
self.miners[str(miner.ip)]["max"] = 2400 self.miners[str(miner.ip)]["max"] = 2400
@@ -149,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 == None: if data_point.wattage_limit is not 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 == None: elif data_point.wattage is not 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)
@@ -183,13 +183,19 @@ class _MinerPhaseBalancer:
if (not miner["tune"]) and (miner["shutdown"]) if (not miner["tune"]) and (miner["shutdown"])
] ]
) )
# min_other_wattage = sum([miner["min"] for miner in self.miners.values() if (not miner["tune"]) and (not miner["shutdown"])]) # min_other_wattage = sum(
# [
# miner["min"]
# for miner in self.miners.values()
# if (not miner["tune"]) and (not miner["shutdown"])
# ]
# )
# make sure wattage isnt set too high # make sure wattage isnt set too high
if wattage > (max_tune_wattage + max_shutdown_wattage + max_other_wattage): if wattage > (max_tune_wattage + max_shutdown_wattage + max_other_wattage):
raise APIError( raise APIError(
f"Wattage setpoint is too high, setpoint: {wattage}W, max: {max_tune_wattage + max_shutdown_wattage + max_other_wattage}W" f"Wattage setpoint is too high, setpoint: {wattage}W, max: {max_tune_wattage + max_shutdown_wattage + max_other_wattage}W"
) # PhaseBalancingError(f"Wattage setpoint is too high, setpoint: {wattage}W, max: {max_tune_wattage + max_shutdown_wattage + max_other_wattage}W") )
# should now know wattage limits and which can be tuned/shutdown # should now know wattage limits and which can be tuned/shutdown
# check if 1/2 max of the miners which can be tuned is low enough # check if 1/2 max of the miners which can be tuned is low enough

View File

@@ -14,13 +14,7 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import ipaddress from .base import AnyMiner
from typing import Union from .data import DataOptions
from .factory import get_miner, miner_factory
from pyasic.miners.base import AnyMiner, BaseMiner from .listener import MinerListener
from pyasic.miners.miner_factory import miner_factory
# abstracted version of get miner that is easier to access
async def get_miner(ip: Union[ipaddress.ip_address, str]) -> AnyMiner:
return await miner_factory.get_miner(ip)

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.types import S17, S17e, S17Plus, S17Pro from pyasic.miners.models import S17, S17e, S17Plus, S17Pro
class BMMinerS17(AntminerOld, S17): class BMMinerS17(AntminerOld, S17):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.types import T17, T17e, T17Plus from pyasic.miners.models import T17, T17e, T17Plus
class BMMinerT17(AntminerOld, T17): class BMMinerT17(AntminerOld, T17):

View File

@@ -15,19 +15,23 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.types import ( from pyasic.miners.models import (
S19, S19,
S19L, S19L,
S19XP, S19XP,
S19a, S19a,
S19aPro, S19aPro,
S19Hydro,
S19i, S19i,
S19j, S19j,
S19jNoPIC, S19jNoPIC,
S19jPro, S19jPro,
S19Plus, S19Plus,
S19Pro, S19Pro,
S19ProHydro,
S19ProPlus, S19ProPlus,
S19ProPlusHydro,
S19KPro,
) )
@@ -77,3 +81,19 @@ class BMMinerS19jPro(AntminerModern, S19jPro):
class BMMinerS19L(AntminerModern, S19L): class BMMinerS19L(AntminerModern, S19L):
pass pass
class BMMinerS19ProHydro(AntminerModern, S19ProHydro):
pass
class BMMinerS19Hydro(AntminerModern, S19Hydro):
pass
class BMMinerS19ProPlusHydro(AntminerModern, S19ProPlusHydro):
pass
class BMMinerS19KPro(AntminerModern, S19KPro):
pass

View File

@@ -15,9 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.types import T19 from pyasic.miners.models import T19
# noqa - Ignore access to _module
class BMMinerT19(AntminerModern, T19): class BMMinerT19(AntminerModern, T19):

View File

@@ -18,6 +18,7 @@ from .S19 import (
BMMinerS19, BMMinerS19,
BMMinerS19a, BMMinerS19a,
BMMinerS19aPro, BMMinerS19aPro,
BMMinerS19Hydro,
BMMinerS19i, BMMinerS19i,
BMMinerS19j, BMMinerS19j,
BMMinerS19jNoPIC, BMMinerS19jNoPIC,
@@ -25,7 +26,10 @@ from .S19 import (
BMMinerS19L, BMMinerS19L,
BMMinerS19Plus, BMMinerS19Plus,
BMMinerS19Pro, BMMinerS19Pro,
BMMinerS19ProHydro,
BMMinerS19ProPlus, BMMinerS19ProPlus,
BMMinerS19ProPlusHydro,
BMMinerS19XP, BMMinerS19XP,
BMMinerS19KPro,
) )
from .T19 import BMMinerT19 from .T19 import BMMinerT19

View File

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

View File

@@ -0,0 +1,16 @@
# ------------------------------------------------------------------------------
# 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 .S21 import BMMinerS21

View File

@@ -15,10 +15,8 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.types import HS3 from pyasic.miners.models import HS3
class BMMinerHS3(AntminerModern, HS3): class BMMinerHS3(AntminerModern, HS3):
def __init__(self, ip: str, api_ver: str = "0.0.0"): supports_shutdown = False
super().__init__(ip, api_ver)
self.supports_shutdown = False

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.types import L3Plus from pyasic.miners.models import L3Plus
class BMMinerL3Plus(AntminerOld, L3Plus): class BMMinerL3Plus(AntminerOld, L3Plus):

View File

@@ -14,10 +14,8 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.types import L7 from pyasic.miners.models import L7
class BMMinerL7(AntminerModern, L7): class BMMinerL7(AntminerModern, L7):
def __init__(self, ip: str, api_ver: str = "0.0.0"): supports_shutdown = False
super().__init__(ip, api_ver)
self.supports_shutdown = False

View File

@@ -15,10 +15,8 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerModern from pyasic.miners.backends import AntminerModern
from pyasic.miners.types import E9Pro from pyasic.miners.models import E9Pro
class BMMinerE9Pro(AntminerModern, E9Pro): class BMMinerE9Pro(AntminerModern, E9Pro):
def __init__(self, ip: str, api_ver: str = "0.0.0"): supports_shutdown = False
super().__init__(ip, api_ver)
self.supports_shutdown = False

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BMMiner from pyasic.miners.backends import BMMiner
from pyasic.miners.types import S9, S9i, S9j from pyasic.miners.models import S9, S9i, S9j
class BMMinerS9(BMMiner, S9): class BMMinerS9(BMMiner, S9):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BMMiner from pyasic.miners.backends import BMMiner
from pyasic.miners.types import T9 from pyasic.miners.models import T9
class BMMinerT9(BMMiner, T9): class BMMinerT9(BMMiner, T9):

View File

@@ -18,3 +18,4 @@ from .X7 import *
from .X9 import * from .X9 import *
from .X17 import * from .X17 import *
from .X19 import * from .X19 import *
from .X21 import *

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSMiner
from pyasic.miners.types import S17, S17e, S17Plus, S17Pro from pyasic.miners.models import S17, S17e, S17Plus, S17Pro
class BOSMinerS17(BOSMiner, S17): class BOSMinerS17(BOSMiner, S17):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSMiner
from pyasic.miners.types import T17, T17e, T17Plus from pyasic.miners.models import T17, T17e, T17Plus
class BOSMinerT17(BOSMiner, T17): class BOSMinerT17(BOSMiner, T17):

View File

@@ -14,8 +14,8 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSer
from pyasic.miners.types import ( from pyasic.miners.models import (
S19, S19,
S19XP, S19XP,
S19a, S19a,
@@ -30,45 +30,45 @@ from pyasic.miners.types import (
) )
class BOSMinerS19(BOSMiner, S19): class BOSMinerS19(BOSer, S19):
pass pass
class BOSMinerS19Plus(BOSMiner, S19Plus): class BOSMinerS19Plus(BOSer, S19Plus):
pass pass
class BOSMinerS19Pro(BOSMiner, S19Pro): class BOSMinerS19Pro(BOSer, S19Pro):
pass pass
class BOSMinerS19a(BOSMiner, S19a): class BOSMinerS19a(BOSer, S19a):
pass pass
class BOSMinerS19j(BOSMiner, S19j): class BOSMinerS19j(BOSer, S19j):
pass pass
class BOSMinerS19jNoPIC(BOSMiner, S19jNoPIC): class BOSMinerS19jNoPIC(BOSer, S19jNoPIC):
pass pass
class BOSMinerS19jPro(BOSMiner, S19jPro): class BOSMinerS19jPro(BOSer, S19jPro):
pass pass
class BOSMinerS19kProNoPIC(BOSMiner, S19kProNoPIC): class BOSMinerS19kProNoPIC(BOSer, S19kProNoPIC):
pass pass
class BOSMinerS19aPro(BOSMiner, S19aPro): class BOSMinerS19aPro(BOSer, S19aPro):
pass pass
class BOSMinerS19jProPlus(BOSMiner, S19jProPlus): class BOSMinerS19jProPlus(BOSer, S19jProPlus):
pass pass
class BOSMinerS19XP(BOSMiner, S19XP): class BOSMinerS19XP(BOSer, S19XP):
pass pass

View File

@@ -14,9 +14,9 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSer
from pyasic.miners.types import T19 from pyasic.miners.models import T19
class BOSMinerT19(BOSMiner, T19): class BOSMinerT19(BOSer, T19):
pass pass

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import BOSMiner from pyasic.miners.backends import BOSMiner
from pyasic.miners.types import S9 from pyasic.miners.models import S9
class BOSMinerS9(BOSMiner, S9): class BOSMinerS9(BOSMiner, S9):

View File

@@ -15,10 +15,8 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.types import Z15 from pyasic.miners.models import Z15
class CGMinerZ15(AntminerOld, Z15): class CGMinerZ15(AntminerOld, Z15):
def __init__(self, ip: str, api_ver: str = "0.0.0"): supports_shutdown = False
super().__init__(ip, api_ver)
self.supports_shutdown = False

View File

@@ -14,10 +14,8 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.types import D3 from pyasic.miners.models import D3
class CGMinerD3(AntminerOld, D3): class CGMinerD3(AntminerOld, D3):
def __init__(self, ip: str, api_ver: str = "0.0.0"): supports_shutdown = False
super().__init__(ip, api_ver)
self.supports_shutdown = False

View File

@@ -15,10 +15,8 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import AntminerOld from pyasic.miners.backends import AntminerOld
from pyasic.miners.types import DR5 from pyasic.miners.models import DR5
class CGMinerDR5(AntminerOld, DR5): class CGMinerDR5(AntminerOld, DR5):
def __init__(self, ip: str, api_ver: str = "0.0.0"): supports_shutdown = False
super().__init__(ip, api_ver)
self.supports_shutdown = False

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import ePIC from pyasic.miners.backends import ePIC
from pyasic.miners.types import S19, S19XP, S19j, S19jPro, S19jProPlus, S19kPro, S19Pro from pyasic.miners.models import S19, S19XP, S19j, S19jPro, S19jProPlus, S19kPro, S19Pro
class ePICS19(ePIC, S19): class ePICS19(ePIC, S19):

View File

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

View File

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

View File

@@ -15,3 +15,4 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from .X19 import * from .X19 import *
from .X21 import *

View File

@@ -21,14 +21,53 @@ 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 from pyasic.miners.backends import Hiveon
from pyasic.miners.types import T9 from pyasic.miners.data import DataFunction, DataLocations, DataOptions, RPCAPICommand
from pyasic.miners.models import T9
HIVEON_T9_DATA_LOC = DataLocations(
**{
str(DataOptions.API_VERSION): DataFunction(
"_get_api_ver",
[RPCAPICommand("rpc_version", "version")],
),
str(DataOptions.FW_VERSION): DataFunction(
"_get_fw_ver",
[RPCAPICommand("rpc_version", "version")],
),
str(DataOptions.HASHRATE): DataFunction(
"_get_hashrate",
[RPCAPICommand("rpc_summary", "summary")],
),
str(DataOptions.EXPECTED_HASHRATE): DataFunction(
"_get_expected_hashrate",
[RPCAPICommand("rpc_stats", "stats")],
),
str(DataOptions.HASHBOARDS): DataFunction(
"_get_hashboards",
[RPCAPICommand("rpc_stats", "stats")],
),
str(DataOptions.ENVIRONMENT_TEMP): DataFunction(
"_get_env_temp",
[RPCAPICommand("rpc_stats", "stats")],
),
str(DataOptions.WATTAGE): DataFunction(
"_get_wattage",
[RPCAPICommand("rpc_stats", "stats")],
),
str(DataOptions.FANS): DataFunction(
"_get_fans",
[RPCAPICommand("rpc_stats", "stats")],
),
str(DataOptions.UPTIME): DataFunction(
"_get_uptime",
[RPCAPICommand("rpc_stats", "stats")],
),
}
)
class HiveonT9(Hiveon, T9): class HiveonT9(Hiveon, T9):
def __init__(self, ip: str, api_ver: str = "0.0.0") -> None: data_locations = HIVEON_T9_DATA_LOC
super().__init__(ip, api_ver=api_ver)
self.ip = ip
self.pwd = "admin"
################################################## ##################################################
### DATA GATHERING FUNCTIONS (get_{some_data}) ### ### DATA GATHERING FUNCTIONS (get_{some_data}) ###
@@ -45,47 +84,57 @@ class HiveonT9(Hiveon, T9):
except (TypeError, ValueError, asyncssh.Error, OSError, AttributeError): except (TypeError, ValueError, asyncssh.Error, OSError, AttributeError):
pass pass
async def get_hashboards(self, api_stats: dict = None) -> List[HashBoard]: async def _get_hashboards(self, rpc_stats: dict = None) -> List[HashBoard]:
hashboards = [
HashBoard(slot=board, expected_chips=self.expected_chips)
for board in range(self.expected_hashboards)
]
if rpc_stats is None:
try:
rpc_stats = self.rpc.stats()
except APIError:
return []
board_map = { board_map = {
0: [2, 9, 10], 0: [2, 9, 10],
1: [3, 11, 12], 1: [3, 11, 12],
2: [4, 13, 14], 2: [4, 13, 14],
} }
hashboards = []
for board in board_map: for board in board_map:
hashboard = HashBoard(slot=board, expected_chips=self.expected_chips)
hashrate = 0 hashrate = 0
chips = 0 chips = 0
for chipset in board_map[board]: for chipset in board_map[board]:
if hashboard.chip_temp == None: if hashboards[board].chip_temp is None:
try: try:
hashboard.board_temp = api_stats["STATS"][1][f"temp{chipset}"] hashboards[board].temp = rpc_stats["STATS"][1][f"temp{chipset}"]
hashboard.chip_temp = api_stats["STATS"][1][f"temp2_{chipset}"] hashboards[board].chip_temp = rpc_stats["STATS"][1][
f"temp2_{chipset}"
]
except (KeyError, IndexError): except (KeyError, IndexError):
pass pass
else: else:
hashboard.missing = False hashboards[board].missing = False
try: try:
hashrate += api_stats["STATS"][1][f"chain_rate{chipset}"] hashrate += rpc_stats["STATS"][1][f"chain_rate{chipset}"]
chips += api_stats["STATS"][1][f"chain_acn{chipset}"] chips += rpc_stats["STATS"][1][f"chain_acn{chipset}"]
except (KeyError, IndexError): except (KeyError, IndexError):
pass pass
hashboard.hashrate = round(hashrate / 1000, 2) hashboards[board].hashrate = round(hashrate / 1000, 2)
hashboard.chips = chips hashboards[board].chips = chips
hashboards.append(hashboard)
return hashboards return hashboards
async def get_wattage(self, api_stats: dict = None) -> Optional[int]: async def _get_wattage(self, rpc_stats: dict = None) -> Optional[int]:
if not api_stats: if not rpc_stats:
try: try:
api_stats = await self.api.stats() rpc_stats = await self.rpc.stats()
except APIError: except APIError:
pass pass
if api_stats: if rpc_stats:
boards = api_stats.get("STATS") boards = rpc_stats.get("STATS")
try: try:
wattage_raw = boards[1]["chain_power"] wattage_raw = boards[1]["chain_power"]
except (KeyError, IndexError): except (KeyError, IndexError):
@@ -94,23 +143,23 @@ class HiveonT9(Hiveon, T9):
# parse wattage position out of raw data # parse wattage position out of raw data
return round(float(wattage_raw.split(" ")[0])) return round(float(wattage_raw.split(" ")[0]))
async def get_env_temp(self, api_stats: dict = None) -> Optional[float]: async def _get_env_temp(self, rpc_stats: dict = None) -> Optional[float]:
env_temp_list = [] env_temp_list = []
board_map = { board_map = {
0: [2, 9, 10], 0: [2, 9, 10],
1: [3, 11, 12], 1: [3, 11, 12],
2: [4, 13, 14], 2: [4, 13, 14],
} }
if not api_stats: if not rpc_stats:
try: try:
api_stats = await self.api.stats() rpc_stats = await self.rpc.stats()
except APIError: except APIError:
pass pass
if api_stats: if rpc_stats:
for board in board_map.values(): for board in board_map.values():
for chipset in board: for chipset in board:
try: try:
env_temp = api_stats["STATS"][1][f"temp3_{chipset}"] env_temp = rpc_stats["STATS"][1][f"temp3_{chipset}"]
if not env_temp == 0: if not env_temp == 0:
env_temp_list.append(int(env_temp)) env_temp_list.append(int(env_temp))
except (KeyError, IndexError): except (KeyError, IndexError):

View File

@@ -0,0 +1,42 @@
# ------------------------------------------------------------------------------
# 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 LUXMiner
from pyasic.miners.models import S19, S19XP, S19jPro, S19jProPlus, S19kPro, S19Pro
class LUXMinerS19(LUXMiner, S19):
pass
class LUXMinerS19Pro(LUXMiner, S19Pro):
pass
class LUXMinerS19jPro(LUXMiner, S19jPro):
pass
class LUXMinerS19jProPlus(LUXMiner, S19jProPlus):
pass
class LUXMinerS19kPro(LUXMiner, S19kPro):
pass
class LUXMinerS19XP(LUXMiner, S19XP):
pass

View File

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

View File

@@ -0,0 +1,25 @@
# ------------------------------------------------------------------------------
# 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 (
LUXMinerS19,
LUXMinerS19jPro,
LUXMinerS19jProPlus,
LUXMinerS19kPro,
LUXMinerS19Pro,
LUXMinerS19XP,
)
from .T19 import LUXMinerT19

View File

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

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 .S21 import LUXMinerS21

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import LUXMiner from pyasic.miners.backends import LUXMiner
from pyasic.miners.types import S9 from pyasic.miners.models import S9
class LUXMinerS9(LUXMiner, S9): class LUXMinerS9(LUXMiner, S9):

View File

@@ -15,3 +15,5 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from .X9 import * from .X9 import *
from .X19 import *
from .X21 import *

View File

@@ -14,7 +14,7 @@
# limitations under the License. - # limitations under the License. -
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish from pyasic.miners.backends import VNish
from pyasic.miners.types import S17Plus, S17Pro from pyasic.miners.models import S17Plus, S17Pro
class VNishS17Plus(VNish, S17Plus): class VNishS17Plus(VNish, S17Plus):

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish from pyasic.miners.backends import VNish
from pyasic.miners.types import ( from pyasic.miners.models import (
S19, S19,
S19XP, S19XP,
S19a, S19a,

View File

@@ -15,7 +15,7 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish from pyasic.miners.backends import VNish
from pyasic.miners.types import T19 from pyasic.miners.models import T19
class VNishT19(VNish, T19): class VNishT19(VNish, T19):

View File

@@ -15,9 +15,8 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from pyasic.miners.backends import VNish from pyasic.miners.backends import VNish
from pyasic.miners.types import L3Plus from pyasic.miners.models import L3Plus
class VnishL3Plus(VNish, L3Plus): class VnishL3Plus(VNish, L3Plus):
def __init__(self, ip: str, api_ver: str = "0.0.0"): pass
super().__init__(ip, api_ver)

View File

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

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 .L7 import VnishL7

View File

@@ -15,5 +15,6 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
from .X3 import * from .X3 import *
from .X7 import *
from .X17 import * from .X17 import *
from .X19 import * from .X19 import *

View File

@@ -0,0 +1 @@
from .flux import *

View File

@@ -0,0 +1,6 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAT1500
class AuradineFluxAT1500(AuradineAT1500, Auradine):
pass

View File

@@ -0,0 +1,10 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAT2860, AuradineAT2880
class AuradineFluxAT2860(AuradineAT2860, Auradine):
pass
class AuradineFluxAT2880(AuradineAT2880, Auradine):
pass

View File

@@ -0,0 +1,2 @@
from .AT1 import AuradineFluxAT1500
from .AT2 import AuradineFluxAT2860, AuradineFluxAT2880

View File

@@ -0,0 +1,6 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAI2500
class AuradineFluxAI2500(AuradineAI2500, Auradine):
pass

View File

@@ -0,0 +1,6 @@
from pyasic.miners.backends import Auradine
from pyasic.miners.models import AuradineAI3680
class AuradineFluxAI3680(AuradineAI3680, Auradine):
pass

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