Compare commits

...

1026 Commits

Author SHA1 Message Date
Brett Rowan
1ea4f4e124 version: bump version number 2025-07-15 08:11:34 -06:00
bbemoll
a8a0e4a5fe Added support for Antminer S19XH Hydro running on Braiins OS (#353)
* Add pyasic files

* Add pyasic files

* Update pyproject.toml

* Update pyproject.toml

* Added support for Antminer S19XP Hydro running on Braiins OS

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-07-15 08:10:59 -06:00
Brett Rowan
5f2f6e01da version: bump version number 2025-07-10 10:56:42 -06:00
Brody
41b4c23d45 Fix API Issue with Bitaxe Miners (#352)
* added checks to identify which field is None.

* better logging

* if asicCount is None, try to find it in /system/asic

* ran pre-commit
2025-07-10 10:56:22 -06:00
Brett Rowan
b4687f18fd version: bump version number 2025-05-01 15:15:42 -06:00
Brett Rowan
2437421005 feature: add support for a bunch of BOS and VNish S21 models. 2025-05-01 15:15:18 -06:00
Ryan Heideman
40ebc2773f Retry and Timeout Changes for espminer (#340)
* Retry and Timeout Fixes for espminer

* Build check fix
2025-05-01 15:07:58 -06:00
Art
b8ae238d23 Fix incorrect computation of active_preset for Antminer VNish. See #338. (#339)
* Fix incorrect computation of active_preset for Antminer VNish. See #338.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* #338 renamed perf_summary to web_perf_summary for clarity and consistency. New API call is done in backward compatibility manner. Data is also retrieved safely

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-05-01 15:07:11 -06:00
Brett Rowan
2920639b70 version: bump version number 2025-04-27 11:01:10 -06:00
Brett Rowan
bd9144b3de requirements: bump dependency versions 2025-04-27 11:01:10 -06:00
SKART1
8f7a67d4dc Fix efficiency_fract property to correctly return computed value. See #334. 2025-04-19 08:28:44 -06:00
Brett Rowan
a62bea33a7 docs: update docs 2025-04-18 16:15:31 -06:00
pre-commit-ci[bot]
406bcd179c [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-04-18 16:12:55 -06:00
Ryan Heideman
aa87ef7d71 nano3s fixes 2025-04-18 16:12:55 -06:00
SKART1
ec88fbf6aa Fix #334 efficiency calculation and add computed fields 2025-04-18 16:12:44 -06:00
pre-commit-ci[bot]
e23c86a944 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/python-poetry/poetry: 2.1.1 → 2.1.2](https://github.com/python-poetry/poetry/compare/2.1.1...2.1.2)
2025-04-16 08:41:30 -06:00
Brett Rowan
b81276cb19 version: bump version number 2025-04-16 08:40:36 -06:00
Adrian
8dcc72b1bb T21 working on LuxOS (#331) 2025-04-14 12:55:54 -06:00
Timur Taipov
540572356f feature: add support for S21+ hydro (#326) 2025-04-14 09:15:06 -06:00
Ryan Heideman
83035a869b feature: Add Support for Avalon Nano 3s (#329) 2025-04-12 15:34:45 -06:00
Brett Rowan
4c104a59ff version: bump version number 2025-04-01 09:24:20 -06:00
Brett Rowan
e708ae3728 bug: remove MSKminer web identification 2025-04-01 09:23:51 -06:00
Wilfred Allyn
a4352816ee bug: pass atmset param as bool 2025-04-01 07:48:42 -06:00
Will Jackson
336bd9c002 bug: update set_dps configuration to handle optional power and hashrate parameters (#319)
* bug: update set_dps configuration to handle optional power and hashrate parameters
2025-03-27 11:09:47 -06:00
Wilfred Allyn
e3c917efde feature: set supports_autotuning True for luxminer 2025-03-26 08:06:38 -06:00
Brett Rowan
4d71012ed6 version: bump version number
Closes: #310
2025-03-20 10:46:30 -06:00
Will Jackson
1acdba8ae0 bug: fix set_dps configuration to handle power target parameters correctly (#318)
* bug: fix set_dps configuration to handle power target parameters correctly

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-03-20 10:45:48 -06:00
Brett Rowan
5567f26c03 version: bump version number
Closes: #316, #310
2025-03-20 09:20:51 -06:00
Brett Rowan
0027485582 bug: fix set_dps tuple
cc: #310
2025-03-20 09:20:23 -06:00
Brett Rowan
c9bcb7bab6 feature: add support for S21+
cc: #316
2025-03-19 13:28:03 -06:00
John-Paul Compagnone
0ee261930e epic: remove guard on expected_hashboards 2025-03-18 09:35:13 -06:00
John-Paul Compagnone
3cfc8dded9 epic: remove v1 from ELITE miner 2025-03-18 09:35:13 -06:00
John-Paul Compagnone
655cf6d0ac epic: add BlockMiner eLITE, S19k Pro Dualie 2025-03-18 09:35:13 -06:00
Brett Rowan
640dc6d8c2 version: bump version number 2025-03-18 09:00:40 -06:00
Brett Rowan
a572fedb4d bug: fix some cases where bosminer config could be invalid 2025-03-18 09:00:16 -06:00
Brett Rowan
6c46a7cd71 bug: handle cases where hashboards and fans can be None with unknown types 2025-03-18 08:18:34 -06:00
Brett Rowan
49f42172da version: bump version number 2025-03-17 14:19:47 -06:00
Brett Rowan
83be80e4bc bug: handle connection errors in grpc for boser 2025-03-17 14:19:28 -06:00
Brett Rowan
0be9e9d519 feature: add fault_light to influx 2025-03-17 14:17:37 -06:00
Upstream Data
4694c0f774 bug: fix error code handling in list 2025-03-06 11:45:38 -07:00
Brett Rowan
11012b310b bug: fix delimiter handling 2025-03-04 21:27:28 -07:00
Brett Rowan
8852fab3ee feature: allow the user to pass a delimiter to as_influx 2025-03-04 20:14:55 -07:00
Brett Rowan
ec1b2ca162 bug: fix bad " " handling in influx 2025-03-04 19:58:44 -07:00
Upstream Data
1f9d4c8c10 bug: swap to lower case booleans 2025-03-04 19:51:48 -07:00
Upstream Data
5bb04b2af4 refactor: round hashrate to 2 decimals for influx 2025-03-04 19:51:48 -07:00
Upstream Data
2e192a1536 feature: update support for influxdb line protocol 2025-03-04 19:51:48 -07:00
Brett Rowan
4da8044bc7 bug: fix bad type hint 2025-03-04 19:51:37 -07:00
Brett Rowan
76078e4d0e bug: fix wattage limit parsing on luxos 2025-03-04 19:51:13 -07:00
Upstream Data
276a476fab bug: fix json decode error possibility with avalon nanos 2025-03-03 15:04:22 -07:00
pre-commit-ci[bot]
e0abed4f93 [pre-commit.ci] pre-commit autoupdate (#307)
updates:
- [github.com/pycqa/isort: 6.0.0 → 6.0.1](https://github.com/pycqa/isort/compare/6.0.0...6.0.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-03-03 14:56:47 -07:00
Ganey
4a67bd5d99 feat: add powerlimit to avalon nano (#302)
* feat: add powerlimit to avalon nano

add power limit to avalon nano

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-02-26 15:23:18 -07:00
pre-commit-ci[bot]
eb48d04939 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/python-poetry/poetry: 2.0.1 → 2.1.1](https://github.com/python-poetry/poetry/compare/2.0.1...2.1.1)
2025-02-18 08:44:43 -07:00
Upstream Data
c4697728e4 version: bump version number 2025-02-13 15:38:53 -07:00
Upstream Data
de64172073 feature: add support for Hiveon S19kPro 2025-02-13 15:38:28 -07:00
Upstream Data
4d7a13433b version: bump version number 2025-02-12 16:08:23 -07:00
Adrian
e14a4791b2 it turns out there are 3 hashboards per miner (#293) 2025-02-12 16:07:46 -07:00
Upstream Data
0e76d4550b version: bump version number 2025-02-11 15:47:56 -07:00
Upstream Data
2d424025e9 feature: add MAC address to mskminer 2025-02-11 15:47:37 -07:00
Upstream Data
bf4903ce4b refactor: remove some unused imports 2025-02-11 09:38:31 -07:00
Upstream Data
4f7f6bf045 version: bump version number 2025-02-11 09:34:57 -07:00
Upstream Data
824890ec97 feature: add very basic support for MSKminer 2025-02-11 09:34:23 -07:00
Upstream Data
ce9d7ffb0f bug: fix issue with vnish preset parsing on some miners 2025-02-11 09:00:59 -07:00
Upstream Data
183b4934c1 refactor: remote unused import in test 2025-02-06 11:44:15 -07:00
Upstream Data
3d2b260b17 version: bump version number 2025-02-06 11:42:33 -07:00
Upstream Data
f88c1734eb bug: fix some issues with avalon 1566, and add tests 2025-02-06 11:42:17 -07:00
Upstream Data
b897ca8363 version: bump version number 2025-02-06 11:33:08 -07:00
Upstream Data
dba341fdae feature: add support for avalon 1566 2025-02-06 11:32:45 -07:00
Upstream Data
837794bd57 version: bump version number 2025-02-05 10:45:56 -07:00
Upstream Data
36d16c7235 feature: add support for elphapex configs 2025-02-05 10:45:35 -07:00
Upstream Data
7797023689 feature: add support for elphapex pools 2025-02-05 08:28:28 -07:00
Upstream Data
1021f200ec version: bump version number 2025-02-05 08:07:35 -07:00
Upstream Data
197d6568e3 bug: fix DG1+ naming 2025-02-05 08:07:14 -07:00
Upstream Data
71c8905674 version: bump version number 2025-02-04 16:00:18 -07:00
Upstream Data
15c3806fbf refactor: cleanup some imports 2025-02-04 15:59:32 -07:00
Upstream Data
a5c42c9c2b feature: add support for Elphapex DG1+ 2025-02-04 15:59:32 -07:00
Upstream Data
90d8a795e6 version: bump version number 2025-02-03 09:39:49 -07:00
Upstream Data
07cf1b134c feature: add support for vnish error codes 2025-02-03 09:39:30 -07:00
Upstream Data
53e1f33fa6 version: bump version number 2025-02-03 09:32:44 -07:00
Upstream Data
16ab2bd4e3 feature: add support for luckyminer LV07 2025-02-03 09:32:16 -07:00
Upstream Data
de728f12d2 version: bump version number 2025-02-03 09:27:43 -07:00
Upstream Data
8092e12dfb feature: add support for S19X88 Hiveon 2025-02-03 09:27:18 -07:00
b-rowan
e70c3e9f79 version: bump version number 2025-01-30 17:56:47 -07:00
b-rowan
39a97f2914 feature: add mac address support for avalon nano 3 2025-01-30 17:56:16 -07:00
b-rowan
35af74ad1a version: bump version number 2025-01-30 07:14:50 -07:00
Erik Olof Gunnar Andersson
15fa91fb98 bug: don’t timeout forever on _socket_ping (#288)
* Don't timeout forever on _socket_ping

* Use factory_get_timeout to configure number of allowed retries

* Add warning log
2025-01-30 07:05:29 -07:00
James Hilliard
084987a3e1 bug: Add cryptography direct dependency (#286) 2025-01-29 10:01:10 -07:00
b-rowan
e93cc77a58 ci: update pre-commit hooks 2025-01-28 21:29:43 -07:00
b-rowan
788d43c51c version: bump version number 2025-01-28 21:27:17 -07:00
Adrian
74c22b82ce bug: add miner algo type for S21 Hydro (#285) 2025-01-28 21:20:39 -07:00
Upstream Data
1f46ce1b9a version: bump version number 2025-01-28 09:36:56 -07:00
Adrian
7964336a0c feature: add support for S21 Hydro (#283) 2025-01-28 09:36:15 -07:00
Upstream Data
a24fc07c2a ci: update pre-commit to run docs generation when committing. 2025-01-28 08:51:13 -07:00
Upstream Data
4c64481d3b bug: do not run unittest when running in precommit.ci 2025-01-28 08:33:02 -07:00
Upstream Data
66fb5834f0 version: bump version number 2025-01-23 13:37:28 -07:00
Upstream Data
db05cc1d97 feature: add support for S21 Pro BOS 2025-01-23 13:37:04 -07:00
Brett Rowan
418e3ce26e Merge pull request #281 from UpstreamData/fix_hammer_pass 2025-01-23 07:42:20 -07:00
John-Paul Compagnone
5a0bb11a44 fix hammer default password 2025-01-23 08:35:37 -05:00
Upstream Data
39f9d087db version: bump version number 2025-01-20 09:27:40 -07:00
Upstream Data
067a376f94 feature: add support for luckyminer LV08 2025-01-20 09:27:16 -07:00
Upstream Data
a5d6e122f9 version: bump version number 2025-01-20 09:01:04 -07:00
Upstream Data
b160fd75ba refactor: reformat some files 2025-01-20 09:00:45 -07:00
Upstream Data
d1007d3ae8 version: bump version number 2025-01-20 08:58:14 -07:00
Upstream Data
33803e89e2 feature: add support for Vnish S19i
Fixes: #279
2025-01-20 08:21:24 -07:00
Upstream Data
10a44b9877 bug: fix invlaid import in luxminer.py 2025-01-20 08:21:12 -07:00
pre-commit-ci[bot]
bbd883f639 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-01-19 08:18:27 -07:00
Wilfred Allyn
8e2ad478e9 refactor: simplify get_wattage_limit for luxos 2025-01-19 08:18:27 -07:00
Wilfred Allyn
957981a9c6 feature: get active preset from luxos 2025-01-19 08:18:27 -07:00
Wilfred Allyn
13a67dfdd1 feature: add _get_wattage_limit for luxos 2025-01-19 08:18:27 -07:00
Wilfred Allyn
e86f2b62c5 docs: fix issues for docs warnings 2025-01-18 08:03:11 -07:00
Wilfred Allyn
88b4d2cac3 docs: add instructions for building docs locally 2025-01-17 09:31:36 -07:00
Upstream Data
5842ef3d97 version: bump version number 2025-01-16 11:02:57 -07:00
Upstream Data
339a689267 bug: fix possible None value from miner type when parsing hammer miners 2025-01-16 11:02:39 -07:00
Brett Rowan
a0764806c4 version: bump version number 2025-01-15 22:23:41 -07:00
Brett Rowan
6eec0f6d44 bug: fix a few bad type hints in config models 2025-01-15 22:22:53 -07:00
Upstream Data
0854f7833c docs: update supported miners list and generation tool to use unique 2025-01-15 10:56:25 -07:00
Upstream Data
b6edc85679 feature: add support for some weird antminer submodel namings for S21 2025-01-15 09:47:14 -07:00
Upstream Data
ff11ebc304 bug: fix antminer KS5 using iceriver backend 2025-01-15 08:25:02 -07:00
Wilfred Allyn
f3681f1aa5 feature: add support for Vnish S19j Pro A 2025-01-15 07:36:29 -07:00
Wilfred Allyn
1a7411edb3 feature: add support for Vnish T21 and update docs 2025-01-15 07:34:47 -07:00
Upstream Data
f2a4a5d524 version: bump version number 2025-01-08 11:24:08 -07:00
Wilfred Allyn
624a3c5919 feature: revise atmset input params 2025-01-08 11:22:46 -07:00
Wilfred Allyn
2ec8054d24 feature: check if atm enabled before settting power 2025-01-08 11:22:46 -07:00
Wilfred Allyn
d148ccfe5f feature: add atm, atmset commands to luxos rpc 2025-01-08 11:22:46 -07:00
Wilfred Allyn
b6c29d16f9 feature: add set_power_limit for luxos 2025-01-08 11:22:46 -07:00
Wilfred Allyn
53a3bb13af feature: remove deprecated board_n param from profileset 2025-01-08 11:22:46 -07:00
John-Paul Compagnone
16e74e659c add expected_hashrate for bitaxe devices 2025-01-07 09:59:51 -07:00
Upstream Data
730caca23f version: bump version number 2025-01-07 08:57:09 -07:00
Upstream Data
dc126b2953 bug: fix a bug with config on S9 sometimes not having quota set. 2025-01-07 08:56:39 -07:00
Brett Rowan
51abdf0b2d version: bump version number 2025-01-04 11:50:08 -07:00
Brett Rowan
b367b2d293 bug: fix an issue with parsing disabled fan mode on BOS+ 2025-01-04 11:49:49 -07:00
Upstream Data
96f52a4b35 version: bump version number 2025-01-02 16:04:35 -07:00
John-Paul Compagnone
5236e02af2 fix hammer test, enforce default hr unit 2025-01-02 16:04:23 -07:00
Upstream Data
9ee52f77f9 version: bump version number 2025-01-02 15:21:09 -07:00
Upstream Data
26389f8ba0 docs: fix docs 2025-01-02 14:59:36 -07:00
Upstream Data
8a0605bd3b docs: update docs with new wm models 2025-01-02 14:59:36 -07:00
Upstream Data
fe9894919e feature: add support for a lot of whatsminers 2025-01-02 14:59:36 -07:00
Upstream Data
bb399fe362 bug: fix a bug with very new versions of btminer hashboards 2025-01-02 12:30:00 -07:00
Brett Rowan
7ca7fe3e7e version: bump version number 2025-01-01 22:40:20 -07:00
JP Compagnone
748279c25d fix: change sticker hashrate to GH for Hammer and VolcMiner (#264)
* change sticker hashrate to GH

* clean up hashrate for Hammer/Volcminer

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-01-01 22:38:57 -07:00
Brett Rowan
23890fa10a version: bump version number 2024-12-31 13:26:51 -07:00
Brett Rowan
8ab7df516e docs: add checkboxes to indicate support for specific features, and some more updates 2024-12-31 13:26:17 -07:00
Brett Rowan
f7a0188104 feature: add support for M50S++VL30, update docs, fix hammer bug, and handle errors with data on unknown types of miners 2024-12-31 13:05:10 -07:00
wilfredallyn
66a8932ea3 feature: add mining presets for luxos (#262)
* feature: add mining mode preset for luxos

* bug: fix type hint
2024-12-31 12:48:13 -07:00
JP Compagnone
56536fd258 feat: add VolcMiner D1 (#263) 2024-12-31 10:02:48 -07:00
John-Paul Compagnone
1b4e6d4da0 Remove pass 2024-12-26 09:12:45 -07:00
John-Paul Compagnone
2019bdaff2 add sticker_hashrate for D10 2024-12-26 09:12:45 -07:00
pre-commit-ci[bot]
b903cc6e5f [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2024-12-26 09:12:45 -07:00
JP
c1a01b5f7b more D10 updates 2024-12-26 09:12:45 -07:00
JP
3427a8d15a fix D10 board temp 2024-12-26 09:12:45 -07:00
JP
25c08b9bc0 fix to only change the dual version 2024-12-26 09:12:45 -07:00
John-Paul Compagnone
01263da52b add dual rig support to ePIC 2024-12-26 09:12:45 -07:00
Upstream Data
5081319a2f version: bump version number 2024-12-24 08:27:28 -07:00
Upstream Data
ec5be00065 feature: add chip count for S19jXP 2024-12-24 08:27:13 -07:00
Upstream Data
891e28bfe6 version: bump version number 2024-12-24 08:10:26 -07:00
Upstream Data
8e15b00e70 feature: add support for antminer S19j XP and update docs 2024-12-24 08:10:08 -07:00
Upstream Data
df71ab3282 version: bump version number 2024-12-24 08:03:36 -07:00
Upstream Data
1508f7873a bug: fix mining mde being set to an invalid miner_mode in antminer stock and hive 2024-12-24 08:03:19 -07:00
Upstream Data
77058ac692 version: bump version number 2024-12-23 09:26:19 -07:00
Upstream Data
1a4491ca56 feature: add partial support for braiins mini miners 2024-12-23 09:25:28 -07:00
Brett Rowan
d018724aa4 version: bump version number 2024-12-20 17:07:33 -07:00
Brett Rowan
5b97bed704 bug: fix hashrate sum start value in data 2024-12-20 17:07:11 -07:00
Brett Rowan
55786b154d version: bump version number 2024-12-20 10:16:19 -07:00
Brett Rowan
6ab9681dec feature: add auto unit to hashrates and improve model dump for hashrates 2024-12-20 10:16:01 -07:00
Brett Rowan
89641c6316 version: bump version number 2024-12-20 09:26:16 -07:00
Brett Rowan
136ff6a688 feature: add generic hashrate type for doing sums 2024-12-20 09:25:52 -07:00
Brett Rowan
d918d93f4a version: bump version number 2024-12-20 09:21:32 -07:00
Brett Rowan
8046c532a6 bug: fix some issues with adding hashrate types 2024-12-20 09:21:06 -07:00
Upstream Data
92820a362d version: bump version number 2024-12-17 08:15:37 -07:00
aquariuslt
9fd90031a9 fix: update data.env_temp type to float 2024-12-17 08:14:59 -07:00
Brett Rowan
2f2223a112 version: bump version number 2024-12-16 20:06:33 -07:00
Wilfred Allyn
50e6cf9dfd feature: add supports_autotuning to vnish 2024-12-16 07:43:15 -07:00
Wilfred Allyn
1b5e3093e6 feature: set power to highest preset <= wattage 2024-12-16 07:43:15 -07:00
Wilfred Allyn
9e3578b4a2 feature: check vnish presets when set power 2024-12-16 07:43:15 -07:00
Wilfred Allyn
a3087e1a96 set vnish power limit 2024-12-16 07:43:15 -07:00
Brett Rowan
4b16ea2ca2 ci: update publish action 2024-12-10 13:55:30 -07:00
Upstream Data
5dd361c4ef version: bump version number 2024-12-10 13:05:20 -07:00
Upstream Data
098112742c bug: fix vnish config parsing in some overclocking cases 2024-12-10 13:04:58 -07:00
Upstream Data
cd31e0743e docs: update docs 2024-12-10 13:03:07 -07:00
Upstream Data
1a7d0bf7cc feature: add support for vnish S19k pro 2024-12-10 13:02:49 -07:00
Upstream Data
41b5ebf0f0 version: bump version number 2024-12-10 12:28:43 -07:00
Upstream Data
5436bede29 bug: add chip count for avalon 1126 Pro 2024-12-10 12:28:25 -07:00
Upstream Data
c01b3958dc version: bump version number 2024-12-10 11:13:40 -07:00
Upstream Data
c16367285f feature: add support for avalonminer 1126 Pro 2024-12-10 11:13:24 -07:00
Upstream Data
17eae253e6 version: bump version number 2024-12-10 11:08:22 -07:00
Upstream Data
ab30988614 bug: fix incorrect scrypt unit base type 2024-12-10 11:08:03 -07:00
Upstream Data
9b8e547f86 version: bump version number 2024-12-10 11:02:24 -07:00
Upstream Data
3b8cbb9ff1 feature: add support for antminer L9 2024-12-10 11:02:02 -07:00
Upstream Data
d39d278296 version: bump version number 2024-12-10 10:51:58 -07:00
Upstream Data
ea8b922367 bug: fix hive default password 2024-12-10 10:51:46 -07:00
Upstream Data
0d1c8d80e0 version: bump version number 2024-12-10 10:46:44 -07:00
Upstream Data
494d25da97 feature: add support for hiveon S19 2024-12-10 10:46:23 -07:00
Upstream Data
0327d93a35 version: bump version number 2024-12-10 10:29:18 -07:00
Upstream Data
680584c468 bug: fix pydantic validation error with hashrate tuning 2024-12-10 10:28:55 -07:00
Upstream Data
c0dbafb198 version: bump version number 2024-12-10 09:21:34 -07:00
Upstream Data
97d2c4ac34 feature: add more hiveon functionality 2024-12-10 09:21:11 -07:00
Upstream Data
055d633c91 bug: fix hiveon identification in some cases 2024-12-10 08:43:39 -07:00
Upstream Data
68c57f265f feature: add supports presets flag 2024-12-10 07:44:34 -07:00
Upstream Data
1ba0f8ed83 feature: parse vnish presets 2024-12-10 07:44:34 -07:00
Upstream Data
7f74b083d3 feature: add mining mode preset option to config 2024-12-10 07:44:34 -07:00
Wilfred Allyn
97c20dae0a bug: fix boser rpc 2024-12-08 08:54:31 -07:00
Upstream Data
09c7aff640 version: bump version number 2024-12-04 10:05:32 -07:00
Upstream Data
7e7cdc9615 docs: fix some docstrings and type annotations 2024-12-04 10:03:33 -07:00
Upstream Data
b6fb0fd2b9 docs: more documentation improvements and fixes 2024-12-04 09:56:42 -07:00
Upstream Data
46788e7d14 docs: use different docs theme, update docs and examples, and improve docs build 2024-12-04 09:46:01 -07:00
Upstream Data
5b4f84a241 refactor: improve handling of user_suffix in pools 2024-12-04 09:43:01 -07:00
Upstream Data
0c56bfdf9e bug: fix vnish appending scheme to nonexistant pool 2024-12-04 09:32:05 -07:00
Upstream Data
4a5d793cd6 version: bump version number 2024-12-02 15:14:36 -07:00
Upstream Data
1894ff1aea feature: add hiveon web API 2024-12-02 15:14:23 -07:00
Upstream Data
3ab9294000 version: bump version number 2024-12-02 15:12:19 -07:00
Upstream Data
5e0641634b bug: fix MRO for hiveon 2024-12-02 15:11:59 -07:00
Upstream Data
a1975bc9b8 version: bump version number 2024-12-02 13:43:09 -07:00
kdmukai
6a265f03f7 cleanup debugging 2024-12-02 13:42:42 -07:00
Upstream Data
c3658f028f version: bump version number 2024-12-02 10:34:08 -07:00
Upstream Data
ba3c653a29 bug: fix chains: [] which doesnt work with vnish 2024-12-02 10:33:53 -07:00
Upstream Data
61fbc132ed version: bump version number 2024-12-02 10:31:15 -07:00
Upstream Data
3f9f232990 bug: fix pool URL for vnish parser 2024-12-02 10:30:57 -07:00
Upstream Data
29c2398846 version: bump version number 2024-12-02 10:16:23 -07:00
Upstream Data
ecc161820d bug: fix vnish overclock setting 2024-12-02 10:16:04 -07:00
Upstream Data
5fec3052f6 version: bump version number 2024-12-02 09:22:18 -07:00
Upstream Data
437ee774ab bug: type convert to int for vnish config 2024-12-02 09:22:00 -07:00
Upstream Data
aed9e0e406 version: bump version number 2024-12-02 09:14:05 -07:00
Upstream Data
be96428823 bug: skip vnish boards with 0 freq 2024-12-02 09:13:46 -07:00
Upstream Data
446881b237 version: bump version number 2024-12-02 09:00:15 -07:00
Upstream Data
ceab8e55b5 feature: add send_config support for vnish 2024-12-02 08:59:58 -07:00
Upstream Data
e12f85c94d version: bump version number 2024-11-28 15:09:28 -07:00
Upstream Data
0c85f53177 bug: fix some issues with pool URLs 2024-11-28 15:05:04 -07:00
Upstream Data
0b524f9bd0 version: bump version number 2024-11-28 14:40:01 -07:00
Upstream Data
95db852636 docs: update docs 2024-11-28 14:39:46 -07:00
Upstream Data
93fa02412a feature: add support for Hiveon S19j Pro 2024-11-28 14:38:30 -07:00
Upstream Data
edb77e9cd8 bug: fix hiveon identification 2024-11-28 14:33:52 -07:00
Upstream Data
cbf7eeb08d version: bump version number 2024-11-26 08:26:26 -07:00
Upstream Data
d34b35a82d bug: add luxos.supports_shutdown value 2024-11-26 08:25:25 -07:00
Upstream Data
5d57f35475 bug: fix possible case where unidentified miner type can raise and error 2024-11-25 13:00:49 -07:00
Brett Rowan
c95491ea45 version: bump version number 2024-11-22 10:49:47 -07:00
Brett Rowan
e9ec43fac9 bug: fix some more issues with type hints causing warnings 2024-11-22 10:49:24 -07:00
Brett Rowan
42bde081c4 bug: fix some issues with type hints causing warnings 2024-11-22 10:44:09 -07:00
Brett Rowan
bfb72aec1b bug: fix LookupError with AntminerOld 2024-11-22 10:41:34 -07:00
Brett Rowan
b2f36b2f0b bug: fix type hints 2024-11-22 10:41:12 -07:00
Upstream Data
f75c07401b refactor: remove unused imports 2024-11-21 15:32:30 -07:00
Upstream Data
01b96227e0 refactor: more optimizations to hashrate types with metaclass 2024-11-21 15:30:01 -07:00
Upstream Data
82552390c8 refactor: optimize hashrate algo units slightly 2024-11-21 14:55:04 -07:00
Upstream Data
b0651e26b8 version: bump version number 2024-11-21 13:44:48 -07:00
Brett Rowan
c00802e311 feature: add alternate algorithm handlers (#240)
* feature: handle all hashrate algorithm conversions for antminers

* feature: handle all hashrate algorithm conversions for auradine

* feature: handle all hashrate algorithm conversions for avalonminers

* feature: handle all hashrate algorithm conversions for bitaxe

* feature: handle all hashrate algorithm conversions for epic

* feature: handle all hashrate algorithm conversions for goldshell

* refactor: clean up imports

* feature: handle all hashrate algorithm conversions for hammer

* feature: handle all hashrate algorithm conversions for iceriver

* feature: handle all hashrate algorithm conversions for innosilicon

* feature: handle all hashrate algorithm conversions for whatsminer

* tests: update tests to check if miners have board, fan, and algo values

* feature: finish updating all miners with boards, fans, and algos

* feature: update algorithm default values

* feature: add algorithm hashrate values

* feature: improve hashrate types, and use `self.algo` inside miners

---------

Co-authored-by: Upstream Data <brett@upstreamdata.ca>
2024-11-21 13:44:17 -07:00
Brett Rowan
d66739e2c9 feature: swap from @dataclass to pydantic BaseModel (#238)
* feature: switch almost everything to pydantic BaseModel

* feature: swap more dataclasses over to pydantic models

* feature: use more model serializers to make data handle better

* bug: fix some serialization issues with `None` values

* bug: fix some initialization problems with miner mode config

* bug: fix new BOS+ pool parsing

* bug: fix new BOS+ board temperature parsing serialization error

* bug: more misc fixes with serialization, extra methods, and hashrate types

* bug: add explicit type conversions to hashrate types

* bug: fix epic pool URL parsing

* bug: fix positional args in hashboards

* bug: fix epic missing url scheme

* convert board temp to int

---------

Co-authored-by: Upstream Data <brett@upstreamdata.ca>
Co-authored-by: John-Paul Compagnone <jpcompagnone@epicblockchain.io>
2024-11-20 13:42:41 -07:00
Upstream Data
65ed565220 tests: add hammer miner tests 2024-11-20 10:22:53 -07:00
Upstream Data
db6499800b bug: fix raising warnings for partially supported None miners 2024-11-19 14:23:23 -07:00
Upstream Data
cc97ceee61 version: bump version number 2024-11-18 09:01:59 -07:00
Upstream Data
3fa1cb18d9 feature: add support for antminer D7 2024-11-18 08:22:30 -07:00
Upstream Data
cb3c50d007 version: bump version number 2024-11-14 11:16:25 -07:00
Upstream Data
2523ef8484 bug: fix some issues with hammer miners 2024-11-14 11:16:09 -07:00
Upstream Data
01342738b0 version: bump version number 2024-11-14 10:26:50 -07:00
Upstream Data
a9dee4a911 feature: add support for bitaxe gamma 2024-11-14 10:26:00 -07:00
Upstream Data
883ffe20b4 bug: fix bmminer subclass pools data location 2024-11-14 10:25:38 -07:00
Upstream Data
261527a380 feature: add support for hammer D10 and hammer discovery 2024-11-14 08:45:59 -07:00
Upstream Data
924b62e0d5 feature: add support for hammer miner 2024-11-14 08:45:59 -07:00
Temi
76a870c2ed feat: Add _get_pools method for Bmminer. (#233)
* backends: Add _get_pools for Bmminer

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-11-13 10:18:07 -07:00
Upstream Data
309356243b version: bump version number 2024-11-12 14:28:51 -07:00
Upstream Data
e9b4cc9bd6 feature: add Antminer D9 support 2024-11-12 14:28:31 -07:00
Upstream Data
648c54de93 bug: add iceriver KS5 chip count 2024-11-12 14:25:13 -07:00
Upstream Data
e1ce96ab1b bug: add innosilicon A11 chip count 2024-11-12 14:24:05 -07:00
Brett Rowan
86860a8dc4 version: bump version number 2024-11-08 09:18:34 -07:00
Jacob Roy
5212641f45 add json serialization to the Scheme class (#232) 2024-11-06 15:13:30 -07:00
Upstream Data
52432e6043 version: bump version number 2024-11-06 09:06:11 -07:00
Upstream Data
727e484860 docs: update docs 2024-11-06 09:05:08 -07:00
Upstream Data
6c091756d2 feature: add support for Iceriver KS5 and submodels 2024-11-06 09:04:38 -07:00
Upstream Data
14533ce4fe version: bump version number 2024-11-05 09:46:35 -07:00
Upstream Data
82d1840039 bug: fix inf and nan in factory 2024-11-05 09:46:11 -07:00
Brett Rowan
8e6240cdba feature: LuxOS fixes and updates (#192)
* feature: add luxos tuner support to config.

* feature: add luxos temp control support to config.

* bug: fix failure to identify luxOS miners sometimes.

* feature: add get_config with temperature parsing.

* bug: fix some handling in hashboards.

* feature: add API version and fw version.

* refactor: improve RPC api handling.

* refactor: remove useless code, and tag bug.

* feature: add fault light check support.

* refactor: improve fanset compatibility.

* feature: add fan config parsing.

* feature: add pools parsing from luxos.

---------

Co-authored-by: Upstream Data <brett@upstreamdata.ca>
2024-11-05 09:43:34 -07:00
pre-commit-ci[bot]
5749e173d1 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.5.0 → v5.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.5.0...v5.0.0)
- [github.com/psf/black: 24.3.0 → 24.10.0](https://github.com/psf/black/compare/24.3.0...24.10.0)
2024-11-05 09:38:40 -07:00
Upstream Data
7d682b62ac version: bump version number 2024-11-05 09:37:18 -07:00
Upstream Data
6739a1001f docs: update supported types 2024-11-05 09:36:58 -07:00
Upstream Data
56e4a5307f feature: add support for Antminer K7 2024-11-05 09:36:27 -07:00
Upstream Data
88de27c9e7 feature: add support for Whatsminer M50VH90 2024-11-05 09:32:30 -07:00
Upstream Data
a77113c4db feature: add support for Innosilicon A11 2024-11-05 09:27:15 -07:00
Upstream Data
c19945bb82 feature: add support for Vnish S19j Pro BB 2024-11-05 09:22:11 -07:00
Upstream Data
1756937d20 feature: add support for Antminer Z15 Pro 2024-11-05 09:18:04 -07:00
Upstream Data
c7b7fe864b feature: improve vnish is_mining functionality
Fixes #225
2024-11-05 09:12:13 -07:00
John-Paul Compagnone
e7ebefd1bf style fix 2024-11-04 09:13:57 -07:00
John-Paul Compagnone
4677efbc46 fix typo for marathon backend 2024-11-04 09:13:57 -07:00
Brett Rowan
4b7a1a0495 bug: fix lockfile failing release 2024-11-01 16:05:59 -06:00
Brett Rowan
cc4e7da4e5 version: bump version number 2024-11-01 16:02:35 -06:00
Brett Rowan
a3d2d7d35e feature: add web parsing for luxOS type 2024-11-01 16:02:15 -06:00
Brett Rowan
d67de98bd0 version: bump version number 2024-11-01 10:52:04 -06:00
Brett Rowan
fd1a3e459b bug: reset betterproto version so that it can be built for pypi 2024-11-01 10:51:49 -06:00
Brett Rowan
adcab694b5 version: bump version number. 2024-11-01 10:46:59 -06:00
Brett Rowan
2bb097272f fix: use git version of better proto for compatibility with home assistant 2024-11-01 10:46:45 -06:00
Upstream Data
896968dded version: bump version number 2024-10-30 14:48:41 -06:00
Upstream Data
56b8f7c5b3 feature: parse iceriver config 2024-10-30 14:48:15 -06:00
Upstream Data
0ed7559aef version: bump version number 2024-10-30 14:37:47 -06:00
Upstream Data
275d87e4fe bug: fix AntminerOld board parsing 2024-10-30 14:37:19 -06:00
Upstream Data
c3ab814d77 version: bump version number 2024-10-30 14:08:38 -06:00
Upstream Data
05a8569205 bug: fix some calcuation errors with pool info 2024-10-30 14:08:22 -06:00
Upstream Data
b098cb8136 version: bump version number 2024-10-30 13:40:44 -06:00
Upstream Data
75fe7857e4 feature: add iceriver pool metrics 2024-10-30 13:39:22 -06:00
Upstream Data
66797aced1 ci: remove deprecated stages arg from pre-commit 2024-10-30 13:20:41 -06:00
Upstream Data
4a71e38078 ci: fix test framework name 2024-10-30 13:19:46 -06:00
Upstream Data
9fb07e4fa3 ci: skip pre-commit CI running pytest 2024-10-30 13:19:12 -06:00
Upstream Data
74792771ec version: bump version number 2024-10-30 13:16:22 -06:00
Upstream Data
fa6e8a976d bug: fix iceriver userpanel parsing 2024-10-30 13:16:07 -06:00
James Hilliard
f20531cff5 Run pre-commit formatting on all files 2024-10-30 13:07:57 -06:00
Upstream Data
8b1cbed9ce version: bump version number. 2024-10-30 12:25:47 -06:00
Upstream Data
0194e13427 bug: update A11MX chip count 2024-10-30 12:25:32 -06:00
Upstream Data
82d71abf54 version: bump version number 2024-10-30 12:23:08 -06:00
Upstream Data
e71cfadf6e bug: add model parser into map for iceriver 2024-10-30 12:22:44 -06:00
Upstream Data
18931c4e98 version: bump version number 2024-10-30 12:18:53 -06:00
Upstream Data
8622c080aa bug: fix inno pool parsing 2024-10-30 12:18:27 -06:00
Upstream Data
cb71b2a593 docs: update supported miners 2024-10-30 10:44:37 -06:00
Upstream Data
ff5956da41 version: bump version number 2024-10-30 10:32:48 -06:00
Upstream Data
acdafc2efd bug: fix hashboard innosilicon model selection 2024-10-30 10:32:29 -06:00
Upstream Data
b8874092ad bug: fix hashboard count on A11MX 2024-10-30 10:07:59 -06:00
Upstream Data
ad28ba0b3e version: bump version number 2024-10-30 09:27:54 -06:00
Upstream Data
0d90b60eef feature: add the rest of the iceriver models 2024-10-30 09:27:12 -06:00
Upstream Data
7c18c9f69c feature: improve iceriver support and add support for KS3M 2024-10-30 09:21:12 -06:00
Upstream Data
975560f46f feature: add iceriver type parsing 2024-10-30 09:12:54 -06:00
Upstream Data
bfe9cbf7d9 bug: fix iceriver miners being identified as bitaxe 2024-10-30 08:54:27 -06:00
Upstream Data
ccb5eb73db version: bump version number 2024-10-30 08:49:25 -06:00
Upstream Data
d143667bd6 feature: add warning message when instantiating an unsupported miner type 2024-10-30 08:49:01 -06:00
Upstream Data
87d809abc0 bug: update KS3 fan count 2024-10-30 08:44:38 -06:00
Upstream Data
4dc5b1a541 feature: add chip count for WM M60VK20 2024-10-30 08:44:08 -06:00
Upstream Data
ddd3e867f9 feature: add stratum+ssl pool url scheme 2024-10-30 08:41:35 -06:00
Upstream Data
77480d3d69 feature: add support for antminer KS5 2024-10-30 08:39:05 -06:00
Upstream Data
0767c93002 feature: add support for antminer KS3 2024-10-30 08:33:59 -06:00
Upstream Data
e690e6dd3b version: bump version number 2024-10-29 16:16:13 -06:00
James Hilliard
d4665ed768 Update betterproto and regenerate protoc files
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
2024-10-29 16:15:30 -06:00
James Hilliard
b90a92c0df Update betterproto and regenerate protoc files
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
2024-10-29 16:15:11 -06:00
Upstream Data
50cfcf9796 version: bump version number 2024-10-29 09:56:30 -06:00
Brett Rowan
5d204f09da Merge pull request #213 from jameshilliard/update-deps
Update dependencices
2024-10-29 09:56:07 -06:00
James Hilliard
4c0410322f Update dependencices 2024-10-29 09:53:33 -06:00
Upstream Data
fbb2b3f6e7 version: bump version number 2024-10-29 09:46:03 -06:00
Upstream Data
0f09fb49fc bug: fix inf and nan parsing issues by replacing them with 0 2024-10-29 09:35:19 -06:00
Upstream Data
b0d063d6ed feature: add support for Inno A11MX (no chip counts) 2024-10-29 09:15:57 -06:00
Upstream Data
a68fe70af4 bug: fix pool parsing failing with no scheme 2024-10-29 08:57:43 -06:00
Upstream Data
43c7ac281b feature: add support for KA3 2024-10-29 08:29:09 -06:00
Upstream Data
a97ae55a06 version: bump version number 2024-10-28 08:18:52 -06:00
Upstream Data
4a3a6f4186 feature: add get_mac for bitaxe 2024-10-28 08:18:15 -06:00
Brett Rowan
f976724ada version: bump version number 2024-10-25 14:12:34 -06:00
Brett Rowan
2632bdaa30 Merge pull request #208 from eandersson/braiin_fix 2024-10-25 14:11:33 -06:00
Erik Olof Gunnar Andersson
91016d7b8c Fix issue with BraiinsOS health check failing 2024-10-25 22:04:34 +02:00
Upstream Data
2b00e741ca version: bump version number
Fixes: #206
2024-10-08 08:16:25 -06:00
Upstream Data
d496c11d67 bug: fix some cases where Antminer online status couldnt be parsed
Re: #206
2024-10-08 08:16:25 -06:00
Upstream Data
5880223517 bug: fix goldshell issues with pools data 2024-10-08 08:16:25 -06:00
Brett Rowan
394a5dcd0d Merge pull request #204 from Ytemiloluwa/BFGMiner
feat: Add _get_pools method for BFGMiner(StockFirmware)
2024-10-01 08:49:40 -06:00
Upstream Data
7365275f46 version: bump version number. 2024-09-24 12:51:17 -06:00
Upstream Data
0ecab5fdd4 bug: fix an issue with moving board slots on BOS+. 2024-09-24 12:50:56 -06:00
ytemiloluwa
ed0d9f73e4 backends: add _get_pools method to bfgminer 2024-09-19 09:05:29 +01:00
Upstream Data
28f4e16662 version: bump version number. 2024-09-18 13:16:51 -06:00
Upstream Data
b9b0bff946 bug: pin betterproto version to avoid errors with unset oneof variants 2024-09-18 13:16:28 -06:00
Upstream Data
790718a5df bug: fix some issues with BOS+ calls. 2024-09-18 13:05:08 -06:00
Brett Rowan
96a0301f5e Merge pull request #203 from Ytemiloluwa/BTMiner
feat: Add _get_pools method for BTMiner(StockFirmware)
2024-09-17 11:30:14 -06:00
ytemiloluwa
c57b019b7d backends: add _get_pools to BTMiner 2024-09-17 08:55:09 +01:00
Brett Rowan
af920c4dda version: bump version number 2024-09-12 17:28:19 -06:00
Brett Rowan
f3d11788ed bug: fix missing await calls
Fixes #201
2024-09-12 17:27:57 -06:00
Brett Rowan
fd0e02af59 feature: add support for BOSMinerT21 2024-09-12 17:19:08 -06:00
Brett Rowan
2a6c51d52c Merge pull request #188 from Ytemiloluwa/marathon
feat: add _get_pools method for marathon miner
2024-09-04 08:38:29 -06:00
ytemiloluwa
2d62e2070b pool: highest priority 2024-09-04 15:21:39 +01:00
ytemiloluwa
b143bd70f0 updated keys 2024-09-03 22:49:55 +01:00
ytemiloluwa
605509c57c updated keys 2024-09-03 21:35:14 +01:00
Brett Rowan
7036137b23 Merge pull request #189 from 1e9abhi1e10/luxminer_firmware 2024-09-02 22:14:15 -06:00
1e9abhi1e10
7a9ff535b4 Refactor upgrade_firmware to maintain bool return type 2024-09-03 09:42:08 +05:30
Brett Rowan
f185bafe2a version: bump version number. 2024-09-02 21:12:56 -06:00
Brett Rowan
ab81d5d020 feature: add some more whatsminer chip counts. 2024-09-02 21:12:37 -06:00
1e9abhi1e10
0965e6489b return status message in upgrade_firmware function 2024-09-02 23:43:17 +05:30
ytemiloluwa
792e1c9cad corrected parsing 2024-09-02 09:27:30 +01:00
Brett Rowan
a6721f971a version: bump version number. 2024-09-01 16:49:26 -06:00
Brett Rowan
8113d0e4e0 bug: remove print statement. 2024-09-01 16:49:07 -06:00
Brett Rowan
e3c7d3f8a2 version: bump version number. 2024-09-01 16:48:15 -06:00
Brett Rowan
6415de8c73 bug: fix more parsing issues. 2024-09-01 16:47:53 -06:00
Brett Rowan
f2838cf31d bug: fix avalon nano parsing. 2024-09-01 16:41:28 -06:00
Brett Rowan
fbd49b370d version: bump version number. 2024-09-01 16:23:33 -06:00
Brett Rowan
79f7296576 bug: fix some issues with avalonminer parsing. 2024-09-01 16:22:59 -06:00
Brett Rowan
76f4ca5f89 version: bump version number. 2024-09-01 13:22:32 -06:00
Brett Rowan
477acda1c1 feature: add support for Avalon Nano 3. 2024-09-01 13:21:53 -06:00
Brett Rowan
a57f343dcc version: bump version number. 2024-09-01 10:05:01 -06:00
Brett Rowan
36e9201ed4 bug: fix false positives as VNish before checking other firmware types. 2024-09-01 10:04:31 -06:00
Brett Rowan
c1525501d4 Merge pull request #190 from UpstreamData/dev_iceriver
feature: Add iceriver support
2024-09-01 09:53:39 -06:00
Brett Rowan
e4bb90a569 Merge pull request #187 from 1e9abhi1e10/antminer_firmware
feat: Add update firmware for Antminer
2024-09-01 09:52:02 -06:00
1e9abhi1e10
28642cc521 Refactor firmware upgrade process 2024-08-27 02:34:23 +05:30
Brett Rowan
beae79ddec version: bump version number. 2024-08-25 10:36:32 -06:00
Brett Rowan
f02e10ab3d bug: fix token not needing to be passed to upgrade wm firmware. 2024-08-25 10:36:11 -06:00
Brett Rowan
d0b9dff476 version: bump version number. 2024-08-25 09:28:46 -06:00
Brett Rowan
501e290839 bug: fix a bug where whatsminers could raise a cascading TimeoutError. 2024-08-25 09:28:27 -06:00
Brett Rowan
a0daf37f80 bug: fix some miners not having matching params due to inheritance. 2024-08-25 09:28:17 -06:00
Brett Rowan
8111b1ff4b refactor: simplify some bad code in scan_network_generator 2024-08-25 09:13:02 -06:00
Brett Rowan
754087afd6 Merge pull request #195 from Ytemiloluwa/CGMiner
feat: Add _get_pools method for CGMiner (StockFirmware)
2024-08-23 14:57:35 -06:00
ytemiloluwa
5e16b6092c backends: add _get_pools for CGMiner 2024-08-24 00:51:10 +04:00
1e9abhi1e10
21636a75fa made upgrade_firmware to return boolean result 2024-08-23 12:45:20 +05:30
Brett Rowan
f124f5422a Merge pull request #194 from jameshilliard/remove-struct 2024-08-22 17:55:52 -06:00
James Hilliard
1e5d1a2528 Cleanup unused struct import 2024-08-22 17:53:54 -06:00
Brett Rowan
1fcef07902 version: bump version number. 2024-08-22 17:39:27 -06:00
Brett Rowan
41e7dd8056 docs: update docs. 2024-08-22 17:39:01 -06:00
Brett Rowan
dccc35db5f Merge pull request #193 from jameshilliard/remove-solinger
Remove horribly broken SO_LINGER socket options
2024-08-22 17:38:18 -06:00
James Hilliard
0cfe59aa34 Remove horribly broken SO_LINGER socket options 2024-08-22 17:35:16 -06:00
1e9abhi1e10
6fdd156fa3 Added upgraderun in rpc/luxminer 2024-08-21 01:06:50 +05:30
Upstream Data
e9fcf25ad3 docs: update docs with iceriver support. 2024-08-20 10:24:06 -06:00
Brett Rowan
a9422165ca Merge pull request #191 from UpstreamData/dev_mara
feature: add mara rpc API.
2024-08-20 10:21:20 -06:00
Upstream Data
0ea5ee8239 feature: add more iceriver functionality. 2024-08-20 10:16:35 -06:00
Upstream Data
fba25cba61 feature: add a couple iceriver data gathering functions. 2024-08-20 09:59:33 -06:00
Upstream Data
343b5a1c50 feature: add basic iceriver framework. 2024-08-20 09:45:31 -06:00
Upstream Data
63522aad81 feature: add mara rpc API. 2024-08-20 08:37:40 -06:00
1e9abhi1e10
b957aa7fba feat: Add update firmware for LuxOS Miner 2024-08-20 16:12:33 +05:30
ytemiloluwa
a71aa6868a backends: add _get_pools to marathon 2024-08-19 07:08:22 +01:00
1e9abhi1e10
6b50bf0cf7 Fix some minor issues 2024-08-18 01:45:03 +05:30
1e9abhi1e10
d00444ec56 feat: Add update firmware for Antminer 2024-08-18 01:18:42 +05:30
Brett Rowan
e7ed39fe39 Merge pull request #157 from 1e9abhi1e10/update_firmware_2 2024-08-13 12:03:38 -06:00
Upstream Data
168d68d0b2 version: fix bad version number. 2024-08-13 09:24:37 -06:00
Upstream Data
63cddfdde3 version: bump version number. 2024-08-13 09:13:49 -06:00
JP Compagnone
4a642fd3da add s21 pro support for stock, ePIC (#186) 2024-08-09 10:18:14 -06:00
Brett Rowan
13c0407b2d Merge pull request #185 from jameshilliard/toml
Use builtin tomllib where possible and tomli{-w} where not.
2024-08-08 08:18:35 -06:00
James Hilliard
794ed6d103 Use builtin tomllib where possible and tomli{-w} where not. 2024-08-07 15:19:22 -06:00
Upstream Data
d0aeb5a6ce version: bump version number. 2024-08-07 11:40:46 -06:00
Brett Rowan
030f8c6079 Merge pull request #184 from jameshilliard/update-deps
Update dependencies and make versions less strict
2024-08-07 11:21:58 -06:00
James Hilliard
7195e204ce Update dependencies and make versions less strict 2024-08-07 11:18:45 -06:00
1e9abhi1e10
962a328219 Fixes result check 2024-07-31 13:23:37 +05:30
Upstream Data
1cec2ca7f3 version: bump version number. 2024-07-30 15:32:20 -06:00
Brett Rowan
a3c4187411 Merge pull request #162 from Ytemiloluwa/BOser
feat: Add _get_pools method to BOSer backend class.
2024-07-30 15:32:02 -06:00
ytemiloluwa
18a2df5d9b replaced getattr with getitem 2024-07-30 22:20:13 +01:00
Upstream Data
6d66c793cb version: bump version number. 2024-07-30 14:14:36 -06:00
Upstream Data
b434c8df1a feature: add support for antminer S19 Pro Plus Hydro. 2024-07-30 13:27:06 -06:00
Upstream Data
2b8fa2fc2b bug: Handle default case with boser power conf. 2024-07-30 13:22:47 -06:00
Upstream Data
1497d2abea bug: add user suffix to boser send_config. 2024-07-30 13:10:12 -06:00
Upstream Data
a2ca79843d feature: implement send_config method for boser. 2024-07-30 13:09:16 -06:00
Upstream Data
f6500e7d66 version: bump version number. 2024-07-29 09:53:52 -06:00
Upstream Data
ea2fd0fc9a feature: add braiinsOS+ pool configuration. 2024-07-29 09:53:02 -06:00
Upstream Data
e2cbd30a99 feature: update braiins proto files. 2024-07-29 09:38:57 -06:00
Upstream Data
151ea44b10 docs: fix settings documentation. 2024-07-29 09:11:15 -06:00
Brett Rowan
6487a0b08e Merge pull request #179 from tydal-borge/patch-1
documentation: Changed settings key in readme to reflect default values
2024-07-29 09:08:39 -06:00
Brett Rowan
552fdf9ec0 Merge pull request #178 from tydal-borge/dev_antminer_customauth
bug: Add custom auth to Digest of AntMiner model check
2024-07-29 09:08:17 -06:00
Børge Holm-Wennberg
00cf1449f9 docs for settings mismatches 2024-07-29 10:45:22 +02:00
Børge Holm-Wennberg
8ec88e385a Remove leftover print of config 2024-07-29 10:41:20 +02:00
tydal-borge
cc29b2960a Changed settings key to reflect default values
Also see issue #106  for details
2024-07-29 10:28:39 +02:00
Børge Holm-Wennberg
568ffd67c4 Add custom auth to Digest of AntMiner model check 2024-07-29 09:47:19 +02:00
1e9abhi1e10
4b4670201a Backed some previous changes 2024-07-27 23:58:57 +05:30
1e9abhi1e10
92f70c9a76 Add keep_settings arg and other reviews 2024-07-27 23:55:50 +05:30
Brett Rowan
1d2dc3fddf Merge pull request #175 from Ytemiloluwa/Innosilicon 2024-07-26 07:18:32 -06:00
ytemiloluwa
c44150fd15 APICommand: web to rpc 2024-07-26 10:22:28 +01:00
1e9abhi1e10
8664b53991 Fix request handling 2024-07-26 05:30:42 +05:30
Abhishek Patidar
31aeca2340 Merge branch 'master' into update_firmware_2 2024-07-26 05:27:30 +05:30
ytemiloluwa
34eec3ff2e backends: add _get_pools to Innosilicon 2024-07-25 13:11:28 +01:00
Brett Rowan
e1416b5a4b Merge pull request #173
feature: add support for Vnish S19 Pro Hydro.
2024-07-12 09:59:57 -06:00
Brett Rowan
3ca75729b9 feature: add support for Vnish S19 Pro Hydro. 2024-07-12 09:59:03 -06:00
Brett Rowan
73031eea65 Merge pull request #163 from 1e9abhi1e10/update_firmware_4 2024-07-11 09:59:15 -06:00
Brett Rowan
1643c5b7ee Merge pull request #172 from UpstreamData/snyk-fix-645b55b0f4651537ebb3c1b9e8d9b811 2024-07-10 09:08:19 -06:00
snyk-bot
ca5db726bd fix: docs/requirements.txt to reduce vulnerabilities
The following vulnerabilities are fixed by pinning transitive dependencies:
- https://snyk.io/vuln/SNYK-PYTHON-ZIPP-7430899
2024-07-10 07:56:03 +00:00
Brett Rowan
4bb4d32b48 Merge pull request #171 from Ytemiloluwa/LuxMiner 2024-07-08 09:00:17 -06:00
ytemiloluwa
fec7a89807 backends: add _get_pools method to luxminer 2024-07-08 15:00:57 +01:00
Upstream Data
db2615a4eb version: bump version number. 2024-07-05 08:57:00 -06:00
Upstream Data
eea5d5ba2a bug: fix dataclass ordering issues and bitaxe issues. 2024-07-05 08:56:36 -06:00
Brett Rowan
f405bbff4d Merge pull request #168 from Ytemiloluwa/BOSMinerPoolUrl 2024-07-03 08:34:42 -06:00
ytemiloluwa
dd8d895b50 Backends: updated BOSMiner _get_pools to include PoolUrl dataclass. 2024-07-03 07:30:30 +01:00
Brett Rowan
dff4e98523 Merge pull request #167 from Ytemiloluwa/Antminer 2024-07-02 22:14:10 -06:00
ytemiloluwa
846bbb9033 Backends: updated BMMiner _get_pools to include PoolUrl dataclass. 2024-07-03 04:55:26 +01:00
1e9abhi1e10
e6f9a33b3c Removed trailing whitespace 2024-07-03 08:50:50 +05:30
1e9abhi1e10
092126bded Added checksum validation and command handling 2024-07-03 08:43:22 +05:30
upstreamdata
e5d5cb4dab version: bump version number. 2024-07-02 15:06:03 -06:00
upstreamdata
bd76966d3a docs: update docs nav. 2024-07-02 15:05:45 -06:00
upstreamdata
d46908a298 docs: update docs. 2024-07-02 15:03:26 -06:00
Brett Rowan
e4cec021b0 Merge pull request #164 from Ytemiloluwa/poolURL 2024-07-02 08:46:48 -06:00
upstreamdata
42d2d975db feature: add firmware type to bitaxe. 2024-07-01 23:11:26 -06:00
upstreamdata
427f91d677 bug: use default chip count for bitaxe when asicCount is not set. 2024-07-01 23:08:31 -06:00
upstreamdata
7a9c9237a3 bug: fix bitaxe not identifying on some versions, switch to using ASICModel key. 2024-06-30 22:03:50 -06:00
ytemiloluwa
9b431b020f method: from_str 2024-06-30 18:20:41 +01:00
upstreamdata
ee1eece181 feature: add config sending for bitaxe. 2024-06-29 15:12:33 -06:00
upstreamdata
3627194f34 feature: add config parsing from bitaxe. 2024-06-29 14:59:27 -06:00
ytemiloluwa
65cfb57605 PEP8: case fix 2024-06-29 17:40:15 +01:00
ytemiloluwa
8e4a547c77 dataclass: PoolUrl 2024-06-29 17:40:14 +01:00
ytemiloluwa
a751efe7d5 dataclass: PoolUrl 2024-06-29 17:40:14 +01:00
Brett Rowan
e859895261 Merge pull request #166 from UpstreamData/dev_bitaxe
feature: Add basic bitaxe support.
2024-06-29 08:42:40 -06:00
1e9abhi1e10
ae3d38603a Removed unused import 2024-06-29 14:29:48 +05:30
upstreamdata
fca72eb747 bug: fix some of the issues with bitaxe. 2024-06-28 22:43:13 -06:00
Brett Rowan
923e963369 feature: basic bitaxe support. 2024-06-28 09:09:42 -06:00
Brett Rowan
7a3c9a3460 refactor: fix hashrate return typing. 2024-06-28 08:35:27 -06:00
1e9abhi1e10
e649348af2 used web attribute and removed some redundant changes from the firmware.py 2024-06-27 03:43:33 +05:30
1e9abhi1e10
ba58e80ec3 Add keep_setting arg in miners/base.py/BaseMiner/upgrade_firmware 2024-06-27 02:21:24 +05:30
1e9abhi1e10
45e2c9a403 modified upgrade_firmware for all subclasses 2024-06-26 19:06:51 +05:30
1e9abhi1e10
bd9592c19c Use web attribute 2024-06-23 08:38:35 +05:30
ytemiloluwa
1bb597999d backends: updated _get_pools arg in BOSer 2024-06-22 19:06:14 +01:00
1e9abhi1e10
7803fa60f2 removed trailing whitespace 2024-06-22 08:12:03 +05:30
1e9abhi1e10
4adb7dc92c feat: Add update firmware for ePIC miner 2024-06-22 08:06:44 +05:30
Abhishek Patidar
ba69a1de2c Merge branch 'master' into update_firmware_2 2024-06-22 07:57:48 +05:30
ytemiloluwa
64265206c2 backends: updated _get_pools in BOSer 2024-06-19 09:25:35 +01:00
ytemiloluwa
eec8f66b81 backends: _get_pools in BOSer 2024-06-18 14:22:30 +01:00
1e9abhi1e10
999e8ef318 Made consistent API calls 2024-06-15 17:44:20 +05:30
Brett Rowan
30f385c2d9 Merge pull request #158 from 1e9abhi1e10/update_firmware_3
feat: Add update firmware for Whatsminer
2024-06-13 13:10:24 -06:00
1e9abhi1e10
87377fbe4c Use the rpc update_firmware method 2024-06-12 22:23:43 +05:30
1e9abhi1e10
2a66602c2c Implement upgrade_firmware and make necessary changes according to the reviews. 2024-06-12 08:45:46 +05:30
Brett Rowan
8cc18ca272 Merge pull request #161 from jpcomps/add_board_info 2024-06-11 12:15:33 -06:00
John-Paul Compagnone
677db8fd0d add active field 2024-06-11 14:14:22 -04:00
John-Paul Compagnone
a458adc45f change default for tuned 2024-06-11 11:28:28 -04:00
John-Paul Compagnone
5a09ddcb04 remove latency 2024-06-11 11:13:50 -04:00
John-Paul Compagnone
4d9fde572e feat: add voltage,tuned status to HB. Add pool_data to ePIC 2024-06-11 11:10:07 -04:00
Brett Rowan
3e4b347506 Merge pull request #160 from UpstreamData/dev
Improved config handling.
2024-06-11 08:46:45 -06:00
Upstream Data
927bbae0c1 Merge remote-tracking branch 'origin/dev' into dev 2024-06-11 08:41:38 -06:00
Upstream Data
7e3e1f19aa bug: fix bad naming for a scaling parameter. 2024-06-11 08:41:27 -06:00
Brett Rowan
5a4b1b6ee1 Merge pull request #159 from Ytemiloluwa/BOSMiner 2024-06-10 21:04:27 -06:00
ytemiloluwa
25767aab8e pools: async/await 2024-06-11 03:44:52 +01:00
ytemiloluwa
b3a0949395 backends: _get_pools in BOSMiner 2024-06-07 14:57:19 +01:00
1e9abhi1e10
18e6fc2a3c Move upgrade_firmware to pyasic.rpc.btminer.py 2024-06-07 06:08:52 +05:30
1e9abhi1e10
4d45b6e50f feat: Add update firmware for Whatsminer 2024-06-07 03:27:34 +05:30
1e9abhi1e10
eefb055a3f Fixed upgrade_firmware for auradine miner 2024-06-07 02:58:09 +05:30
1e9abhi1e10
9c41a6b28f Undo changes for ePIC and BFG miners 2024-06-07 02:21:41 +05:30
1e9abhi1e10
bf0e2e6cfe feat: Add update firmware for BFG miner 2024-06-07 02:12:48 +05:30
1e9abhi1e10
4a2adabe95 feat: Add update firmware for Auradine and ePIC miners 2024-06-07 02:04:16 +05:30
John-Paul Compagnone
4031a42350 add BoardTune and ManualMode to ePIC 2024-06-06 11:23:46 -04:00
Upstream Data
4698a806f0 feature: refactor scaling into mining mode. 2024-06-05 17:11:52 -06:00
Upstream Data
aec53aa5f0 bug: fix some loggin issues. 2024-06-05 10:27:07 -06:00
Upstream Data
e15ddd020c bug: fix missing import. 2024-06-05 10:26:25 -06:00
Upstream Data
6f4aead0d4 bug: fix dependencies. 2024-06-05 10:25:44 -06:00
Upstream Data
6b3bf31597 docs: fix some documentation. 2024-06-05 08:12:58 -06:00
Brett Rowan
2ac118a008 Merge pull request #147 from 1e9abhi1e10/update_firmware_1 2024-06-04 19:08:08 -06:00
1e9abhi1e10
c87880529c Removed updater directory 2024-06-05 06:35:08 +05:30
Brett Rowan
b12766321d Merge pull request #156 from UpstreamData/dev_dps 2024-06-04 17:31:07 -06:00
Upstream Data
3d6bee2d85 feature: rename config.power_scaling to scaling, and add hashrate scaling for boser (missing from parser). 2024-06-04 15:56:44 -06:00
Upstream Data
c8a8315ad0 version: bump version number. 2024-06-04 09:28:15 -06:00
Upstream Data
dac9bcc3de refactor: improve _get_data implementation slightly. 2024-06-04 08:53:25 -06:00
1e9abhi1e10
7688288d05 Improved file structure and add requested changes 2024-06-03 02:46:34 +05:30
Brett Rowan
46621d6b93 Merge pull request #151 from Ytemiloluwa/master 2024-06-02 13:50:51 -06:00
ytemiloluwa
35700f7e57 pools: MinerData 2024-06-02 20:47:58 +01:00
ytemiloluwa
08e6744595 index: unused variable 2024-06-02 07:26:43 +01:00
ytemiloluwa
2de3e5e328 update: _get_pools method 2024-06-02 07:13:39 +01:00
Temi
51f2eb1b1d Merge branch 'UpstreamData:master' into master 2024-06-02 06:51:28 +01:00
1e9abhi1e10
b4faf7c49e Fix code style issues 2024-05-29 18:02:43 +05:30
1e9abhi1e10
26d9562c18 Add structured directories for firmware update 2024-05-29 17:52:01 +05:30
Brett Rowan
d40d92c1ca version: bump version number. 2024-05-28 21:46:41 -06:00
Brett Rowan
7ea63643a9 bug: fix a bunch of spelling mistakes. 2024-05-28 21:46:13 -06:00
1e9abhi1e10
0bd5c22681 Implement a class to handle firmware management tasks 2024-05-29 08:54:13 +05:30
1e9abhi1e10
8f0cf5b3a3 Made some changes in the code based on reviews 2024-05-29 02:05:58 +05:30
1e9abhi1e10
6458a71b5d Add upgrade_firmware for BOS miner. 2024-05-29 01:20:37 +05:30
1e9abhi1e10
dbdd23e37d Moved update_firmware from base.py to braiins_os.py 2024-05-28 16:12:02 +05:30
upstreamdata
313c324771 bug: fix into naming on vnish with expected hashrate. 2024-05-27 15:57:06 -06:00
upstreamdata
a9fd9343d8 feature: add vnish fault light. 2024-05-26 21:59:59 -06:00
upstreamdata
8f41d4d0bc bug: fix MRO with vnish. 2024-05-26 21:59:57 -06:00
ytemiloluwa
521853863b base: _get_pools and get_pools 2024-05-26 13:21:53 +01:00
ytemiloluwa
b7a5a647b3 pools: DATA LOC 2024-05-26 00:36:07 +01:00
ytemiloluwa
4434f9ccad get_data: kwarg key 2024-05-26 00:22:57 +01:00
ytemiloluwa
82a1cc3cfe backends: _get_pools in antminer 2024-05-25 23:08:33 +01:00
1e9abhi1e10
2d92c2c0e2 Replace aiohttp with httpx and add the next steps for update_firmware 2024-05-26 02:22:21 +05:30
Brett Rowan
6f10c91482 Merge pull request #150 from UpstreamData/snyk-fix-c1d73ce3e71f8a7a86f4d2be00564ee4 2024-05-25 09:00:39 -06:00
snyk-bot
f2d6bce165 fix: docs/requirements.txt to reduce vulnerabilities
The following vulnerabilities are fixed by pinning transitive dependencies:
- https://snyk.io/vuln/SNYK-PYTHON-JINJA2-6809379
2024-05-25 02:29:08 +00:00
1e9abhi1e10
1ab05c7a5e Add firmare update funtionality 2024-05-20 23:43:39 +05:30
Brett Rowan
61623cc44d version: bump version number. 2024-05-19 11:41:43 -06:00
Brett Rowan
a30a726324 bug: fix some issues with boser handlers. 2024-05-19 11:41:10 -06:00
Brett Rowan
0e90ad64cd Merge pull request #145 from Ytemiloluwa/master 2024-05-18 11:08:31 -06:00
ytemiloluwa
53572c6236 add new attributes 2024-05-18 16:53:06 +01:00
Brett Rowan
67da56a03b version: bump version number. 2024-05-17 21:06:23 -06:00
Brett Rowan
be8633185d bug: remove StrEnum references. 2024-05-17 21:02:57 -06:00
Brett Rowan
1d656da2a2 bug: remove StrEnum references. 2024-05-17 21:00:43 -06:00
Upstream Data
189deae3d1 version: bump version number. 2024-05-17 09:05:00 -06:00
Brett Rowan
46188ad52b Merge pull request #146 from UpstreamData/fix_typo
fix typo
2024-05-17 09:02:22 -06:00
John-Paul Compagnone
19e232ddb9 fix typo 2024-05-17 11:01:01 -04:00
ytemiloluwa
5d90b7e938 pools: updated metrics dataclass 2024-05-16 20:20:53 +01:00
ytemiloluwa
3f90799544 update metrics dataclass 2024-05-16 19:25:48 +01:00
Temi
1f70ec0d28 Merge branch 'UpstreamData:master' into master 2024-05-16 19:00:45 +01:00
Upstream Data
c26b78aa01 version: bump version number. 2024-05-16 08:27:38 -06:00
Brett Rowan
0debf16f7c Merge pull request #144 from jpcomps/master
ePIC: bug fixes
2024-05-16 08:27:07 -06:00
John-Paul Compagnone
d7f48d8f9f remove tuned from MinerConfig 2024-05-16 10:26:04 -04:00
ytemiloluwa
58c95559dd pools: dataclass metrics 2024-05-16 14:08:00 +01:00
JP Compagnone
03caa9fe94 Merge branch 'UpstreamData:master' into master 2024-05-15 21:03:32 -04:00
John-Paul Compagnone
afd8697f07 change from optimized to tuned, which is more generic for other FW 2024-05-15 21:03:12 -04:00
Upstream Data
fc77aded28 version: bump version number. 2024-05-15 14:21:27 -06:00
Brett Rowan
a5cafd1fb8 Merge pull request #137 from UpstreamData/dev_data
feature: Improve timestamp serialization,  add device_data to MinerData, and use enums for device information
2024-05-15 14:20:16 -06:00
John-Paul Compagnone
91d504fc1c add Vopt status, fix typo 2024-05-14 23:07:34 -04:00
Upstream Data
db0444a8eb tests: fix tests. 2024-05-14 13:36:26 -06:00
Upstream Data
0cab872baf bug: fix zero division cases with miner data. 2024-05-14 13:34:17 -06:00
Upstream Data
7f191eb2fd feature: add __getitem__ to config. 2024-05-14 13:34:16 -06:00
Upstream Data
52adc2553b feature: add keys to miner data. 2024-05-14 13:34:16 -06:00
Upstream Data
de49fd7e95 refactor: Optimize imports. 2024-05-14 13:34:16 -06:00
Upstream Data
7eb61473a8 feature: add custom hashrate types and conversion. 2024-05-14 13:34:14 -06:00
Upstream Data
f6a134342a feature: rename MinerModels to MinerModel, and add device info in as properties of MinerData. 2024-05-14 13:33:12 -06:00
Upstream Data
1d67e5ed68 refactor: clean and optimize imports. 2024-05-14 13:33:12 -06:00
Upstream Data
7d4aa80966 refactor: move models to pyasic.miners.devices 2024-05-14 13:33:12 -06:00
Upstream Data
742dde622b feature: add device models. 2024-05-14 13:33:12 -06:00
Upstream Data
497aa6a42c feature: add expected fans to miner data. 2024-05-14 13:33:10 -06:00
Upstream Data
40ebf42da1 feature: create device_info field for MinerData. 2024-05-14 13:32:12 -06:00
Upstream Data
2f8aea5285 bug: fix as_influx timestamp parsing. 2024-05-14 13:32:12 -06:00
Upstream Data
53f545ba13 feature: save datetime object as private in MinerData, and parse datetime in ISO format along with a timestamp. 2024-05-14 13:32:08 -06:00
Upstream Data
689b34611e version: bump version number. 2024-05-14 08:48:38 -06:00
Brett Rowan
d55c3f45ef Merge pull request #143 from jpcomps/master
feat: add additional ePIC UMC features, add Output Voltage to MinerData
2024-05-14 08:47:00 -06:00
John-Paul Compagnone
5ac533616f missed chiptune 2024-05-14 10:46:26 -04:00
John-Paul Compagnone
96ea5f5d16 remove passing self 2024-05-14 10:41:18 -04:00
John-Paul Compagnone
87526f5efc change target as well to get 2024-05-13 23:54:41 -04:00
John-Paul Compagnone
d31bafbc0e less lines 2024-05-13 23:51:23 -04:00
John-Paul Compagnone
66bae47bb9 seperate these out 2024-05-13 21:26:15 -04:00
John-Paul Compagnone
7a09b66d4e simplify 2024-05-13 21:22:31 -04:00
John-Paul Compagnone
de5932184f use get and cheap way to do full backwards compat 2024-05-13 21:17:48 -04:00
John-Paul Compagnone
2cba62e050 push self into secondary level 2024-05-13 21:03:26 -04:00
John-Paul Compagnone
c7520d98e0 better descriptions 2024-05-13 17:00:02 -04:00
John-Paul Compagnone
92e9f7bc08 fix typo 2024-05-13 16:57:19 -04:00
Upstream Data
e0becce349 bug: fix zero division cases with miner data. 2024-05-13 14:41:37 -06:00
John-Paul Compagnone
a65c4ba215 feat: add voltage param to minerdata 2024-05-13 15:44:12 -04:00
John-Paul Compagnone
4cd0c3357b remove prints 2024-05-12 16:05:08 -04:00
John-Paul Compagnone
d5cabf8af5 fix: fix send_config for epic, add throttle step and min throttle for Vopt 2024-05-12 14:08:12 -04:00
JP Compagnone
3120de757d Merge branch 'UpstreamData:master' into master 2024-05-12 13:20:50 -04:00
Upstream Data
0b69fe591e version: bump version number. 2024-05-10 13:34:00 -06:00
Upstream Data
032288d062 bug: fix k pro identification on latest versions. 2024-05-10 13:33:42 -06:00
Upstream Data
1d6618c1c0 feature: add __getitem__ to config. 2024-05-10 13:08:45 -06:00
Upstream Data
7126e03f0d feature: add keys to miner data. 2024-05-10 12:55:29 -06:00
Upstream Data
c27556c809 refactor: Optimize imports. 2024-05-09 15:04:36 -06:00
Upstream Data
99ff28d3e1 feature: add custom hashrate types and conversion. 2024-05-09 15:01:40 -06:00
Upstream Data
8ad6f60757 feature: rename MinerModels to MinerModel, and add device info in as properties of MinerData. 2024-05-09 12:48:30 -06:00
Brett Rowan
5f67b987a0 Merge pull request #139 from UpstreamData/snyk-fix-77dddc60686385a842810025bed37669
[Snyk] Security upgrade jinja2 from 3.1.2 to 3.1.4
2024-05-09 12:26:13 -06:00
snyk-bot
5842b3c4aa fix: docs/requirements.txt to reduce vulnerabilities
The following vulnerabilities are fixed by pinning transitive dependencies:
- https://snyk.io/vuln/SNYK-PYTHON-JINJA2-6809379
2024-05-08 20:27:28 +00:00
Upstream Data
e2e1d2f2fd version: bump version number. 2024-05-06 14:43:19 -06:00
Upstream Data
dd205c0f06 feature: use semaphore for scanning. 2024-05-06 14:43:03 -06:00
Upstream Data
79e247c0cf version: bump version number. 2024-05-03 11:19:50 -06:00
Upstream Data
836d045b65 bug: fix bosminer sometimes not being able to set config due to temp settings not being set. 2024-05-03 11:19:33 -06:00
Upstream Data
2d029b65e6 version: bump version number. 2024-05-03 08:31:39 -06:00
Upstream Data
993b7efeef bug: fix bosminer.toml writing to use only ssh, no sftp. 2024-05-03 08:30:51 -06:00
Upstream Data
7e02a6b932 refactor: clean and optimize imports. 2024-05-01 14:29:02 -06:00
Upstream Data
60e38fb8bc refactor: move models to pyasic.miners.devices 2024-05-01 14:18:22 -06:00
Upstream Data
4fc2757ffa feature: add device models. 2024-05-01 14:16:49 -06:00
Upstream Data
c89b25d7c9 feature: add expected fans to miner data. 2024-05-01 11:53:45 -06:00
Upstream Data
f2fc354f8c Merge remote-tracking branch 'origin/dev_data' into dev_data 2024-05-01 11:37:00 -06:00
Upstream Data
0e7eca339c feature: create device_info field for MinerData. 2024-05-01 11:36:54 -06:00
Upstream Data
5f76cb9f0a feature: create device_info field for MinerData. 2024-05-01 11:36:28 -06:00
Upstream Data
ed3a4bd32a bug: fix as_influx timestamp parsing. 2024-05-01 10:16:02 -06:00
Upstream Data
a0a1b68f68 feature: save datetime object as private in MinerData, and parse datetime in ISO format along with a timestamp. 2024-05-01 08:57:02 -06:00
Upstream Data
b7a81097a4 version: bump version number. 2024-04-30 15:50:37 -06:00
Upstream Data
651bef8203 bug: round mara fw wattage. 2024-04-30 14:43:35 -06:00
Upstream Data
a9e5c99ab2 bug: fix mara fw expected hashrate scaling. 2024-04-30 14:42:43 -06:00
Upstream Data
30216fdd5b bug: fix mara fw hashrate scaling. 2024-04-30 14:32:43 -06:00
Upstream Data
341cc13d83 bug: fix no firmware type for BOSer. 2024-04-30 13:12:01 -06:00
Upstream Data
05a4ae6f04 bug: reformat, and fix miner listener. 2024-04-30 11:50:21 -06:00
Brett Rowan
5971d9fd83 Merge pull request #125 from UpstreamData/dev_marafw
feature: Add maraFW support.
2024-04-30 10:01:35 -06:00
Brett Rowan
3968f2275c Merge branch 'master' into dev_marafw 2024-04-30 10:01:28 -06:00
Upstream Data
84344ca883 feature: make mara discover more consistent. 2024-04-30 09:11:23 -06:00
1e9abhi1e10
59b80254eb remove trailing whitespace 2024-04-30 09:11:23 -06:00
1e9abhi1e10
06fdb19e0b Add tess in config_tests 2024-04-30 09:11:23 -06:00
Upstream Data
75222e8cd2 docs: update docs generation to fix marathon miners. 2024-04-30 09:11:23 -06:00
Upstream Data
5a067d60e7 bug: remove some excepts that were catching propagated cancellations. 2024-04-30 09:11:21 -06:00
Upstream Data
2fbc4fcb4a version: bump version number. 2024-04-30 09:11:18 -06:00
Upstream Data
13fe60504a bug: fix bad naming of S19J Pro Plus NOPIC. 2024-04-30 09:11:18 -06:00
Upstream Data
cdc52c3605 docs: update docs. 2024-04-30 09:11:17 -06:00
Upstream Data
a9db097355 version: bump version number. 2024-04-30 09:11:17 -06:00
Upstream Data
ec5557cf88 feature: Add support for S19jPro+ No PIC. 2024-04-30 09:11:17 -06:00
Upstream Data
a8ea84d2f3 version: bump version number. 2024-04-30 09:11:17 -06:00
Upstream Data
58d369eedf bug: fix disabling fans when using immersion mode. 2024-04-30 09:11:17 -06:00
Abhishek Patidar
f8f9dd7070 Add tests in rpc_tests (#128) 2024-04-30 09:11:17 -06:00
Upstream Data
01b72e1ee6 version: bump version number. 2024-04-30 09:11:16 -06:00
Upstream Data
e367e630b8 bug: fix bosminer fan control for 2.0 versions. 2024-04-30 09:11:16 -06:00
upstreamdata
385cca6fc0 docs: update index and readme. 2024-04-30 09:11:16 -06:00
upstreamdata
75a3a466a3 docs: update documentation to include new web docstrings. 2024-04-30 09:11:16 -06:00
Harsh Singh Rawat
4bf08dbfe6 docs: add docstring for antminer and auradine in web (#127)
* docs: add docstring for antminer and auradine in web

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>

* Remove Trailing whitespace from the docstring

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>

* Remove Trailing whitespace from the docstring

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>

* Remove Trailing whitespace from the docstring of the fucntion multicommand

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>

---------

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>
2024-04-30 09:11:16 -06:00
Abhishek Patidar
833d061315 docs: Add documentation for config (#121)
* docs: Add documentation for `config`

* Fix styling

* Add documentation for classmethods

* fixes some docstring
2024-04-30 09:11:16 -06:00
Abhishek Patidar
a85558278d docs: Add documentation for ssh (#126) 2024-04-30 09:11:15 -06:00
Upstream Data
bf5087b06d Merge remote-tracking branch 'origin/master' 2024-04-29 09:14:59 -06:00
Upstream Data
ec58d13bae docs: update docs generation to fix marathon miners. 2024-04-29 09:14:47 -06:00
Brett Rowan
75993564ab Merge pull request #131 from 1e9abhi1e10/config_tests 2024-04-27 12:16:30 -06:00
1e9abhi1e10
f3ea169dec remove trailing whitespace 2024-04-27 15:47:08 +05:30
1e9abhi1e10
39b3fe5c25 Add tess in config_tests 2024-04-27 15:40:03 +05:30
John-Paul Compagnone
3b2b586420 add new critical temp api, add board serial no 2024-04-26 19:27:19 -04:00
Upstream Data
5c79c6cb0c bug: remove some excepts that were catching propagated cancellations. 2024-04-26 13:00:16 -06:00
Upstream Data
bab4261bed version: bump version number. 2024-04-24 10:39:34 -06:00
Upstream Data
e1d5c89388 bug: fix bad naming of S19J Pro Plus NOPIC. 2024-04-24 10:37:07 -06:00
Upstream Data
5f6c8cca18 docs: update docs. 2024-04-24 10:04:46 -06:00
Upstream Data
39db14b002 version: bump version number. 2024-04-24 10:04:13 -06:00
Upstream Data
3be04c678b feature: Add support for S19jPro+ No PIC. 2024-04-24 10:03:36 -06:00
Upstream Data
099ec35a8f version: bump version number. 2024-04-22 12:28:20 -06:00
Upstream Data
113dfb9170 bug: fix disabling fans when using immersion mode. 2024-04-22 12:27:44 -06:00
Abhishek Patidar
8d19e0ebbb Add tests in rpc_tests (#128) 2024-04-22 09:30:20 -06:00
Upstream Data
ec064eba65 version: bump version number. 2024-04-22 08:58:28 -06:00
Upstream Data
3451127761 bug: fix bosminer fan control for 2.0 versions. 2024-04-22 08:58:06 -06:00
upstreamdata
b3be52ca77 docs: update index and readme. 2024-04-19 21:43:22 -06:00
upstreamdata
b6ec6caa72 docs: update documentation to include new web docstrings. 2024-04-19 21:41:17 -06:00
Harsh Singh Rawat
8e81e18622 docs: add docstring for antminer and auradine in web (#127)
* docs: add docstring for antminer and auradine in web

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>

* Remove Trailing whitespace from the docstring

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>

* Remove Trailing whitespace from the docstring

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>

* Remove Trailing whitespace from the docstring of the fucntion multicommand

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>

---------

Signed-off-by: PAINxNAGATO <harshrawat349@gmail.com>
2024-04-19 15:14:01 -06:00
Abhishek Patidar
6ea26e0e19 docs: Add documentation for config (#121)
* docs: Add documentation for `config`

* Fix styling

* Add documentation for classmethods

* fixes some docstring
2024-04-19 15:05:12 -06:00
Abhishek Patidar
be446f94c1 docs: Add documentation for ssh (#126) 2024-04-19 15:03:51 -06:00
Upstream Data
3d94e30f22 feature: Add wattage settings, reboot, restart backend, stop mining, and start mining. 2024-04-12 15:20:09 -06:00
Upstream Data
d5a7ff3a46 feature: add wattage limit data and set wattage to mara. 2024-04-12 15:15:23 -06:00
Upstream Data
bbfa97632d feature: add send_config for mara miners. 2024-04-12 14:56:18 -06:00
Upstream Data
ecf0ce22d6 feature: add mara config parsing. 2024-04-12 14:28:22 -06:00
Upstream Data
d56da007a5 feature: make mara discover more consistent. 2024-04-12 13:40:10 -06:00
Upstream Data
2c86b2da7e feature: Add mara fw light functions. 2024-04-12 13:16:55 -06:00
Upstream Data
c73b1ceb07 feature: update mara fw data locations. 2024-04-12 13:09:23 -06:00
Upstream Data
a320c8967d feature: remove some mara support in order to get rid of Antminer function calls. 2024-04-12 10:19:24 -06:00
Upstream Data
e21e340f60 feature: add mara miner models. 2024-04-12 10:02:13 -06:00
Upstream Data
f63d8f4b91 feature: add really basic MaraFW support. 2024-04-12 09:55:45 -06:00
Upstream Data
ba6a1606b6 version: bump version number. 2024-04-12 08:48:52 -06:00
Upstream Data
51b0c0456f bug: fix parsing of tuner algo modes into json. 2024-04-12 08:47:40 -06:00
Upstream Data
04bd03b496 version: bump version number. 2024-04-11 09:31:00 -06:00
Upstream Data
bc5764c8ff feature: add stock support for T21. 2024-04-11 09:30:24 -06:00
Brett Rowan
1f2e066f4c Merge pull request #122 from jpcomps/fix_is_mining
feature: add is_mining for ePIC, add T21, add BlockMiner 720i
2024-04-11 09:28:18 -06:00
Upstream Data
74c457a694 version: bump version number. 2024-04-11 09:23:55 -06:00
Upstream Data
4a1c53dfd7 bug: fix some issues with config on bosminer. 2024-04-11 09:23:33 -06:00
John-Paul Compagnone
81b77f8768 cleaner code 2024-04-11 11:06:45 -04:00
John-Paul Compagnone
3b127b6862 fix is_mining for ePIC 2024-04-11 09:34:40 -04:00
Upstream Data
2815d2ba11 version: bump version number. 2024-04-08 12:15:38 -06:00
Upstream Data
1ff20fc6f0 feature: add bosminer S21 support. 2024-04-08 12:15:18 -06:00
Brett Rowan
797c847055 version: bump version number. 2024-04-07 17:17:17 -06:00
Brett Rowan
65c7f2f66f bug: fix vnish shutting-down handling. 2024-04-07 17:16:37 -06:00
Brett Rowan
445d621590 version: bump version number. 2024-04-07 17:04:10 -06:00
Brett Rowan
d39ecfd6b4 feature: add is_mining for vnish. 2024-04-07 17:03:28 -06:00
Brett Rowan
36663471fb version: bump version number. 2024-04-06 12:34:43 -06:00
Brett Rowan
80293ac52f bug: fix incorrect model for XP. 2024-04-06 12:34:14 -06:00
UpstreamData
70b45f40f5 docs: update dev setup. 2024-03-29 11:19:17 -06:00
UpstreamData
a511fabd9c Update README.md with dev docs. 2024-03-29 11:17:39 -06:00
Jim Burtoft
8bc8f6f178 Comment on some code I didn't understand initially (#118) 2024-03-28 21:31:37 -06:00
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
JP Compagnone
577e8df612 Merge branch 'UpstreamData:master' into master 2024-03-14 16:58:12 -04: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
John-Paul Compagnone
743823f66e add Blockminer 720i and Antminer T21 support 2024-02-25 17:44:20 -05: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
UpstreamData
d84d95fe5f version: bump version number. 2023-12-21 15:25:57 -07:00
UpstreamData
0e5b811fb9 Add config attribute to data and refactor data naming (#81)
* feature: add config to MinerData.  Remove related attributes.

* feature: rename ideal and nominal to expected to make data naming consistent across files.

* refactor: run isort on all files.

* docs: update docstrings.
2023-12-21 15:20:50 -07:00
UpstreamData
3d31179562 feature: add more BOS+ supported types. 2023-12-19 08:40:31 -07:00
UpstreamData
69f39bef0c docs: update tagline 2023-12-19 08:18:06 -07:00
UpstreamData
1076dab7f5 Update README.md 2023-12-19 08:17:39 -07:00
UpstreamData
3ae1f700c2 docs: update README.md 2023-12-18 14:48:19 -07:00
UpstreamData
dc3f061b9b docs: update shields. 2023-12-18 14:44:43 -07:00
UpstreamData
52758dd8b3 docs: update README. 2023-12-18 14:33:42 -07:00
UpstreamData
0e492f1cfd tests: add more tests for miners. 2023-12-18 14:11:16 -07:00
UpstreamData
659dc55f3c bug: add missing key to epic data locations. 2023-12-18 14:07:46 -07:00
UpstreamData
eb9b29aca1 tests: add tests for config and update tests. 2023-12-18 14:00:40 -07:00
UpstreamData
b045abe76e bug: reorder config information and fix bad key. 2023-12-18 13:59:56 -07:00
Upstream Data
7a75818a20 version: bump version number. 2023-12-17 09:09:00 -07:00
Upstream Data
d2be68d35e bug: fix MinerConfig default values for 3.11+. Add MinerConfig.as_epic default implementation. 2023-12-17 09:08:14 -07:00
Upstream Data
c5c4bb10ee version: bump version number. 2023-12-16 10:59:23 -07:00
Upstream Data
c4dfdda448 Merge branch 'dev_bugs'
# Conflicts:
#	pyasic/miners/miner_factory.py
#	pyasic/miners/types/whatsminer/M6X/M60.py
#	pyasic/miners/types/whatsminer/M6X/M60S.py
#	pyasic/miners/types/whatsminer/M6X/M63.py
#	pyasic/miners/types/whatsminer/M6X/M63S.py
#	pyasic/miners/types/whatsminer/M6X/M66.py
#	pyasic/miners/types/whatsminer/M6X/M66S.py
#	pyasic/miners/types/whatsminer/M6X/__init__.py
#	pyasic/miners/whatsminer/btminer/M6X/M60.py
#	pyasic/miners/whatsminer/btminer/M6X/M60S.py
#	pyasic/miners/whatsminer/btminer/M6X/M66S.py
#	pyasic/miners/whatsminer/btminer/M6X/__init__.py
#	pyasic/miners/whatsminer/btminer/__init__.py
2023-12-16 10:55:27 -07:00
Upstream Data
4459de2260 feature: add support for S19kProNoPIC BOS. Reformat. 2023-12-16 10:54:51 -07:00
UpstreamData
201cfd7ef9 docs: update documentation to be more readable on the main page. 2023-12-13 11:15:03 -07:00
UpstreamData
4201905fdd bug: fix some tasks not being cancelled properly in miner factory. 2023-12-13 10:18:28 -07:00
checksum0
497ffb5bc0 Add all the currently known Whatsminer M6X machines (#77)
* Create new BTMiner M6X backend class to represent Whatsminer new M6X generation

* Add all new known types of Whatsminer M6X

* Ensure all new types are imported in their respective __init__.py

* Create all BTMiner API class for known types of new M6X generation

* Ensure all new BTMiner API class are imported in __init__.py

* Fix erroneous M6X models data

* Ensure M6X miners are imported and add them to their MinerTypes dictionary in miner_factory.py
2023-12-12 19:38:36 -07:00
checksum0
2f762c95db Add all the currently known Whatsminer M6X machines (#77)
* Create new BTMiner M6X backend class to represent Whatsminer new M6X generation

* Add all new known types of Whatsminer M6X

* Ensure all new types are imported in their respective __init__.py

* Create all BTMiner API class for known types of new M6X generation

* Ensure all new BTMiner API class are imported in __init__.py

* Fix erroneous M6X models data

* Ensure M6X miners are imported and add them to their MinerTypes dictionary in miner_factory.py
2023-12-12 19:32:12 -07:00
UpstreamData
67aed79330 bug: fix mode spec in bosminer config. 2023-12-12 13:21:50 -07:00
UpstreamData
073e048726 bug: fix bosminer config missing format information. 2023-12-12 13:11:49 -07:00
UpstreamData
02234f3d1e feature: improve dict merging speed 2023-12-12 09:25:43 -07:00
UpstreamData
dc22df0280 refactor: remove innosilicon pool comment, as it is correct. 2023-12-12 08:54:24 -07:00
UpstreamData
02056b8c88 refactor: remove config prints. 2023-12-11 15:36:02 -07:00
UpstreamData
3a43cd293c bug: Fix improper naming of fan mode. 2023-12-11 15:18:23 -07:00
UpstreamData
6941d9f349 bug: add default case for work mode when there is no work mode returned from bitmain. 2023-12-11 15:08:57 -07:00
UpstreamData
f6b0b64d86 bug: set default quota to 1. 2023-12-11 14:07:17 -07:00
UpstreamData
8d68dd9dac refactor: re-order config keys 2023-12-11 14:06:22 -07:00
UpstreamData
27368a9bd2 bug: fix some issues, and remove unused imports. 2023-12-11 13:48:26 -07:00
UpstreamData
c919b00312 feature: allow config conversion to and from dict. 2023-12-11 13:40:10 -07:00
UpstreamData
f162529883 feature: allow dps conversion for bos grpc. 2023-12-11 11:40:46 -07:00
Upstream Data
bb182bb22d bug: fix some issues with return types and missing return statements. 2023-12-10 20:28:06 -07:00
Upstream Data
af15c4fbd1 bug: pin working betterproto version. 2023-12-10 20:25:27 -07:00
Upstream Data
47c2eb9f0e feature: use betterproto + grpclib. 2023-12-10 20:10:11 -07:00
Upstream Data
1ab39f5873 bug: fix bosminer config parsing. 2023-12-10 17:40:39 -07:00
Upstream Data
43200a7354 feature: Add bosminer.toml parser. 2023-12-10 13:20:03 -07:00
Upstream Data
4fc57832e1 feature: Finish fixing get and send config handlers for miners. 2023-12-10 10:14:57 -07:00
Upstream Data
9ee63cc3ab feature: Update get and send config methods for most miners, and add as_inno. 2023-12-10 10:10:55 -07:00
Upstream Data
b22b506d55 feature: Add whatsminer send_config. 2023-12-10 09:55:05 -07:00
Upstream Data
468fba3465 feature: Add whatsminer set mode commands. 2023-12-10 09:49:24 -07:00
Upstream Data
0399094197 feature: add AM old and goldshell configs. 2023-12-10 09:45:34 -07:00
Upstream Data
bfdfa8a6ab feature: Add AM modern send and get config. 2023-12-10 09:30:31 -07:00
Upstream Data
83d0d09b0d feature: Add whatsminer get_config. 2023-12-09 17:35:47 -07:00
Upstream Data
f892c3a0fd feature: Add from am_modern to config. 2023-12-09 16:59:39 -07:00
Upstream Data
81b974f565 bug: fix bad indentation. 2023-12-09 15:12:36 -07:00
UpstreamData
5eaf876c6d feature: add bos to config miner types. 2023-12-09 13:27:23 -07:00
Upstream Data
d7d1b845a7 feature: add MinerConfig.from_api(). 2023-12-09 13:06:52 -07:00
UpstreamData
242517a36a feature: add inno to config miner types. 2023-12-08 11:03:36 -07:00
UpstreamData
791249bf3d feature: add avalon and goldshell to miner config types. 2023-12-08 10:57:57 -07:00
UpstreamData
5a70a27f07 reformat: remove some useless files. 2023-12-08 10:11:43 -07:00
UpstreamData
bca81f3bca feature: add AM old and modern, and WM config implementation. 2023-12-08 10:10:21 -07:00
UpstreamData
6d75565baf feature: start adding new config implementation. 2023-12-08 09:16:04 -07:00
JP Compagnone
9f42e6a3be add new Antminer models (S19jPro+ and S19k Pro) (#75)
* Add S19jPro+ and S19K Pro

* typo
2023-12-08 08:34:30 -07:00
Upstream Data
362b204c91 version: bump version number. 2023-11-29 20:45:46 -07:00
Upstream Data
952b660c05 bug: re-add missing socket check during scan. 2023-11-29 20:45:25 -07:00
UpstreamData
fbd73881d4 version: bump version number. 2023-11-28 16:42:15 -07:00
JP Compagnone
68c4dadb63 hotfix: fix epic api error handling (#74)
* hotfix: fix epic api error handling

* much cleaner way to handle the retry
2023-11-28 16:39:57 -07:00
UpstreamData
87016670d4 version: bump version number. 2023-11-28 10:50:56 -07:00
JP Compagnone
8701bbe4e2 Feature - Add initial ePIC UMC support (#71)
* prelim support of ePIC UMC

* slowly adding things

* add most api calls

* add some guards

* fix post commands

* remove print

* catch when API returns error

* missing guard

* remove semicolon

* recommended changes

* add docs and changes

* respect ignore_errors
2023-11-28 10:49:49 -07:00
UpstreamData
7d1f125b0b docs: update settings docs to list. 2023-11-27 11:07:43 -07:00
UpstreamData
e433902bd5 docs: update settings docs. 2023-11-27 10:57:13 -07:00
UpstreamData
a653772968 docs: update network docs. 2023-11-27 10:53:40 -07:00
UpstreamData
d8b938cd5b version: bump version number. 2023-11-27 10:39:10 -07:00
UpstreamData
47d76e325a docs: update docs to include new information. 2023-11-27 10:37:38 -07:00
UpstreamData
7ee7868094 feature: change so_linger_time to socket_linger_time. 2023-11-27 10:19:30 -07:00
UpstreamData
3f1183a4f9 feature: add so_linger option to settings. 2023-11-27 09:24:28 -07:00
Upstream Data
2b443497ea bug: improve handling of whatsminers in get_miner. 2023-11-25 12:48:45 -07:00
Upstream Data
c3972f9524 feature: add default ssl ctx to all httpx clients to speed up initialization. 2023-11-25 01:08:04 -07:00
Upstream Data
92bbb21c11 bug: handle OSError as ConnectionError, and handle Vnish Msg bug because of missing id key. 2023-11-25 00:05:03 -07:00
Upstream Data
1980ff2563 bug: do additional checks on refused connection when scanning. 2023-11-24 23:32:22 -07:00
Upstream Data
93d09a1483 bug: handle unhandled error in pings. 2023-11-24 23:28:16 -07:00
Upstream Data
690d0d99df feature: added new setting for api command timeouts. 2023-11-24 23:19:14 -07:00
Upstream Data
78f689eb2c feature: update scan method to use port 80 when possible, and add .scan() method. 2023-11-24 23:13:56 -07:00
Upstream Data
e68f188e8f bug: fix timeout references in MinerFactory and fix MinerNetwork instantiation. 2023-11-24 23:00:06 -07:00
Upstream Data
7eda611fe9 bug: fix scanning size being too large. 2023-11-24 22:50:43 -07:00
Upstream Data
1d12817942 feature: improve network parsing and implementation. 2023-11-24 22:38:43 -07:00
UpstreamData
b24efd4c69 bug: fix miner network not working with lists. 2023-11-24 13:27:09 -07:00
UpstreamData
5533135b05 docs: update supported miners. 2023-11-23 11:54:01 -07:00
UpstreamData
475054fbe0 feature: finish support for most whatsminer subtypes. 2023-11-23 11:52:44 -07:00
Daniel Sokil
06bad1bbe0 Add More Whatsminer Models, and Additional Config For Existing Models (#70) 2023-11-23 11:35:18 -07:00
UpstreamData
f3746ff756 version: bump version number. 2023-11-20 11:19:45 -07:00
UpstreamData
9f16d37c8b feature: hide GRPC and GQL if BOSer is not found. 2023-11-20 11:19:13 -07:00
UpstreamData
8a13c7940a docs: update pyproject.toml description. 2023-11-20 10:33:25 -07:00
UpstreamData
8bea76ff67 feature: add chip count for M30S+VG50. 2023-11-20 10:32:51 -07:00
Upstream Data
1504bd744c version: bump version number. 2023-11-18 22:45:38 -07:00
Upstream Data
6449f10615 feature: implement GPRC set commands properly. 2023-11-18 22:45:09 -07:00
UpstreamData
d79509bda7 version: bump version number. Pin httpx to 0.25.0 min. 2023-11-12 18:36:45 -07:00
UpstreamData
630b847466 version: bump version number. Pin httpx to 0.25.0 min. 2023-11-12 18:35:52 -07:00
725 changed files with 43029 additions and 16328 deletions

View File

@@ -13,10 +13,10 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4.2.2
- name: Publish GH release
uses: softprops/action-gh-release@v0.1.14
uses: softprops/action-gh-release@v2.1.0
- name: Build using poetry and publish to PyPi
uses: JRubics/poetry-publish@v1.11
uses: JRubics/poetry-publish@v2.0
with:
pypi_token: ${{ secrets.PYPI_API_KEY }}

View File

@@ -1,16 +1,33 @@
ci:
skip:
- poetry-lock
- unittest
- generate-docs
repos:
- repo: https://github.com/python-poetry/poetry
rev: 2.1.2
hooks:
- id: poetry-check
- id: poetry-lock
- id: poetry-install
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: check-yaml
name: check-yaml for mkdocs.yml
files: ^mkdocs\.yml$
args: [--unsafe]
- id: check-yaml
name: check-yaml for other YAML files
exclude: ^mkdocs\.yml$
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: 22.6.0
rev: 25.1.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.10.1
rev: 6.0.1
hooks:
- id: isort
name: isort (python)
@@ -21,7 +38,12 @@ repos:
name: unittest
entry: python -m unittest discover
language: system
'types': [python]
types: [ python ]
args: ["-p '*test.py'"] # Probably this option is absolutely not needed.
pass_filenames: false
stages: [commit]
- id: generate-docs
name: generate-docs
entry: python docs/generate_miners.py
language: system
types: [ python ]
pass_filenames: false

View File

@@ -1,20 +1,18 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
tools:
python: "3.9"
tools: { python: "3.11" }
jobs:
pre_create_environment:
- asdf plugin add poetry
- asdf install poetry latest
- asdf global poetry latest
- poetry config virtualenvs.create false
post_install:
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --only docs
mkdocs:
configuration: mkdocs.yml
# Optionally declare the Python requirements required to build your docs
python:
install:
- requirements: docs/requirements.txt
configuration: mkdocs.yml

351
README.md
View File

@@ -1,142 +1,293 @@
# pyasic
*A simplified and standardized interface for Bitcoin ASICs.*
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![pypi](https://img.shields.io/pypi/v/pyasic.svg)](https://pypi.org/project/pyasic/)
[![python](https://img.shields.io/pypi/pyversions/pyasic.svg)](https://pypi.org/project/pyasic/)
[![Read the Docs](https://img.shields.io/readthedocs/pyasic)](https://pyasic.readthedocs.io/en/latest/)
[![GitHub](https://img.shields.io/github/license/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)
[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/UpstreamData/pyasic)](https://www.codefactor.io/repository/github/upstreamdata/pyasic)
## Documentation and Supported Miners
Documentation is located on Read the Docs as [pyasic](https://pyasic.readthedocs.io/en/latest/).
[![PyPI - Version](https://img.shields.io/pypi/v/pyasic.svg)](https://pypi.org/project/pyasic/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/pyasic)](https://pypi.org/project/pyasic/)
Supported miners are listed in the docs, [here](https://pyasic.readthedocs.io/en/latest/miners/supported_types/).
[![Python - Supported Versions](https://img.shields.io/pypi/pyversions/pyasic.svg)](https://pypi.org/project/pyasic/)
[![CodeFactor - Grade](https://img.shields.io/codefactor/grade/github/UpstreamData/pyasic)](https://www.codefactor.io/repository/github/upstreamdata/pyasic)
[![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)
[![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)
---
## Intro
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](https://docs.pyasic.org/en/latest/miners/supported_types/)
---
## Installation
You can install pyasic directly from pip with the command `pip install pyasic`.
For those of you who aren't comfortable with code and developer tools, there are windows builds of GUI applications that use this library [here](https://drive.google.com/drive/folders/1DjR8UOS_g0ehfiJcgmrV0FFoqFvE9akW?usp=sharing).
It is recommended to install `pyasic` in a [virtual environment](https://realpython.com/python-virtual-environments-a-primer/#what-other-popular-options-exist-aside-from-venv) to isolate it from the rest of your system. Options include:
- [pypoetry](https://python-poetry.org/): the reccommended way, since pyasic already uses it by default. Use version 2.0+
## Developer Setup
It is highly reccommended that you contribute to this project through [`pyasic-super`](https://github.com/UpstreamData/pyasic-super) using its submodules. This allows testing in conjunction with other `pyasic` related programs.
<br>
This repo uses poetry for dependencies, which can be installed by following the guide on their website [here](https://python-poetry.org/docs/#installation).
After you have poetry installed, run `poetry install --with dev`, or `poetry install --with dev,docs` if you want to include packages required for documentation.
Finally, initialize pre-commit hooks with `poetry run pre-commit install`.
### Documentation Testing
Testing the documentation can be done by running `poetry run mkdocs serve`, whcih will serve the documentation locally on port 8000.
## Interfacing with miners programmatically
There are 2 main ways to get a miner (and the functions attached to it), via scanning or via the `MinerFactory()`.
#### Scanning for miners
```python
import asyncio
from pyasic.network import MinerNetwork
# define asynchronous function to scan for miners
async def scan_and_get_data():
# Define network range to be used for scanning
# This can take a list of IPs, a constructor string, or an IP and subnet mask
# The standard mask is /24 (x.x.x.0-255), and you can pass any IP address in the subnet
net = MinerNetwork("192.168.1.69", mask=24)
# Scan the network for miners
# This function returns a list of miners of the correct type as a class
miners: list = await net.scan_network_for_miners()
# We can now get data from any of these miners
# To do them all we have to create a list of tasks and gather them
tasks = [miner.get_data() for miner in miners]
# Gather all tasks asynchronously and run them
data = await asyncio.gather(*tasks)
# Data is now a list of MinerData, and we can reference any part of that
# Print out all data for now
for item in data:
print(item)
if __name__ == "__main__":
asyncio.run(scan_and_get_data())
```
poetry install
```
- [venv](https://docs.python.org/3/library/venv.html): included in Python standard library but has fewer features than other options
- [pyenv-virtualenv](https://github.com/pyenv/pyenv-virtualenv): [pyenv](https://github.com/pyenv/pyenv) plugin for managing virtualenvs
#### Getting a miner if you know the IP
```
pyenv install <python version number>
pyenv virtualenv <python version number> <env name>
pyenv activate <env name>
```
- [conda](https://docs.conda.io/en/latest/)
##### Installing `pyasic`
`python -m pip install pyasic` or `poetry install`
##### Additional Developer Setup
```
poetry install --with dev
pre-commit install
```
##### Building Documentation Locally
```
poetry install --with docs
python docs/generate_miners.py
poetry run mkdocs serve
```
---
## Getting started
Getting started with `pyasic` is easy. First, find your miner (or miners) on the network by scanning for them or getting the correct class automatically for them if you know the IP.
##### Scanning for miners
To scan for miners in `pyasic`, we use the class `MinerNetwork`, which abstracts the search, communication, identification, setup, and return of a miner to 1 command.
The command `MinerNetwork.scan()` returns a list that contains any miners found.
```python
import asyncio # asyncio for handling the async part
from pyasic.network import MinerNetwork # miner network handles the scanning
async def scan_miners(): # define async scan function to allow awaiting
# create a miner network
# you can pass in any IP and it will use that in a subnet with a /24 mask (255 IPs).
network = MinerNetwork.from_subnet("192.168.1.50/24") # this uses the 192.168.1.0-255 network
# scan for miners asynchronously
# this will return the correct type of miners if they are supported with all functionality.
miners = await network.scan()
print(miners)
if __name__ == "__main__":
asyncio.run(scan_miners()) # run the scan asynchronously with asyncio.run()
```
---
##### Creating miners based on IP
If you already know the IP address of your miner or miners, you can use the `MinerFactory` to communicate and identify the miners, or an abstraction of its functionality, `get_miner()`.
The function `get_miner()` will return any miner it found at the IP address specified, or an `UnknownMiner` if it cannot identify the miner.
```python
import asyncio # asyncio for handling the async part
from pyasic import get_miner # handles miner creation
async def get_miners(): # define async scan function to allow awaiting
# get the miner with the miner factory
# the miner factory is a singleton, and will always use the same object and cache
# this means you can always call it as MinerFactory().get_miner(), or just get_miner()
miner_1 = await get_miner("192.168.1.75")
miner_2 = await get_miner("192.168.1.76")
print(miner_1, miner_2)
# can also gather these, since they are async
# gathering them will get them both at the same time
# this makes it much faster to get a lot of miners at a time
tasks = [get_miner("192.168.1.75"), get_miner("192.168.1.76")]
miners = await asyncio.gather(*tasks)
print(miners)
if __name__ == "__main__":
asyncio.run(get_miners()) # get the miners asynchronously with asyncio.run()
```
---
## Data gathering
Once you have your miner(s) identified, you will likely want to get data from the miner(s). You can do this using a built-in function in each miner called `get_data()`.
This function will return an instance of the dataclass `MinerData` with all data it can gather from the miner.
Each piece of data in a `MinerData` instance can be referenced by getting it as an attribute, such as `MinerData().hashrate`.
##### One miner
```python
import asyncio
from pyasic import get_miner
async def gather_miner_data():
miner = await get_miner("192.168.1.75")
if miner is not None:
miner_data = await miner.get_data()
print(miner_data) # all data from the dataclass
print(miner_data.hashrate) # hashrate of the miner in TH/s
if __name__ == "__main__":
asyncio.run(gather_miner_data())
```
---
##### Multiple miners
You can do something similar with multiple miners, with only needing to make a small change to get all the data at once.
```python
import asyncio # asyncio for handling the async part
from pyasic.network import MinerNetwork # miner network handles the scanning
async def gather_miner_data(): # define async scan function to allow awaiting
network = MinerNetwork.from_subnet("192.168.1.50/24")
miners = await network.scan()
# we need to asyncio.gather() all the miners get_data() functions to make them run together
all_miner_data = await asyncio.gather(*[miner.get_data() for miner in miners])
for miner_data in all_miner_data:
print(miner_data) # print out all the data one by one
if __name__ == "__main__":
asyncio.run(gather_miner_data())
```
---
## Miner control
`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`.
These functions are
`check_light`,
`fault_light_off`,
`fault_light_on`,
`get_config`,
`get_data`,
`get_errors`,
`get_hostname`,
`get_model`,
`reboot`,
`restart_backend`,
`stop_mining`,
`resume_mining`,
`is_mining`,
`send_config`, and
`set_power_limit`.
##### Usage
```python
import asyncio
from pyasic import get_miner
# define asynchronous function to get miner and data
async def get_miner_data(miner_ip: str):
# Use MinerFactory to get miner
# MinerFactory is a singleton, so we can just get the instance in place
miner = await get_miner(miner_ip)
async def set_fault_light():
miner = await get_miner("192.168.1.20")
# Get data from the miner
data = await miner.get_data()
print(data)
# call control function
await miner.fault_light_on()
if __name__ == "__main__":
asyncio.run(get_miner_data("192.168.1.69"))
asyncio.run(set_fault_light())
```
### Advanced data gathering
---
## Helper dataclasses
If needed, this library exposes a wrapper for the miner API that can be used for advanced data gathering.
##### `MinerConfig` and `MinerData`
You can see more information on basic usage of the APIs past this example in the docs [here](https://pyasic.readthedocs.io/en/latest/API/api/).
`pyasic` implements a few dataclasses as helpers to make data return types consistent across different miners and miner APIs. The different fields of these dataclasses can all be viewed with the classmethod `cls.fields()`.
Please see the appropriate API documentation page (pyasic docs -> Advanced -> Miner APIs -> your API type) for a link to that specific miner's API documentation page and more information.
---
#### List available API commands
##### MinerData
`MinerData` is a return from the [`get_data()`](#get-data) function, and is used to have a consistent dataset across all returns.
You can call `MinerData.as_dict()` to get the dataclass as a dictionary, and there are many other helper functions contained in the class to convert to different data formats.
`MinerData` instances can also be added to each other to combine their data and can be divided by a number to divide all their data, allowing you to get average data from many miners by doing -
```python
from pyasic import MinerData
# examples of miner data
d1 = MinerData("192.168.1.1")
d2 = MinerData("192.168.1.2")
list_of_miner_data = [d1, d2]
average_data = sum(list_of_miner_data, start=MinerData("0.0.0.0"))/len(list_of_miner_data)
```
---
##### MinerConfig
`MinerConfig` is `pyasic`'s way to represent a configuration file from a miner.
It is designed to unionize the configuration of all supported miner types, and is the return from [`get_config()`](#get-config).
Each miner has a unique way to convert the `MinerConfig` to their specific type, there are helper functions in the class.
In most cases these helper functions should not be used, as [`send_config()`](#send-config) takes a [`MinerConfig` and will do the conversion to the right type for you.
You can use the `MinerConfig` as follows:
```python
import asyncio
from pyasic import get_miner
async def get_api_commands(miner_ip: str):
# Get the miner
miner = await get_miner(miner_ip)
async def set_fault_light():
miner = await get_miner("192.168.1.20")
# List all available commands
# Can also be called explicitly with the function miner.api.get_commands()
print(miner.api.commands)
# get config
cfg = await miner.get_config()
# send config
await miner.send_config(cfg)
if __name__ == "__main__":
asyncio.run(get_api_commands("192.168.1.69"))
asyncio.run(set_fault_light())
```
#### Use miner API commands to gather data
---
## Settings
The miner API commands will raise an `APIError` if they fail with a bad status code, to bypass this you must send them manually by using `miner.api.send_command(command, ignore_errors=True)`
`pyasic` has settings designed to make using large groups of miners easier. You can set the default password for all types of miners using the `pyasic.settings` module, used as follows:
```python
import asyncio
from pyasic import settings
from pyasic import get_miner
async def get_api_commands(miner_ip: str):
# Get the miner
miner = await get_miner(miner_ip)
# Run the devdetails command
# This is equivalent to await miner.api.send_command("devdetails")
devdetails: dict = await miner.api.devdetails()
print(devdetails)
if __name__ == "__main__":
asyncio.run(get_api_commands("192.168.1.69"))
settings.update("default_antminer_web_password", "my_pwd")
```
##### Default values:
```
"network_ping_retries": 1,
"network_ping_timeout": 3,
"network_scan_semaphore": None,
"factory_get_retries": 1,
"factory_get_timeout": 3,
"get_data_retries": 1,
"api_function_timeout": 5,
"antminer_mining_mode_as_str": False,
"default_whatsminer_rpc_password": "admin",
"default_innosilicon_web_password": "admin",
"default_antminer_web_password": "root",
"default_bosminer_web_password": "root",
"default_vnish_web_password": "admin",
"default_goldshell_web_password": "123456789",
"default_auradine_web_password": "admin",
"default_epic_web_password": "letmein",
"default_hive_web_password": "admin",
"default_antminer_ssh_password": "miner",
"default_bosminer_ssh_password": "root",
# ADVANCED
# Only use this if you know what you are doing
"socket_linger_time": 1000,
```

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

@@ -6,19 +6,3 @@
options:
show_root_heading: false
heading_level: 4
## Pool Groups
::: pyasic.config._PoolGroup
handler: python
options:
show_root_heading: false
heading_level: 4
## Pools
::: pyasic.config._Pool
handler: python
options:
show_root_heading: false
heading_level: 4

View File

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

View File

@@ -2,8 +2,9 @@ import asyncio
import importlib
import os
import warnings
from pathlib import Path
from pyasic.miners.miner_factory import MINER_CLASSES, MinerTypes
from pyasic.miners.factory import MINER_CLASSES, MinerTypes
warnings.filterwarnings("ignore")
@@ -27,10 +28,14 @@ def backend_str(backend: MinerTypes) -> str:
match backend:
case MinerTypes.ANTMINER:
return "Stock Firmware Antminers"
case MinerTypes.AURADINE:
return "Stock Firmware Auradine Miners"
case MinerTypes.AVALONMINER:
return "Stock Firmware Avalonminers"
case MinerTypes.VNISH:
return "Vnish Firmware Miners"
case MinerTypes.EPIC:
return "ePIC Firmware Miners"
case MinerTypes.BRAIINS_OS:
return "BOS+ Firmware Miners"
case MinerTypes.HIVEON:
@@ -43,6 +48,23 @@ def backend_str(backend: MinerTypes) -> str:
return "Stock Firmware Goldshells"
case MinerTypes.LUX_OS:
return "LuxOS Firmware Miners"
case MinerTypes.MARATHON:
return "Mara Firmware Miners"
case MinerTypes.BITAXE:
return "Stock Firmware BitAxe Miners"
case MinerTypes.LUCKYMINER:
return "Stock Firmware Lucky Miners"
case MinerTypes.ICERIVER:
return "Stock Firmware IceRiver Miners"
case MinerTypes.HAMMER:
return "Stock Firmware Hammer Miners"
case MinerTypes.VOLCMINER:
return "Stock Firmware Volcminers"
case MinerTypes.ELPHAPEX:
return "Stock Firmware Elphapex Miners"
case MinerTypes.MSKMINER:
return "MSKMiner Firmware Miners"
raise TypeError("Unknown miner backend, cannot generate docs")
def create_url_str(mtype: str):
@@ -57,11 +79,17 @@ def create_url_str(mtype: str):
HEADER_FORMAT = "# pyasic\n## {} Models\n\n"
MINER_HEADER_FORMAT = "## {}\n"
DATA_FORMAT = """::: {}
DATA_FORMAT = """
- [{}] Shutdowns
- [{}] Power Modes
- [{}] Setpoints
- [{}] Presets
::: {}
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
"""
SUPPORTED_TYPES_HEADER = """# pyasic
@@ -69,6 +97,8 @@ SUPPORTED_TYPES_HEADER = """# pyasic
Supported miner types are here on this list. If your miner (or miner version) is not on this list, please feel free to [open an issue on GitHub](https://github.com/UpstreamData/pyasic/issues) to get it added.
Keep in mind that some functionality is only supported for specific miners or firmwares, please check the page for your miner to make sure the functionality you need is supported.
##### pyasic currently supports the following miners and subtypes:
<style>
details {
@@ -99,39 +129,49 @@ BACKEND_TYPE_CLOSER = """
</details>"""
m_data = {}
done = []
for m in MINER_CLASSES:
for t in MINER_CLASSES[m]:
if t is not None:
for t in sorted(MINER_CLASSES[m], key=lambda x: x or ""):
if t is not None and MINER_CLASSES[m][t] not in done:
miner = MINER_CLASSES[m][t]
if make(miner) not in m_data:
m_data[make(miner)] = {}
if model_type(miner) not in m_data[make(miner)]:
m_data[make(miner)][model_type(miner)] = []
m_data[make(miner)][model_type(miner)].append(miner)
done.append(miner)
async def create_directory_structure(directory, data):
def create_directory_structure(directory, data):
if not os.path.exists(directory):
os.makedirs(directory)
for key, value in data.items():
subdirectory = os.path.join(directory, key)
if isinstance(value, dict):
await create_directory_structure(subdirectory, value)
create_directory_structure(subdirectory, value)
elif isinstance(value, list):
file_path = os.path.join(subdirectory + ".md")
with open(file_path, "w") as file:
file.write(HEADER_FORMAT.format(key))
for item in value:
header = await item("1.1.1.1").get_model()
obj = item("1.1.1.1")
header = obj.model
file.write(MINER_HEADER_FORMAT.format(header))
file.write(DATA_FORMAT.format(path(item)))
file.write(
DATA_FORMAT.format(
"x" if obj.supports_shutdown else " ",
"x" if obj.supports_power_modes else " ",
"x" if obj.supports_autotuning else " ",
"x" if obj.supports_presets else " ",
path(item),
)
)
async def create_supported_types(directory):
def create_supported_types(directory):
with open(os.path.join(directory, "supported_types.md"), "w") as file:
file.write(SUPPORTED_TYPES_HEADER)
for mback in MINER_CLASSES:
@@ -148,7 +188,7 @@ async def create_supported_types(directory):
for mtype in backend_types:
file.write(MINER_TYPE_HEADER.format(mtype))
for minstance in backend_types[mtype]:
model = await minstance("1.1.1.1").get_model()
model = minstance("1.1.1.1").model
file.write(
MINER_DETAILS.format(
make(minstance), mtype, create_url_str(model), model
@@ -158,6 +198,7 @@ async def create_supported_types(directory):
file.write(BACKEND_TYPE_CLOSER)
root_directory = os.path.join(os.getcwd(), "miners")
asyncio.run(create_directory_structure(root_directory, m_data))
asyncio.run(create_supported_types(root_directory))
if __name__ == "__main__":
root_directory = Path(__file__).parent.joinpath("miners")
create_directory_structure(root_directory, m_data)
create_supported_types(root_directory)

View File

@@ -1,267 +1,210 @@
# pyasic
*A set of modules for interfacing with many common types of ASIC bitcoin miners, using both their API and SSH.*
*A simplified and standardized interface for Bitcoin ASICs.*
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![pypi](https://img.shields.io/pypi/v/pyasic.svg)](https://pypi.org/project/pyasic/)
[![python](https://img.shields.io/pypi/pyversions/pyasic.svg)](https://pypi.org/project/pyasic/)
[![Read the Docs](https://img.shields.io/readthedocs/pyasic)](https://pyasic.readthedocs.io/en/latest/)
[![GitHub](https://img.shields.io/github/license/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)
[![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/UpstreamData/pyasic)](https://www.codefactor.io/repository/github/upstreamdata/pyasic)
[![PyPI - Version](https://img.shields.io/pypi/v/pyasic.svg)](https://pypi.org/project/pyasic/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/pyasic)](https://pypi.org/project/pyasic/)
[![Python - Supported Versions](https://img.shields.io/pypi/pyversions/pyasic.svg)](https://pypi.org/project/pyasic/)
[![CodeFactor - Grade](https://img.shields.io/codefactor/grade/github/UpstreamData/pyasic)](https://www.codefactor.io/repository/github/upstreamdata/pyasic)
[![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)
[![Read The Docs - Docs](https://img.shields.io/readthedocs/pyasic)](https://pyasic.readthedocs.io/en/latest/)
[![License - Apache 2.0](https://img.shields.io/github/license/UpstreamData/pyasic)](https://github.com/UpstreamData/pyasic/blob/master/LICENSE.txt)
## Intro
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.
[Supported Miner Types](miners/supported_types.md)
[Click here to view supported miner types](miners/supported_types.md)
Getting started with pyasic is easy. First, find your miner (or miners) on the network by scanning for them or getting the correct class automatically for them if you know the IP.
## 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.
`pyasic` can be installed directly from pip, either with `pip install pyasic`, or a different command if using a tool like `pypoetry`.
<br>
## Getting started
---
Getting started with `pyasic` is easy. First, find your miner (or miners) on the network by scanning for them or getting the correct class automatically for them if you know the IP.
## Scanning for miners
To scan for miners in pyasic, we use the class [`MinerNetwork`][pyasic.network.MinerNetwork], which abstracts the search, communication, identification, setup, and return of a miner to 1 command.
The command [`MinerNetwork().scan_network_for_miners()`][pyasic.network.MinerNetwork.scan_network_for_miners] returns a list that contains any miners found.
```python
import asyncio # asyncio for handling the async part
from pyasic.network import MinerNetwork # miner network handles the scanning
### Scanning for miners
To scan for miners in `pyasic`, we use the class [`MinerNetwork`][pyasic.network.MinerNetwork], which abstracts the search, communication, identification, setup, and return of a miner to 1 command.
The command [`MinerNetwork.scan()`][pyasic.network.MinerNetwork.scan] returns a list that contains any miners found.
```python3
import asyncio# (1)!
from pyasic.network import MinerNetwork# (2)!
async def scan_miners(): # define async scan function to allow awaiting
# create a miner network
# you can pass in any IP and it will use that in a subnet with a /24 mask (255 IPs).
network = MinerNetwork("192.168.1.50") # this uses the 192.168.1.0-255 network
async def scan_miners():# (3)!
network = MinerNetwork.from_subnet("192.168.1.50/24")# (4)!
# scan for miners asynchronously
# this will return the correct type of miners if they are supported with all functionality.
miners = await network.scan_network_for_miners()
miners = await network.scan()# (5)!
print(miners)
if __name__ == "__main__":
asyncio.run(scan_miners()) # run the scan asynchronously with asyncio.run()
asyncio.run(scan_miners())# (6)!
```
<br>
1. `asyncio` for handling the async part.
2. `MinerNetwork` handles the scanning.
3. Define an async function to allow awaiting.
4. Create a miner network.
You can pass in any IP and it will use that in a subnet with a /24 mask (255 IPs).
This uses the 192.168.1.0-255 network.
5. Scan for miners asynchronously.
This will return the correct type of miners (if they are supported) with all functionality.
6. Run the scan asynchronously with asyncio.run().
## 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].
---
### Creating miners based on IP
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.
```python
import asyncio # asyncio for handling the async part
from pyasic import get_miner # handles miner creation
import asyncio# (1)!
from pyasic import get_miner# (2)!
async def get_miners(): # define async scan function to allow awaiting
# get the miner with the miner factory
# the miner factory is a singleton, and will always use the same object and cache
# this means you can always call it as MinerFactory().get_miner(), or just get_miner()
miner_1 = await get_miner("192.168.1.75")
async def get_miners():# (3)!
miner_1 = await get_miner("192.168.1.75")# (4)!
miner_2 = await get_miner("192.168.1.76")
print(miner_1, miner_2)
# can also gather these, since they are async
tasks = [get_miner("192.168.1.75"), get_miner("192.168.1.76")]
miners = await asyncio.gather(*tasks)
miners = await asyncio.gather(*tasks)# (5)!
print(miners)
if __name__ == "__main__":
asyncio.run(get_miners()) # get the miners asynchronously with asyncio.run()
asyncio.run(get_miners())# (6)!
```
<br>
1. `asyncio` for handling the async part.
2. `get_miner` handles the miner type selection.
3. Define an async function to allow awaiting.
4. Get the miner.
5. Can also gather these, since they are async.
Gathering them will get them both at the same time.
This makes it much faster to get a lot of miners at a time.
6. Get the miners asynchronously with asyncio.run().
## Getting data from miners
Once you have your miner(s) identified, you will likely want to get data from the miner(s). You can do this using a built in function in each miner called `get_data()`.
## Data gathering
---
Once you have your miner(s) identified, you will likely want to get data from the miner(s). You can do this using a built-in function in each miner called `get_data()`.
This function will return an instance of the dataclass [`MinerData`][pyasic.data.MinerData] with all data it can gather from the miner.
Each piece of data in a [`MinerData`][pyasic.data.MinerData] instance can be referenced by getting it as an attribute, such as [`MinerData().hashrate`][pyasic.data.MinerData].
```python
import asyncio
from pyasic import get_miner
async def gather_miner_data():
miner = await get_miner("192.168.1.75")
if miner is not None:
miner_data = await miner.get_data()
print(miner_data) # all data from the dataclass
### One miner
```python
import asyncio# (1)!
from pyasic import get_miner# (2)!
async def gather_miner_data():# (3)!
miner = await get_miner("192.168.1.75")# (4)!
if miner is not None:# (5)!
miner_data = await miner.get_data()# (6)!
print(miner_data)# (7)!
print(miner_data.hashrate) # hashrate of the miner in TH/s
if __name__ == "__main__":
asyncio.run(gather_miner_data())
asyncio.run(gather_miner_data())# (9)!
```
1. `asyncio` for handling the async part.
2. `get_miner` handles the miner type selection.
3. Define an async function to allow awaiting.
4. Get the miner.
5. Make sure the miner exists.
If this result is `None`, the miner may be offline.
6. Get data from the miner.
7. All the data from the dataclass.
8. Hashrate of the miner, with unit information.
9. Get the miner data asynchronously with asyncio.run().
### Multiple miners
You can do something similar with multiple miners, with only needing to make a small change to get all the data at once.
```python
import asyncio # asyncio for handling the async part
from pyasic.network import MinerNetwork # miner network handles the scanning
import asyncio# (1)!
from pyasic.network import MinerNetwork# (2)!
async def gather_miner_data(): # define async scan function to allow awaiting
network = MinerNetwork("192.168.1.50")
miners = await network.scan_network_for_miners()
async def gather_miner_data():# (3)!
network = MinerNetwork.from_subnet("192.168.1.50/24")# (4)!
miners = await network.scan()# (5)!
# we need to asyncio.gather() all the miners get_data() functions to make them run together
all_miner_data = await asyncio.gather(*[miner.get_data() for miner in miners])
for miner_data in all_miner_data:
print(miner_data) # print out all the data one by one
print(miner_data)# (7)!
if __name__ == "__main__":
asyncio.run(gather_miner_data())
asyncio.run(gather_miner_data())# (8)!
```
<br>
1. `asyncio` for handling the async part.
2. `MinerNetwork` handles the scanning.
3. Define an async function to allow awaiting.
4. Create a miner network.
5. Scan for miners asynchronously.
6. Use `asyncio.gather()` with all the miners' `get_data()` functions to make them run together.
7. Print out the data one at a time.
8. Get the miner data asynchronously with asyncio.run().
## Controlling miners via pyasic
Every miner class in pyasic must implement all the control functions defined in [`BaseMiner`][pyasic.miners.BaseMiner].
## Miner control
---
`pyasic` exposes a standard interface for each miner using control functions.
Every miner class in `pyasic` must implement all the following control functions.
These functions are
[`check_light`](#check-light),
[`fault_light_off`](#fault-light-off),
[`fault_light_on`](#fault-light-on),
[`get_config`](#get-config),
[`get_data`](#get-data),
[`get_errors`](#get-errors),
[`get_hostname`](#get-hostname),
[`get_model`](#get-model),
[`reboot`](#reboot),
[`restart_backend`](#restart-backend),
[`stop_mining`](#stop-mining),
[`resume_mining`](#resume-mining),
[`is_mining`](#is-mining),
[`send_config`](#send-config), and
[`set_power_limit`](#set-power-limit).
[`check_light`][pyasic.miners.base.MinerProtocol.check_light],
[`fault_light_off`][pyasic.miners.base.MinerProtocol.fault_light_off],
[`fault_light_on`][pyasic.miners.base.MinerProtocol.fault_light_on],
[`get_config`][pyasic.miners.base.MinerProtocol.get_config],
[`get_data`][pyasic.miners.base.MinerProtocol.get_data],
[`get_errors`][pyasic.miners.base.MinerProtocol.get_errors],
[`get_hostname`][pyasic.miners.base.MinerProtocol.get_hostname],
[`get_model`][pyasic.miners.base.MinerProtocol.get_model],
[`reboot`][pyasic.miners.base.MinerProtocol.reboot],
[`restart_backend`][pyasic.miners.base.MinerProtocol.restart_backend],
[`stop_mining`][pyasic.miners.base.MinerProtocol.stop_mining],
[`resume_mining`][pyasic.miners.base.MinerProtocol.resume_mining],
[`is_mining`][pyasic.miners.base.MinerProtocol.is_mining],
[`send_config`][pyasic.miners.base.MinerProtocol.send_config], and
[`set_power_limit`][pyasic.miners.base.MinerProtocol.set_power_limit].
<br>
### Usage
```python
import asyncio# (1)!
from pyasic import get_miner# (2)!
### Check Light
::: pyasic.miners.BaseMiner.check_light
handler: python
options:
heading_level: 4
<br>
async def set_fault_light():# (3)!
miner = await get_miner("192.168.1.20")# (4)!
### Fault Light Off
::: pyasic.miners.BaseMiner.fault_light_off
handler: python
options:
heading_level: 4
await miner.fault_light_on()# (5)!
<br>
if __name__ == "__main__":
asyncio.run(set_fault_light())# (6)!
```
### Fault Light On
::: pyasic.miners.BaseMiner.fault_light_on
handler: python
options:
heading_level: 4
1. `asyncio` for handling the async part.
2. `get_miner` handles the miner type selection.
3. Define an async function to allow awaiting.
4. Get the miner.
5. Call the miner control function.
6. Call the control function asynchronously with asyncio.run().
<br>
### Get Config
::: pyasic.miners.BaseMiner.get_config
handler: python
options:
heading_level: 4
## Helper dataclasses
---
<br>
### [`MinerConfig`][pyasic.config.MinerConfig] and [`MinerData`][pyasic.data.MinerData]
### Get Data
::: pyasic.miners.BaseMiner.get_data
handler: python
options:
heading_level: 4
`pyasic` implements a few dataclasses as helpers to make data return types consistent across different miners and miner APIs. The different fields of these dataclasses can all be viewed with the classmethod `cls.fields()`.
<br>
### Get Errors
::: pyasic.miners.BaseMiner.get_errors
handler: python
options:
heading_level: 4
<br>
### Get Hostname
::: pyasic.miners.BaseMiner.get_hostname
handler: python
options:
heading_level: 4
<br>
### Get Model
::: pyasic.miners.BaseMiner.get_model
handler: python
options:
heading_level: 4
<br>
### Reboot
::: pyasic.miners.BaseMiner.reboot
handler: python
options:
heading_level: 4
<br>
### Restart Backend
::: pyasic.miners.BaseMiner.restart_backend
handler: python
options:
heading_level: 4
<br>
### Stop Mining
::: pyasic.miners.BaseMiner.stop_mining
handler: python
options:
heading_level: 4
<br>
### Resume Mining
::: pyasic.miners.BaseMiner.resume_mining
handler: python
options:
heading_level: 4
<br>
### Is Mining
::: pyasic.miners.BaseMiner.is_mining
handler: python
options:
heading_level: 4
<br>
### Send Config
::: pyasic.miners.BaseMiner.send_config
handler: python
options:
heading_level: 4
<br>
### Set Power Limit
::: pyasic.miners.BaseMiner.set_power_limit
handler: python
options:
heading_level: 4
<br>
## [`MinerConfig`][pyasic.config.MinerConfig] and [`MinerData`][pyasic.data.MinerData]
Pyasic implements a few dataclasses as helpers to make data return types consistent across different miners and miner APIs. The different fields of these dataclasses can all be viewed with the classmethod `cls.fields()`.
<br>
---
### [`MinerData`][pyasic.data.MinerData]
[`MinerData`][pyasic.data.MinerData] is a return from the [`get_data()`](#get-data) function, and is used to have a consistent dataset across all returns.
[`MinerData`][pyasic.data.MinerData] is a return from the [`get_data()`][pyasic.miners.base.MinerProtocol.get_data] function, and is used to have a consistent dataset across all returns.
You can call [`MinerData.as_dict()`][pyasic.data.MinerData.as_dict] to get the dataclass as a dictionary, and there are many other helper functions contained in the class to convert to different data formats.
@@ -278,37 +221,69 @@ list_of_miner_data = [d1, d2]
average_data = sum(list_of_miner_data, start=MinerData("0.0.0.0"))/len(list_of_miner_data)
```
<br>
---
### [`MinerConfig`][pyasic.config.MinerConfig]
[`MinerConfig`][pyasic.config.MinerConfig] is pyasic's way to represent a configuration file from a miner.
It is the return from [`get_config()`](#get-config).
[`MinerConfig`][pyasic.config.MinerConfig] is `pyasic`'s way to represent a configuration file from a miner.
It is designed to unionize the configuration of all supported miner types, and is the return from [`get_config()`][pyasic.miners.base.MinerProtocol.get_config].
Each miner has a unique way to convert the [`MinerConfig`][pyasic.config.MinerConfig] to their specific type, there are helper functions in the class.
In most cases these helper functions should not be used, as [`send_config()`](#send-config) takes a [`MinerConfig`][pyasic.config.MinerConfig] and will do the conversion to the right type for you.
In most cases these helper functions should not be used, as [`send_config()`][pyasic.miners.base.MinerProtocol.send_config] takes a [`MinerConfig`][pyasic.config.MinerConfig] and will do the conversion to the right type for you.
You can use the [`MinerConfig`][pyasic.config.MinerConfig] as follows:
```python
import asyncio
from pyasic import get_miner
async def set_fault_light():
miner = await get_miner("192.168.1.20")
# get config
cfg = await miner.get_config()
# send config
await miner.send_config(cfg)
if __name__ == "__main__":
asyncio.run(set_fault_light())
```
## Settings
`pyasic` has settings designed to make using large groups of miners easier. You can set the default password for all types of miners using the [`pyasic.settings`][pyasic.settings] module, used as follows:
---
`pyasic` has settings designed to make using large groups of miners easier. You can set the default password for all types of miners using the `pyasic.settings` module, used as follows:
```python
from pyasic import settings
settings.update("default_antminer_password", "my_pwd")
settings.update("default_antminer_web_password", "my_pwd")
```
Here are of all the settings, and their default values:
### Default values:
```
"network_ping_retries": 1,
"network_ping_timeout": 3,
"network_scan_threads": 300,
"network_scan_semaphore": None,
"factory_get_retries": 1,
"factory_get_timeout": 3,
"get_data_retries": 1,
"default_whatsminer_password": "admin",
"default_innosilicon_password": "admin",
"default_antminer_password": "root",
"default_bosminer_password": "root",
"default_vnish_password": "admin",
"default_goldshell_password": "123456789",
"api_function_timeout": 5,
"antminer_mining_mode_as_str": False,
"default_whatsminer_rpc_password": "admin",
"default_innosilicon_web_password": "admin",
"default_antminer_web_password": "root",
"default_bosminer_web_password": "root",
"default_vnish_web_password": "admin",
"default_goldshell_web_password": "123456789",
"default_auradine_web_password": "admin",
"default_epic_web_password": "letmein",
"default_hive_web_password": "admin",
"default_antminer_ssh_password": "miner",
"default_bosminer_ssh_password": "root",
# ADVANCED
# Only use this if you know what you are doing
"socket_linger_time": 1000,
```

View File

@@ -1,10 +1,29 @@
# pyasic
## X15 Models
## Z15
## Z15 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.cgminer.X15.Z15.CGMinerZ15
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## Z15 Pro (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X15.Z15.BMMinerZ15Pro
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,115 +1,211 @@
# pyasic
## X17 Models
## S17
## S17 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S17+
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Plus
handler: python
options:
show_root_heading: false
heading_level: 4
## S17 Pro (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## S17 Pro
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Pro
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S17+ (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17Plus
handler: python
options:
show_root_heading: false
heading_level: 0
## S17e (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## S17e
::: pyasic.miners.antminer.bmminer.X17.S17.BMMinerS17e
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## T17 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## T17
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## T17+ (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## T17+
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17Plus
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## T17e (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## T17e
::: pyasic.miners.antminer.bmminer.X17.T17.BMMinerT17e
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S17 (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
## S17 (BOS)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S17+ (BOS)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Plus
handler: python
options:
show_root_heading: false
heading_level: 4
## S17 Pro (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
## S17 Pro (BOS)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Pro
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S17+ (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17Plus
handler: python
options:
show_root_heading: false
heading_level: 0
## S17e (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
## S17e (BOS)
::: pyasic.miners.antminer.bosminer.X17.S17.BOSMinerS17e
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## T17 (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
## T17 (BOS)
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## T17+ (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
## T17+ (BOS)
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17Plus
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## T17e (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
## T17e (BOS)
::: pyasic.miners.antminer.bosminer.X17.T17.BOSMinerT17e
handler: python
options:
show_root_heading: false
heading_level: 4
## S17+ (VNish)
::: pyasic.miners.antminer.vnish.X17.S17.VNishS17Plus
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S17 Pro (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X17.S17.VNishS17Pro
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S17+ (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X17.S17.VNishS17Plus
handler: python
options:
show_root_heading: false
heading_level: 0

File diff suppressed because it is too large Load Diff

328
docs/miners/antminer/X21.md Normal file
View File

@@ -0,0 +1,328 @@
# pyasic
## X21 Models
## S21 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 Hydro (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21Hydro
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 Pro (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21Pro
handler: python
options:
show_root_heading: false
heading_level: 0
## S21+ (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21Plus
handler: python
options:
show_root_heading: false
heading_level: 0
## S21+ Hydro (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X21.S21.BMMinerS21PlusHydro
handler: python
options:
show_root_heading: false
heading_level: 0
## T21 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X21.T21.BMMinerT21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bosminer.X21.S21.BOSMinerS21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 Hydro (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bosminer.X21.S21.BOSMinerS21Hydro
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 Pro (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bosminer.X21.S21.BOSMinerS21Pro
handler: python
options:
show_root_heading: false
heading_level: 0
## S21+ (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bosminer.X21.S21.BOSMinerS21Plus
handler: python
options:
show_root_heading: false
heading_level: 0
## S21+ Hydro (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bosminer.X21.S21.BOSMinerS21PlusHydro
handler: python
options:
show_root_heading: false
heading_level: 0
## T21 (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bosminer.X21.T21.BOSMinerT21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X21.S21.VNishS21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 Hydro (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X21.S21.VNishS21Hydro
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 Pro (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X21.S21.VNishS21Pro
handler: python
options:
show_root_heading: false
heading_level: 0
## S21+ (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X21.S21.VNishS21Plus
handler: python
options:
show_root_heading: false
heading_level: 0
## S21+ Hydro (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X21.S21.VNishS21PlusHydro
handler: python
options:
show_root_heading: false
heading_level: 0
## T21 (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X21.T21.VNishT21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 (ePIC)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.epic.X21.S21.ePICS21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 Pro (ePIC)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.epic.X21.S21.ePICS21Pro
handler: python
options:
show_root_heading: false
heading_level: 0
## T21 (ePIC)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.epic.X21.T21.ePICT21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 (LuxOS)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.luxos.X21.S21.LUXMinerS21
handler: python
options:
show_root_heading: false
heading_level: 0
## T21 (LuxOS)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.luxos.X21.T21.LUXMinerT21
handler: python
options:
show_root_heading: false
heading_level: 0
## S21 (MaraFW)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.marathon.X21.S21.MaraS21
handler: python
options:
show_root_heading: false
heading_level: 0
## T21 (MaraFW)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.marathon.X21.T21.MaraT21
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,31 +1,81 @@
# pyasic
## X3 Models
## D3
## D3 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.cgminer.X3.D3.CGMinerD3
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## HS3 (Stock)
- [ ] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
## HS3
::: pyasic.miners.antminer.bmminer.X3.HS3.BMMinerHS3
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## KA3 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X3.KA3.BMMinerKA3
handler: python
options:
show_root_heading: false
heading_level: 0
## KS3 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X3.KS3.BMMinerKS3
handler: python
options:
show_root_heading: false
heading_level: 0
## L3+ (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## L3+
::: pyasic.miners.antminer.bmminer.X3.L3.BMMinerL3Plus
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## L3+ (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X3.L3.VnishL3Plus
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -1,10 +1,42 @@
# pyasic
## X5 Models
## DR5
## DR5 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.cgminer.X5.DR5.CGMinerDR5
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## KS5 (Stock)
- [ ] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X5.KS5.BMMinerKS5
handler: python
options:
show_root_heading: false
heading_level: 0
## KS5 (Stock)
- [ ] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X5.KS5.BMMinerKS5Pro
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,10 +1,55 @@
# pyasic
## X7 Models
## L7
## D7 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X7.D7.BMMinerD7
handler: python
options:
show_root_heading: false
heading_level: 0
## K7 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X7.K7.BMMinerK7
handler: python
options:
show_root_heading: false
heading_level: 0
## L7 (Stock)
- [ ] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X7.L7.BMMinerL7
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## L7 (VNish)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.vnish.X7.L7.VnishL7
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,59 +1,133 @@
# pyasic
## X9 Models
## E9Pro
## D9 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X9.D9.BMMinerD9
handler: python
options:
show_root_heading: false
heading_level: 0
## E9Pro (Stock)
- [ ] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X9.E9.BMMinerE9Pro
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## L9 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.antminer.bmminer.X9.L9.BMMinerL9
handler: python
options:
show_root_heading: false
heading_level: 0
## S9 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## S9
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S9i (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## S9i
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9i
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S9j (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## S9j
::: pyasic.miners.antminer.bmminer.X9.S9.BMMinerS9j
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## T9 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## T9
::: pyasic.miners.antminer.bmminer.X9.T9.BMMinerT9
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S9 (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
## S9 (BOS)
::: pyasic.miners.antminer.bosminer.X9.S9.BOSMinerS9
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## T9 (Hive)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## T9 (Hiveon)
::: pyasic.miners.antminer.hiveon.X9.T9.HiveonT9
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## S9 (LuxOS)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [x] Presets
::: pyasic.miners.antminer.luxos.X9.S9.LUXMinerS9
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -0,0 +1,42 @@
# pyasic
## AD Models
## AT1500 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.auradine.flux.AD.AT1.AuradineFluxAT1500
handler: python
options:
show_root_heading: false
heading_level: 0
## AT2860 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.auradine.flux.AD.AT2.AuradineFluxAT2860
handler: python
options:
show_root_heading: false
heading_level: 0
## AT2880 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.auradine.flux.AD.AT2.AuradineFluxAT2880
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -0,0 +1,29 @@
# pyasic
## AI Models
## AI2500 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.auradine.flux.AI.AI2.AuradineFluxAI2500
handler: python
options:
show_root_heading: false
heading_level: 0
## AI3680 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.auradine.flux.AI.AI3.AuradineFluxAI3680
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -0,0 +1,29 @@
# pyasic
## AT Models
## AD2500 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.auradine.flux.AT.AD2.AuradineFluxAD2500
handler: python
options:
show_root_heading: false
heading_level: 0
## AD3500 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.auradine.flux.AT.AD3.AuradineFluxAD3500
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,24 +1,42 @@
# pyasic
## A10X Models
## Avalon 1026
## Avalon 1026 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.A10X.A1026.CGMinerAvalon1026
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## Avalon 1047 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## Avalon 1047
::: pyasic.miners.avalonminer.cgminer.A10X.A1047.CGMinerAvalon1047
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## Avalon 1066 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## Avalon 1066
::: pyasic.miners.avalonminer.cgminer.A10X.A1066.CGMinerAvalon1066
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -1,10 +1,29 @@
# pyasic
## A11X Models
## Avalon 1166 Pro
## Avalon 1126 Pro (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.A11X.A1126.CGMinerAvalon1126Pro
handler: python
options:
show_root_heading: false
heading_level: 0
## Avalon 1166 Pro (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.A11X.A1166.CGMinerAvalon1166Pro
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -1,10 +1,16 @@
# pyasic
## A12X Models
## Avalon 1246
## Avalon 1246 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.A12X.A1246.CGMinerAvalon1246
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -0,0 +1,16 @@
# pyasic
## A15X Models
## Avalon 1566 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.A15X.A1566.CGMinerAvalon1566
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,24 +1,42 @@
# pyasic
## A7X Models
## Avalon 721
## Avalon 721 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.A7X.A721.CGMinerAvalon721
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## Avalon 741 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## Avalon 741
::: pyasic.miners.avalonminer.cgminer.A7X.A741.CGMinerAvalon741
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## Avalon 761 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## Avalon 761
::: pyasic.miners.avalonminer.cgminer.A7X.A761.CGMinerAvalon761
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -1,24 +1,42 @@
# pyasic
## A8X Models
## Avalon 821
## Avalon 821 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.A8X.A821.CGMinerAvalon821
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## Avalon 841 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## Avalon 841
::: pyasic.miners.avalonminer.cgminer.A8X.A841.CGMinerAvalon841
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## Avalon 851 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
## Avalon 851
::: pyasic.miners.avalonminer.cgminer.A8X.A851.CGMinerAvalon851
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -1,10 +1,16 @@
# pyasic
## A9X Models
## Avalon 921
## Avalon 921 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.A9X.A921.CGMinerAvalon921
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -0,0 +1,29 @@
# pyasic
## nano Models
## Avalon Nano 3s (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.nano.nano3.CGMinerAvalonNano3s
handler: python
options:
show_root_heading: false
heading_level: 0
## Avalon Nano 3 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.avalonminer.cgminer.nano.nano3.CGMinerAvalonNano3
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,7 +1,15 @@
# pyasic
## 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
options:
show_root_heading: false

View File

@@ -1,6 +1,7 @@
# pyasic
## BFGMinerAPI
::: pyasic.API.bfgminer.BFGMinerAPI
## ePIC Backend
::: pyasic.miners.backends.epic.ePIC
handler: python
options:
show_root_heading: false

View File

@@ -1,7 +1,14 @@
# pyasic
## Hiveon Backend
## Modern Hiveon Backend
::: pyasic.miners.backends.hiveon.Hiveon
::: pyasic.miners.backends.hiveon.HiveonModern
handler: python
options:
show_root_heading: false
heading_level: 4
## Old Hiveon Backend
::: pyasic.miners.backends.hiveon.HiveonOld
handler: python
options:
show_root_heading: false

View File

@@ -1,10 +1,12 @@
# pyasic
## 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

55
docs/miners/bitaxe/BM.md Normal file
View File

@@ -0,0 +1,55 @@
# pyasic
## BM Models
## Ultra (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.bitaxe.espminer.BM.BM1366.BitAxeUltra
handler: python
options:
show_root_heading: false
heading_level: 0
## Supra (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.bitaxe.espminer.BM.BM1368.BitAxeSupra
handler: python
options:
show_root_heading: false
heading_level: 0
## Gamma (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.bitaxe.espminer.BM.BM1370.BitAxeGamma
handler: python
options:
show_root_heading: false
heading_level: 0
## Max (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.bitaxe.espminer.BM.BM1397.BitAxeMax
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -0,0 +1,42 @@
# pyasic
## blockminer Models
## BlockMiner 520i (ePIC)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.blockminer.epic.blockminer.blockminer.ePICBlockMiner520i
handler: python
options:
show_root_heading: false
heading_level: 0
## BlockMiner 720i (ePIC)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.blockminer.epic.blockminer.blockminer.ePICBlockMiner720i
handler: python
options:
show_root_heading: false
heading_level: 0
## BlockMiner eLITE 1.0 (ePIC)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.blockminer.epic.blockminer.blockminer.ePICBlockMinerELITE1
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -0,0 +1,29 @@
# pyasic
## BMM Models
## BMM100 (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.braiins.braiins.BMM.BMM.BraiinsBMM100
handler: python
options:
show_root_heading: false
heading_level: 0
## BMM101 (BOS+)
- [x] Shutdowns
- [ ] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.braiins.braiins.BMM.BMM.BraiinsBMM101
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -0,0 +1,16 @@
# pyasic
## DGX Models
## DG1+ (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.elphapex.daoge.DGX.DG1.ElphapexDG1Plus
handler: python
options:
show_root_heading: false
heading_level: 0

10
docs/miners/functions.md Normal file
View File

@@ -0,0 +1,10 @@
## Control functionality
All control functionality is outlined by the [`MinerProtocol`][pyasic.miners.base.MinerProtocol] class.
## Miner Protocol
::: pyasic.miners.base.MinerProtocol
handler: python
options:
heading_level: 4

View File

@@ -1,24 +1,42 @@
# pyasic
## X5 Models
## CK5
::: pyasic.miners.goldshell.bfgminer.X5.CK5.BFGMinerCK5
## CK5 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.goldshell.bfgminer.X5.CK5.GoldshellCK5
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## HS5
::: pyasic.miners.goldshell.bfgminer.X5.HS5.BFGMinerHS5
## HS5 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.goldshell.bfgminer.X5.HS5.GoldshellHS5
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## KD5
::: pyasic.miners.goldshell.bfgminer.X5.KD5.BFGMinerKD5
## KD5 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.goldshell.bfgminer.X5.KD5.GoldshellKD5
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -0,0 +1,29 @@
# pyasic
## XBox Models
## KD Box II (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.goldshell.bfgminer.XBox.KDBox.GoldshellKDBoxII
handler: python
options:
show_root_heading: false
heading_level: 0
## KD Box Pro (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.goldshell.bfgminer.XBox.KDBox.GoldshellKDBoxPro
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,10 +1,16 @@
# pyasic
## XMax Models
## KD Max
::: pyasic.miners.goldshell.bfgminer.XMax.KDMax.BFGMinerKDMax
## KD Max (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.goldshell.bfgminer.XMax.KDMax.GoldshellKDMax
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

16
docs/miners/hammer/DX.md Normal file
View File

@@ -0,0 +1,16 @@
# pyasic
## DX Models
## D10 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.hammer.blackminer.DX.D10.HammerD10
handler: python
options:
show_root_heading: false
heading_level: 0

120
docs/miners/iceriver/KSX.md Normal file
View File

@@ -0,0 +1,120 @@
# pyasic
## KSX Models
## KS0 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS0.IceRiverKS0
handler: python
options:
show_root_heading: false
heading_level: 0
## KS1 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS1.IceRiverKS1
handler: python
options:
show_root_heading: false
heading_level: 0
## KS2 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS2.IceRiverKS2
handler: python
options:
show_root_heading: false
heading_level: 0
## KS3 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3
handler: python
options:
show_root_heading: false
heading_level: 0
## KS3L (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3L
handler: python
options:
show_root_heading: false
heading_level: 0
## KS3M (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS3.IceRiverKS3M
handler: python
options:
show_root_heading: false
heading_level: 0
## KS5 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS5.IceRiverKS5
handler: python
options:
show_root_heading: false
heading_level: 0
## KS5L (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS5.IceRiverKS5L
handler: python
options:
show_root_heading: false
heading_level: 0
## KS5M (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.iceriver.iceminer.KSX.KS5.IceRiverKS5M
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,10 +1,16 @@
# pyasic
## A10X Models
## A10X
::: pyasic.miners.innosilicon.cgminer.A10X.A10X.CGMinerA10X
## A10X (Stock)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.innosilicon.cgminer.A10X.A10X.InnosiliconA10X
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -0,0 +1,29 @@
# pyasic
## A11X Models
## A11 (Stock)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.innosilicon.cgminer.A11X.A11.InnosiliconA11
handler: python
options:
show_root_heading: false
heading_level: 0
## A11MX (Stock)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.innosilicon.cgminer.A11X.A11M.InnosiliconA11MX
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,10 +1,16 @@
# pyasic
## T3X Models
## T3H+
::: pyasic.miners.innosilicon.cgminer.T3X.T3H.CGMinerT3HPlus
## T3H+ (Stock)
- [x] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.innosilicon.cgminer.T3X.T3H.InnosiliconT3HPlus
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

View File

@@ -0,0 +1,29 @@
# pyasic
## LV Models
## LV07 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.luckyminer.espminer.LV.LV07.LuckyMinerLV07
handler: python
options:
show_root_heading: false
heading_level: 0
## LV08 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.luckyminer.espminer.LV.LV08.LuckyMinerLV08
handler: python
options:
show_root_heading: false
heading_level: 0

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
# pyasic
## DX Models
## D1 (Stock)
- [ ] Shutdowns
- [ ] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.volcminer.blackminer.DX.D1.VolcMinerD1
handler: python
options:
show_root_heading: false
heading_level: 0

View File

@@ -1,80 +1,172 @@
# pyasic
## M2X Models
## M20 V10
::: pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20V10
## M20P V10 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV10
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## M20S V10
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV10
## M20P V30 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M20P.BTMinerM20PV30
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## M20S V20
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV20
handler: python
options:
show_root_heading: false
heading_level: 4
## M20S+ V30 (Stock)
## M20S V30
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV30
handler: python
options:
show_root_heading: false
heading_level: 4
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
## M20S+ V30
::: pyasic.miners.whatsminer.btminer.M2X.M20S_Plus.BTMinerM20SPlusV30
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## M21 V10
::: pyasic.miners.whatsminer.btminer.M2X.M21.BTMinerM21V10
## M20S V10 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV10
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## M21S V20
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV20
## M20S V20 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV20
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## M21S V60
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV60
## M20S V30 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M20S.BTMinerM20SV30
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## M21S V70
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV70
## M20 V10 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M20.BTMinerM20V10
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## M21S+ V20 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
## M21S+ V20
::: pyasic.miners.whatsminer.btminer.M2X.M21S_Plus.BTMinerM21SPlusV20
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0
## M21S V20 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV20
handler: python
options:
show_root_heading: false
heading_level: 0
## M21S V60 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV60
handler: python
options:
show_root_heading: false
heading_level: 0
## M21S V70 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M21S.BTMinerM21SV70
handler: python
options:
show_root_heading: false
heading_level: 0
## M21 V10 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M2X.M21.BTMinerM21V10
handler: python
options:
show_root_heading: false
heading_level: 0
## M29 V10 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [ ] Setpoints
- [ ] Presets
## M29 V10
::: pyasic.miners.whatsminer.btminer.M2X.M29.BTMinerM29V10
handler: python
options:
show_root_heading: false
heading_level: 4
heading_level: 0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
# pyasic
## M7X Models
## M70 VM30 (Stock)
- [x] Shutdowns
- [x] Power Modes
- [x] Setpoints
- [ ] Presets
::: pyasic.miners.whatsminer.btminer.M7X.M70.BTMinerM70VM30
handler: python
options:
show_root_heading: false
heading_level: 0

View File

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

View File

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

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

@@ -0,0 +1,27 @@
# pyasic
## Miner RPC APIs
Each miner has a unique RPC API that is used to communicate with it.
Each of these API types has commands that differ between them, and some commands have data that others do not.
Each miner that is a subclass of [`BaseMiner`][pyasic.miners.base.BaseMiner] may have an API linked to it as `Miner.rpc`.
All RPC API implementations inherit from [`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI], which implements the basic communications protocols.
[`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI] should never be used unless inheriting to create a new miner API class for a new type of miner (which should be exceedingly rare).
[`BaseMinerRPCAPI`][pyasic.rpc.base.BaseMinerRPCAPI] 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

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

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

View File

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

7
docs/rpc/bosminer.md Normal file
View File

@@ -0,0 +1,7 @@
# pyasic
## BOSMinerRPCAPI
::: pyasic.rpc.bosminer.BOSMinerRPCAPI
handler: python
options:
show_root_heading: false
heading_level: 4

7
docs/rpc/btminer.md Normal file
View File

@@ -0,0 +1,7 @@
# pyasic
## BTMinerRPCAPI
::: pyasic.rpc.btminer.BTMinerRPCAPI
handler: python
options:
show_root_heading: false
heading_level: 4

7
docs/rpc/cgminer.md Normal file
View File

@@ -0,0 +1,7 @@
# pyasic
## CGMinerRPCAPI
::: pyasic.rpc.cgminer.CGMinerRPCAPI
handler: python
options:
show_root_heading: false
heading_level: 4

View File

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

View File

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

View File

@@ -1,11 +1,29 @@
# pyasic
## settings
::: pyasic.settings
handler: python
options:
show_root_heading: false
heading_level: 4
All settings here are global settings for all of pyasic. Set these settings with `update(key, value)`.
Settings options:
- `network_ping_retries`
- `network_ping_timeout`
- `network_scan_threads`
- `factory_get_retries`
- `factory_get_timeout`
- `get_data_retries`
- `api_function_timeout`
- `antminer_mining_mode_as_str`
- `default_whatsminer_rpc_password`
- `default_innosilicon_web_password`
- `default_antminer_web_password`
- `default_bosminer_web_password`
- `default_vnish_web_password`
- `default_goldshell_web_password`
- `default_auradine_web_password`
- `default_epic_web_password`
- `default_hive_web_password`
- `default_antminer_ssh_password`
- `default_bosminer_ssh_password`
### get

14
docs/web/antminer.md Normal file
View File

@@ -0,0 +1,14 @@
# pyasic
## AntminerModernWebAPI
::: pyasic.web.antminer.AntminerModernWebAPI
handler: python
options:
show_root_heading: false
heading_level: 4
## AntminerOldWebAPI
::: pyasic.web.antminer.AntminerOldWebAPI
handler: python
options:
show_root_heading: false
heading_level: 4

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

@@ -0,0 +1,27 @@
# pyasic
## Miner Web APIs
Each miner has a unique Web API that is used to communicate with it.
Each of these API types has commands that differ between them, and some commands have data that others do not.
Each miner that is a subclass of [`BaseMiner`][pyasic.miners.base.BaseMiner] may have an API linked to it as `Miner.web`.
All API implementations inherit from [`BaseWebAPI`][pyasic.web.BaseWebAPI], which implements the basic communications protocols.
[`BaseWebAPI`][pyasic.web.BaseWebAPI] should never be used unless inheriting to create a new miner API class for a new type of miner (which should be exceedingly rare).
Use these instead -
#### [AntminerModerNWebAPI][pyasic.web.antminer.AntminerModernWebAPI]
#### [AntminerOldWebAPI][pyasic.web.antminer.AntminerOldWebAPI]
#### [AuradineWebAPI][pyasic.web.auradine.AuradineWebAPI]
#### [ePICWebAPI][pyasic.web.epic.ePICWebAPI]
#### [GoldshellWebAPI][pyasic.web.goldshell.GoldshellWebAPI]
#### [InnosiliconWebAPI][pyasic.web.innosilicon.InnosiliconWebAPI]
#### [MaraWebAPI][pyasic.web.marathon.MaraWebAPI]
#### [VNishWebAPI][pyasic.web.vnish.VNishWebAPI]
<br>
## BaseWebAPI
::: pyasic.web.BaseWebAPI
handler: python
options:
heading_level: 4

7
docs/web/auradine.md Normal file
View File

@@ -0,0 +1,7 @@
# pyasic
## AuradineWebAPI
::: pyasic.web.auradine.AuradineWebAPI
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,6 +1,6 @@
# pyasic
## BTMinerAPI
::: pyasic.API.btminer.BTMinerAPI
## ePICWebAPI
::: pyasic.web.epic.ePICWebAPI
handler: python
options:
show_root_heading: false

7
docs/web/goldshell.md Normal file
View File

@@ -0,0 +1,7 @@
# pyasic
## GoldshellWebAPI
::: pyasic.web.goldshell.GoldshellWebAPI
handler: python
options:
show_root_heading: false
heading_level: 4

7
docs/web/innosilicon.md Normal file
View File

@@ -0,0 +1,7 @@
# pyasic
## InnosiliconWebAPI
::: pyasic.web.innosilicon.InnosiliconWebAPI
handler: python
options:
show_root_heading: false
heading_level: 4

View File

@@ -1,6 +1,6 @@
# pyasic
## BMMinerAPI
::: pyasic.API.bmminer.BMMinerAPI
## MaraWebAPI
::: pyasic.web.marathon.MaraWebAPI
handler: python
options:
show_root_heading: false

View File

@@ -1,6 +1,6 @@
# pyasic
## CGMinerAPI
::: pyasic.API.cgminer.CGMinerAPI
## VNishWebAPI
::: pyasic.web.vnish.VNishWebAPI
handler: python
options:
show_root_heading: false

View File

@@ -1,27 +1,67 @@
site_name: pyasic
repo_url: https://github.com/UpstreamData/pyasic
site_url: !ENV SITE_URL
theme:
name: material
features:
- content.code.copy
- content.code.annotate
palette:
- media: "(prefers-color-scheme)"
toggle:
icon: material/brightness-auto
name: Switch to light mode
- media: "(prefers-color-scheme: light)"
scheme: default
toggle:
icon: material/weather-night
name: Switch to dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
toggle:
icon: material/weather-sunny
name: Switch to auto mode
markdown_extensions:
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.inlinehilite
- pymdownx.snippets
- pymdownx.superfences
nav:
- Introduction: "index.md"
- Miners:
- Supported Miners: "miners/supported_types.md"
- Standard Functionality: "miners/functions.md"
- Miner Factory: "miners/miner_factory.md"
- Network:
- Miner Network: "network/miner_network.md"
- Miner Network Range: "network/miner_network_range.md"
- Dataclasses:
- Miner Data: "data/miner_data.md"
- Error Codes: "data/error_codes.md"
- Miner Config: "config/miner_config.md"
- Advanced:
- Miner APIs:
- Intro: "API/api.md"
- BFGMiner: "API/bfgminer.md"
- BMMiner: "API/bmminer.md"
- BOSMiner: "API/bosminer.md"
- BTMiner: "API/btminer.md"
- CGMiner: "API/cgminer.md"
- LUXMiner: "API/luxminer.md"
- Unknown: "API/unknown.md"
- RPC APIs:
- Intro: "rpc/api.md"
- BFGMiner: "rpc/bfgminer.md"
- BMMiner: "rpc/bmminer.md"
- BOSMiner: "rpc/bosminer.md"
- BTMiner: "rpc/btminer.md"
- CGMiner: "rpc/cgminer.md"
- LUXMiner: "rpc/luxminer.md"
- Unknown: "rpc/unknown.md"
- Web APIs:
- Intro: "web/api.md"
- Antminer: "web/antminer.md"
- Auradine: "web/auradine.md"
- ePIC: "web/epic.md"
- Goldshell: "web/goldshell.md"
- Innosilicon: "web/innosilicon.md"
- Marathon: "web/marathon.md"
- VNish: "web/vnish.md"
- Backends:
- BMMiner: "miners/backends/bmminer.md"
- BOSMiner: "miners/backends/bosminer.md"
@@ -30,6 +70,7 @@ nav:
- CGMiner: "miners/backends/cgminer.md"
- LUXMiner: "miners/backends/luxminer.md"
- VNish: "miners/backends/vnish.md"
- ePIC: "miners/backends/epic.md"
- Hiveon: "miners/backends/hiveon.md"
- Classes:
- Antminer X3: "miners/antminer/X3.md"
@@ -39,6 +80,9 @@ nav:
- Antminer X15: "miners/antminer/X15.md"
- Antminer X17: "miners/antminer/X17.md"
- Antminer X19: "miners/antminer/X19.md"
- Antminer X21: "miners/antminer/X21.md"
- Braiins Mini Miners: "miners/braiins/BMM.md"
- Avalon Nano: "miners/avalonminer/nano.md"
- Avalon 7X: "miners/avalonminer/A7X.md"
- Avalon 8X: "miners/avalonminer/A8X.md"
- Avalon 9X: "miners/avalonminer/A9X.md"
@@ -48,10 +92,22 @@ nav:
- Whatsminer M2X: "miners/whatsminer/M2X.md"
- Whatsminer M3X: "miners/whatsminer/M3X.md"
- Whatsminer M5X: "miners/whatsminer/M5X.md"
- Whatsminer M6X: "miners/whatsminer/M6X.md"
- Whatsminer M7X: "miners/whatsminer/M7X.md"
- Innosilicon T3X: "miners/innosilicon/T3X.md"
- Innosilicon A10X: "miners/innosilicon/A10X.md"
- Innosilicon A11X: "miners/innosilicon/A11X.md"
- Goldshell X5: "miners/goldshell/X5.md"
- Goldshell XMax: "miners/goldshell/XMax.md"
- Goldshell XBox: "miners/goldshell/XBox.md"
- Auradine AD: "miners/auradine/AD.md"
- Auradine AI: "miners/auradine/AI.md"
- Auradine AT: "miners/auradine/AT.md"
- Blockminer: "miners/blockminer/blockminer.md"
- BitAxe BM: "miners/bitaxe/BM.md"
- Hammer DX: "miners/hammer/DX.md"
- Iceriver KSX: "miners/iceriver/KSX.md"
- Volcminer DX: "miners/volcminer/DX.md"
- Base Miner: "miners/base_miner.md"
- Settings:
- Settings: "settings/settings.md"

1705
poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

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

@@ -13,46 +13,16 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
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.data import (
BraiinsOSError,
InnosiliconError,
MinerData,
WhatsminerError,
X19Error,
)
from pyasic.errors import APIError, APIWarning
from pyasic.miners import get_miner
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
import importlib.metadata
__all__ = [
"BMMinerAPI",
"BOSMinerAPI",
"BTMinerAPI",
"CGMinerAPI",
"UnknownAPI",
"MinerConfig",
"MinerData",
"BraiinsOSError",
"InnosiliconError",
"WhatsminerError",
"X19Error",
"APIError",
"APIWarning",
"get_miner",
"AnyMiner",
"MinerFactory",
"miner_factory",
"MinerListener",
"MinerNetwork",
"settings",
]
from pyasic import settings
from pyasic.config import MinerConfig
from pyasic.data import MinerData
from pyasic.errors import APIError, APIWarning
from pyasic.miners import *
from pyasic.network import MinerNetwork
from pyasic.rpc import *
from pyasic.ssh import *
from pyasic.web import *
__version__ = importlib.metadata.version("pyasic")

View File

@@ -14,663 +14,339 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
import logging
import random
import string
import time
from dataclasses import asdict, dataclass, fields
from enum import IntEnum
from typing import List, Literal
from pydantic import BaseModel, Field
import toml
import yaml
from pyasic.config.fans import FanMode, FanModeConfig, FanModeNormal
from pyasic.config.mining import MiningMode, MiningModeConfig
from pyasic.config.mining.scaling import ScalingConfig
from pyasic.config.pools import PoolConfig
from pyasic.config.temperature import TemperatureConfig
from pyasic.misc import merge_dicts
class X19PowerMode(IntEnum):
Normal = 0
Sleep = 1
LPM = 3
class MinerConfig(BaseModel):
"""Represents the configuration for a miner including pool configuration,
fan mode, temperature settings, mining mode, and power scaling."""
class Config:
arbitrary_types_allowed = True
@dataclass
class _Pool:
"""A dataclass for pool information.
pools: PoolConfig = Field(default_factory=PoolConfig.default)
fan_mode: FanMode = Field(default_factory=FanModeConfig.default)
temperature: TemperatureConfig = Field(default_factory=TemperatureConfig.default)
mining_mode: MiningMode = Field(default_factory=MiningModeConfig.default)
Attributes:
url: URL of the pool.
username: Username on the pool.
password: Worker password on the pool.
"""
url: str = ""
username: str = ""
password: str = ""
@classmethod
def fields(cls):
return fields(cls)
def from_dict(self, data: dict):
"""Convert raw pool data as a dict to usable data and save it to this class.
Parameters:
data: The raw config data to convert.
"""
for key in data.keys():
if key == "url":
self.url = data[key]
if key in ["user", "username"]:
self.username = data[key]
if key in ["pass", "password"]:
self.password = data[key]
return self
def as_wm(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an Whatsminer device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_x19(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an X19 device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_x17(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an X5 device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_goldshell(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by a goldshell device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "pass": self.password}
return pool
def as_inno(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an Innosilicon device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {
f"Pool": self.url,
f"UserName": username,
f"Password": self.password,
}
return pool
def as_avalon(self, user_suffix: str = None) -> str:
"""Convert the data in this class to a string usable by an Avalonminer device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = ",".join([self.url, username, self.password])
return pool
def as_bos(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an BOSMiner device.
Parameters:
user_suffix: The suffix to append to username.
"""
username = self.username
if user_suffix:
username = f"{username}{user_suffix}"
pool = {"url": self.url, "user": username, "password": self.password}
return pool
@dataclass
class _PoolGroup:
"""A dataclass for pool group information.
Attributes:
quota: The group quota.
group_name: The name of the pool group.
pools: A list of pools in this group.
"""
quota: int = 1
group_name: str = None
pools: List[_Pool] = None
@classmethod
def fields(cls):
return fields(cls)
def __post_init__(self):
if not self.group_name:
self.group_name = "".join(
random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
) # generate random pool group name in case it isn't set
def from_dict(self, data: dict):
"""Convert raw pool group data as a dict to usable data and save it to this class.
Parameters:
data: The raw config data to convert.
"""
pools = []
for key in data.keys():
if key in ["name", "group_name"]:
self.group_name = data[key]
if key == "quota":
self.quota = data[key]
if key in ["pools", "pool"]:
for pool in data[key]:
pools.append(_Pool().from_dict(pool))
self.pools = pools
return self
def as_x19(self, user_suffix: str = None) -> List[dict]:
"""Convert the data in this class to a list usable by an X19 device.
Parameters:
user_suffix: The suffix to append to username.
"""
pools = []
for pool in self.pools[:3]:
pools.append(pool.as_x19(user_suffix=user_suffix))
return pools
def as_x17(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by an X17 device.
Parameters:
user_suffix: The suffix to append to username.
"""
pools = {
"_ant_pool1url": "",
"_ant_pool1user": "",
"_ant_pool1pw": "",
"_ant_pool2url": "",
"_ant_pool2user": "",
"_ant_pool2pw": "",
"_ant_pool3url": "",
"_ant_pool3user": "",
"_ant_pool3pw": "",
}
for idx, pool in enumerate(self.pools[:3]):
pools[f"_ant_pool{idx+1}url"] = pool.as_x17(user_suffix=user_suffix)["url"]
pools[f"_ant_pool{idx+1}user"] = pool.as_x17(user_suffix=user_suffix)[
"user"
]
pools[f"_ant_pool{idx+1}pw"] = pool.as_x17(user_suffix=user_suffix)["pass"]
return pools
def as_goldshell(self, user_suffix: str = None) -> list:
"""Convert the data in this class to a list usable by a goldshell device.
Parameters:
user_suffix: The suffix to append to username.
"""
return [pool.as_goldshell(user_suffix=user_suffix) for pool in self.pools[:3]]
def as_inno(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by an Innosilicon device.
Parameters:
user_suffix: The suffix to append to username.
"""
pools = {
"Pool1": None,
"UserName1": None,
"Password1": None,
"Pool2": None,
"UserName2": None,
"Password2": None,
"Pool3": None,
"UserName3": None,
"Password3": None,
}
for idx, pool in enumerate(self.pools[:3]):
pool_data = pool.as_inno(user_suffix=user_suffix)
for key in pool_data:
pools[f"{key}{idx+1}"] = pool_data[key]
return pools
def as_wm(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a list usable by a Whatsminer device.
Parameters:
user_suffix: The suffix to append to username.
"""
pools = {}
for i in range(1, 4):
if i <= len(self.pools):
pool_wm = self.pools[i - 1].as_wm(user_suffix)
pools[f"pool_{i}"] = pool_wm["url"]
pools[f"worker_{i}"] = pool_wm["user"]
pools[f"passwd_{i}"] = pool_wm["pass"]
else:
pools[f"pool_{i}"] = ""
pools[f"worker_{i}"] = ""
pools[f"passwd_{i}"] = ""
return pools
def as_avalon(self, user_suffix: str = None) -> str:
"""Convert the data in this class to a dict usable by an Avalonminer device.
Parameters:
user_suffix: The suffix to append to username.
"""
pool = self.pools[0].as_avalon(user_suffix=user_suffix)
return pool
def as_bos(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a dict usable by an BOSMiner device.
Parameters:
user_suffix: The suffix to append to username.
"""
group = {
"name": self.group_name,
"quota": self.quota,
"pool": [pool.as_bos(user_suffix=user_suffix) for pool in self.pools],
}
return group
@dataclass
class MinerConfig:
"""A dataclass for miner configuration information.
Attributes:
pool_groups: A list of pool groups in this config.
temp_mode: The temperature control mode.
temp_target: The target temp.
temp_hot: The hot temp (100% fans).
temp_dangerous: The dangerous temp (shutdown).
minimum_fans: The minimum numbers of fans to run the miner.
fan_speed: Manual fan speed to run the fan at (only if temp_mode == "manual").
asicboost: Whether or not to enable asicboost.
autotuning_enabled: Whether or not to enable autotuning.
autotuning_mode: Autotuning mode, either "wattage" or "hashrate".
autotuning_wattage: The wattage to use when autotuning.
autotuning_hashrate: The hashrate to use when autotuning.
dps_enabled: Whether or not to enable dynamic power scaling.
dps_power_step: The amount of power to reduce autotuning by when the miner reaches dangerous temp.
dps_min_power: The minimum power to reduce autotuning to.
dps_shutdown_enabled: Whether or not to shutdown the miner when `dps_min_power` is reached.
dps_shutdown_duration: The amount of time to shutdown for (in hours).
"""
pool_groups: List[_PoolGroup] = None
temp_mode: Literal["auto", "manual", "disabled"] = "auto"
temp_target: float = 70.0
temp_hot: float = 80.0
temp_dangerous: float = 100.0
minimum_fans: int = None
fan_speed: Literal[tuple(range(101))] = None # noqa - Ignore weird Literal usage
asicboost: bool = None
miner_mode: IntEnum = X19PowerMode.Normal
autotuning_enabled: bool = True
autotuning_mode: Literal["power", "hashrate"] = None
autotuning_wattage: int = None
autotuning_hashrate: int = None
dps_enabled: bool = None
dps_power_step: int = None
dps_min_power: int = None
dps_shutdown_enabled: bool = None
dps_shutdown_duration: float = None
@classmethod
def fields(cls):
return fields(cls)
def __getitem__(self, item):
try:
return getattr(self, item)
except AttributeError:
raise KeyError
def as_dict(self) -> dict:
"""Convert the data in this class to a dict."""
logging.debug(f"MinerConfig - (To Dict) - Dumping Dict config")
data_dict = asdict(self)
for key in asdict(self).keys():
if isinstance(data_dict[key], IntEnum):
data_dict[key] = data_dict[key].value
if data_dict[key] is None:
del data_dict[key]
return data_dict
"""Converts the MinerConfig object to a dictionary."""
return self.model_dump()
def as_toml(self) -> str:
"""Convert the data in this class to toml."""
logging.debug(f"MinerConfig - (To TOML) - Dumping TOML config")
return toml.dumps(self.as_dict())
def as_yaml(self) -> str:
"""Convert the data in this class to yaml."""
logging.debug(f"MinerConfig - (To YAML) - Dumping YAML config")
return yaml.dump(self.as_dict(), sort_keys=False)
def from_raw(self, data: dict):
"""Convert raw config data as a dict to usable data and save it to this class.
This should be able to handle any raw config file from any miner supported by pyasic.
Parameters:
data: The raw config data to convert.
"""
logging.debug(f"MinerConfig - (From Raw) - Loading raw config")
pool_groups = []
if isinstance(data, list):
# goldshell config list
data = {"pools": data}
for key in data.keys():
if key == "pools":
pool_groups.append(_PoolGroup().from_dict({"pools": data[key]}))
elif key == "group":
for group in data[key]:
pool_groups.append(_PoolGroup().from_dict(group))
if key == "bitmain-fan-ctrl":
if data[key]:
self.temp_mode = "manual"
if data.get("bitmain-fan-pwm"):
self.fan_speed = int(data["bitmain-fan-pwm"])
elif key == "bitmain-work-mode":
if data[key]:
self.miner_mode = X19PowerMode(int(data[key]))
elif key == "fan_control":
for _key in data[key]:
if _key == "min_fans":
self.minimum_fans = data[key][_key]
elif _key == "speed":
self.fan_speed = data[key][_key]
elif key == "temp_control":
for _key in data[key]:
if _key == "mode":
self.temp_mode = data[key][_key]
elif _key == "target_temp":
self.temp_target = data[key][_key]
elif _key == "hot_temp":
self.temp_hot = data[key][_key]
elif _key == "dangerous_temp":
self.temp_dangerous = data[key][_key]
if key == "hash_chain_global":
if data[key].get("asic_boost"):
self.asicboost = data[key]["asic_boost"]
if key == "autotuning":
for _key in data[key]:
if _key == "enabled":
self.autotuning_enabled = data[key][_key]
elif _key == "psu_power_limit":
self.autotuning_wattage = data[key][_key]
elif _key == "power_target":
self.autotuning_wattage = data[key][_key]
elif _key == "hashrate_target":
self.autotuning_hashrate = data[key][_key]
elif _key == "mode":
self.autotuning_mode = data[key][_key].replace("_target", "")
if key in ["power_scaling", "performance_scaling"]:
for _key in data[key]:
if _key == "enabled":
self.dps_enabled = data[key][_key]
elif _key == "power_step":
self.dps_power_step = data[key][_key]
elif _key in ["min_psu_power_limit", "min_power_target"]:
self.dps_min_power = data[key][_key]
elif _key == "shutdown_enabled":
self.dps_shutdown_enabled = data[key][_key]
elif _key == "shutdown_duration":
self.dps_shutdown_duration = data[key][_key]
self.pool_groups = pool_groups
return self
def from_api(self, pools: list):
"""Convert list output from the `AnyMiner.api.pools()` command into a usable data and save it to this class.
Parameters:
pools: The list of pool data to convert.
"""
logging.debug(f"MinerConfig - (From API) - Loading API config")
_pools = []
for pool in pools:
url = pool.get("URL")
user = pool.get("User")
_pools.append({"url": url, "user": user, "pass": "123"})
self.pool_groups = [_PoolGroup().from_dict({"pools": _pools})]
return self
def from_dict(self, data: dict):
"""Convert an output dict of this class back into usable data and save it to this class.
Parameters:
data: The dict config data to convert.
"""
logging.debug(f"MinerConfig - (From Dict) - Loading Dict config")
pool_groups = []
for group in data["pool_groups"]:
pool_groups.append(_PoolGroup().from_dict(group))
for key in data:
if (
hasattr(self, key)
and not key == "pool_groups"
and not key == "miner_mode"
):
setattr(self, key, data[key])
if key == "miner_mode":
self.miner_mode = X19PowerMode(data[key])
self.pool_groups = pool_groups
return self
def from_toml(self, data: str):
"""Convert output toml of this class back into usable data and save it to this class.
Parameters:
data: The toml config data to convert.
"""
logging.debug(f"MinerConfig - (From TOML) - Loading TOML config")
return self.from_dict(toml.loads(data))
def from_yaml(self, data: str):
"""Convert output yaml of this class back into usable data and save it to this class.
Parameters:
data: The yaml config data to convert.
"""
logging.debug(f"MinerConfig - (From YAML) - Loading YAML config")
return self.from_dict(yaml.load(data, Loader=yaml.SafeLoader))
def as_wm(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by a Whatsminer device.
Parameters:
user_suffix: The suffix to append to username.
"""
logging.debug(f"MinerConfig - (As Whatsminer) - Generating Whatsminer config")
def as_am_modern(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for modern Antminers."""
return {
"pools": self.pool_groups[0].as_wm(user_suffix=user_suffix),
"wattage": self.autotuning_wattage,
}
def as_inno(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by an Innosilicon device.
Parameters:
user_suffix: The suffix to append to username.
"""
logging.debug(f"MinerConfig - (As Inno) - Generating Innosilicon config")
return self.pool_groups[0].as_inno(user_suffix=user_suffix)
def as_x19(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by an X19 device.
Parameters:
user_suffix: The suffix to append to username.
"""
logging.debug(f"MinerConfig - (As X19) - Generating X19 config")
cfg = {
"bitmain-fan-ctrl": False,
"bitmain-fan-pwn": "100",
**self.fan_mode.as_am_modern(),
"freq-level": "100",
"miner-mode": str(self.miner_mode.value),
"pools": self.pool_groups[0].as_x19(user_suffix=user_suffix),
**self.mining_mode.as_am_modern(),
**self.pools.as_am_modern(user_suffix=user_suffix),
**self.temperature.as_am_modern(),
}
if not self.temp_mode == "auto":
cfg["bitmain-fan-ctrl"] = True
if self.fan_speed:
cfg["bitmain-fan-pwn"] = str(self.fan_speed)
return cfg
def as_x17(self, user_suffix: str = None) -> dict:
"""Convert the data in this class to a config usable by an X5 device.
Parameters:
user_suffix: The suffix to append to username.
"""
cfg = self.pool_groups[0].as_x17(user_suffix=user_suffix)
return cfg
def as_goldshell(self, user_suffix: str = None) -> list:
"""Convert the data in this class to a config usable by a goldshell device.
Parameters:
user_suffix: The suffix to append to username.
"""
cfg = self.pool_groups[0].as_goldshell(user_suffix=user_suffix)
return cfg
def as_avalon(self, user_suffix: str = None) -> str:
"""Convert the data in this class to a config usable by an Avalonminer device.
Parameters:
user_suffix: The suffix to append to username.
"""
logging.debug(f"MinerConfig - (As Avalon) - Generating AvalonMiner config")
cfg = self.pool_groups[0].as_avalon(user_suffix=user_suffix)
return cfg
def as_bos(self, model: str = "S9", user_suffix: str = None) -> str:
"""Convert the data in this class to a config usable by an BOSMiner device.
Parameters:
model: The model of the miner to be used in the format portion of the config.
user_suffix: The suffix to append to username.
"""
logging.debug(f"MinerConfig - (As BOS) - Generating BOSMiner config")
cfg = {
"format": {
"version": "1.2+",
"model": f"Antminer {model.replace('j', 'J')}",
"generator": "pyasic",
"timestamp": int(time.time()),
},
"group": [
group.as_bos(user_suffix=user_suffix) for group in self.pool_groups
],
"temp_control": {
"mode": self.temp_mode,
"target_temp": self.temp_target,
"hot_temp": self.temp_hot,
"dangerous_temp": self.temp_dangerous,
},
def as_hiveon_modern(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for modern Hiveon."""
return {
**self.fan_mode.as_hiveon_modern(),
"freq-level": "100",
**self.mining_mode.as_hiveon_modern(),
**self.pools.as_hiveon_modern(user_suffix=user_suffix),
**self.temperature.as_hiveon_modern(),
}
if self.autotuning_enabled or self.autotuning_wattage:
cfg["autotuning"] = {}
if self.autotuning_enabled:
cfg["autotuning"]["enabled"] = True
else:
cfg["autotuning"]["enabled"] = False
if self.autotuning_mode:
cfg["format"]["version"] = "2.0"
cfg["autotuning"]["mode"] = self.autotuning_mode + "_target"
if self.autotuning_wattage:
cfg["autotuning"]["power_target"] = self.autotuning_wattage
elif self.autotuning_hashrate:
cfg["autotuning"]["hashrate_target"] = self.autotuning_hashrate
else:
if self.autotuning_wattage:
cfg["autotuning"]["psu_power_limit"] = self.autotuning_wattage
def as_elphapex(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for modern Elphapex."""
return {
**self.fan_mode.as_elphapex(),
"fc-freq-level": "100",
**self.mining_mode.as_elphapex(),
**self.pools.as_elphapex(user_suffix=user_suffix),
**self.temperature.as_elphapex(),
}
if self.asicboost:
cfg["hash_chain_global"] = {}
cfg["hash_chain_global"]["asic_boost"] = self.asicboost
def as_wm(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for Whatsminers."""
return {
**self.fan_mode.as_wm(),
**self.mining_mode.as_wm(),
**self.pools.as_wm(user_suffix=user_suffix),
**self.temperature.as_wm(),
}
if self.minimum_fans is not None or self.fan_speed is not None:
cfg["fan_control"] = {}
if self.minimum_fans is not None:
cfg["fan_control"]["min_fans"] = self.minimum_fans
if self.fan_speed is not None:
cfg["fan_control"]["speed"] = self.fan_speed
def as_am_old(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for old versions of Antminers."""
return {
**self.fan_mode.as_am_old(),
**self.mining_mode.as_am_old(),
**self.pools.as_am_old(user_suffix=user_suffix),
**self.temperature.as_am_old(),
}
if any(
[
getattr(self, item)
for item in [
"dps_enabled",
"dps_power_step",
"dps_min_power",
"dps_shutdown_enabled",
"dps_shutdown_duration",
]
]
):
cfg["power_scaling"] = {}
if self.dps_enabled:
cfg["power_scaling"]["enabled"] = self.dps_enabled
if self.dps_power_step:
cfg["power_scaling"]["power_step"] = self.dps_power_step
if self.dps_min_power:
if cfg["format"]["version"] == "2.0":
cfg["power_scaling"]["min_power_target"] = self.dps_min_power
else:
cfg["power_scaling"]["min_psu_power_limit"] = self.dps_min_power
if self.dps_shutdown_enabled:
cfg["power_scaling"]["shutdown_enabled"] = self.dps_shutdown_enabled
if self.dps_shutdown_duration:
cfg["power_scaling"]["shutdown_duration"] = self.dps_shutdown_duration
def as_goldshell(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for Goldshell miners."""
return {
**self.fan_mode.as_goldshell(),
**self.mining_mode.as_goldshell(),
**self.pools.as_goldshell(user_suffix=user_suffix),
**self.temperature.as_goldshell(),
}
return toml.dumps(cfg)
def as_avalon(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for Avalonminers."""
return {
**self.fan_mode.as_avalon(),
**self.mining_mode.as_avalon(),
**self.pools.as_avalon(user_suffix=user_suffix),
**self.temperature.as_avalon(),
}
def as_inno(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for Innosilicon miners."""
return {
**self.fan_mode.as_inno(),
**self.mining_mode.as_inno(),
**self.pools.as_inno(user_suffix=user_suffix),
**self.temperature.as_inno(),
}
def as_bosminer(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the bosminer.toml format."""
return {
**merge_dicts(self.fan_mode.as_bosminer(), self.temperature.as_bosminer()),
**self.mining_mode.as_bosminer(),
**self.pools.as_bosminer(user_suffix=user_suffix),
}
def as_boser(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for BOSer."""
return {
**self.fan_mode.as_boser(),
**self.temperature.as_boser(),
**self.mining_mode.as_boser(),
**self.pools.as_boser(user_suffix=user_suffix),
}
def as_epic(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for ePIC miners."""
return {
**merge_dicts(self.fan_mode.as_epic(), self.temperature.as_epic()),
**self.mining_mode.as_epic(),
**self.pools.as_epic(user_suffix=user_suffix),
}
def as_auradine(self, user_suffix: str | None = None) -> dict:
"""Generates the configuration in the format suitable for Auradine miners."""
return {
**self.fan_mode.as_auradine(),
**self.temperature.as_auradine(),
**self.mining_mode.as_auradine(),
**self.pools.as_auradine(user_suffix=user_suffix),
}
def as_mara(self, user_suffix: str | None = None) -> dict:
return {
**self.fan_mode.as_mara(),
**self.temperature.as_mara(),
**self.mining_mode.as_mara(),
**self.pools.as_mara(user_suffix=user_suffix),
}
def as_espminer(self, user_suffix: str | None = None) -> dict:
return {
**self.fan_mode.as_espminer(),
**self.temperature.as_espminer(),
**self.mining_mode.as_espminer(),
**self.pools.as_espminer(user_suffix=user_suffix),
}
def as_luxos(self, user_suffix: str | None = None) -> dict:
return {
**self.fan_mode.as_luxos(),
**self.temperature.as_luxos(),
**self.mining_mode.as_luxos(),
**self.pools.as_luxos(user_suffix=user_suffix),
}
def as_vnish(self, user_suffix: str | None = None) -> dict:
main_cfg = {
"miner": {
**self.fan_mode.as_vnish(),
**self.temperature.as_vnish(),
**self.mining_mode.as_vnish(),
**self.pools.as_vnish(user_suffix=user_suffix),
}
}
if isinstance(self.fan_mode, FanModeNormal):
main_cfg["miner"]["cooling"]["mode"]["param"] = self.temperature.target
return main_cfg
def as_hammer(self, *args, **kwargs) -> dict:
return self.as_am_modern(*args, **kwargs)
@classmethod
def from_dict(cls, dict_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from a dictionary."""
return cls(
pools=PoolConfig.from_dict(dict_conf.get("pools")),
mining_mode=MiningModeConfig.from_dict(dict_conf.get("mining_mode")),
fan_mode=FanModeConfig.from_dict(dict_conf.get("fan_mode")),
temperature=TemperatureConfig.from_dict(dict_conf.get("temperature")),
)
@classmethod
def from_api(cls, api_pools: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from API pool data."""
return cls(pools=PoolConfig.from_api(api_pools))
@classmethod
def from_am_modern(cls, web_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from web configuration for modern Antminers."""
return cls(
pools=PoolConfig.from_am_modern(web_conf),
mining_mode=MiningModeConfig.from_am_modern(web_conf),
fan_mode=FanModeConfig.from_am_modern(web_conf),
)
@classmethod
def from_hiveon_modern(cls, web_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from web configuration for Hiveon."""
return cls(
pools=PoolConfig.from_hiveon_modern(web_conf),
mining_mode=MiningModeConfig.from_hiveon_modern(web_conf),
fan_mode=FanModeConfig.from_hiveon_modern(web_conf),
)
@classmethod
def from_elphapex(cls, web_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from web configuration for modern Antminers."""
return cls(
pools=PoolConfig.from_elphapex(web_conf),
mining_mode=MiningModeConfig.from_elphapex(web_conf),
fan_mode=FanModeConfig.from_elphapex(web_conf),
)
@classmethod
def from_am_old(cls, web_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from web configuration for old versions of Antminers."""
return cls.from_am_modern(web_conf)
@classmethod
def from_goldshell(cls, web_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from web configuration for Goldshell miners."""
return cls(pools=PoolConfig.from_am_modern(web_conf))
@classmethod
def from_inno(cls, web_pools: list) -> "MinerConfig":
"""Constructs a MinerConfig object from web configuration for Innosilicon miners."""
return cls(pools=PoolConfig.from_inno(web_pools))
@classmethod
def from_bosminer(cls, toml_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from the bosminer.toml file, same as the `as_bosminer` dumps a dict for writing to that file as toml."""
return cls(
pools=PoolConfig.from_bosminer(toml_conf),
mining_mode=MiningModeConfig.from_bosminer(toml_conf),
fan_mode=FanModeConfig.from_bosminer(toml_conf),
temperature=TemperatureConfig.from_bosminer(toml_conf),
)
@classmethod
def from_boser(cls, grpc_miner_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from gRPC configuration for BOSer."""
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),
)
@classmethod
def from_epic(cls, web_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from web configuration for ePIC miners."""
return cls(
pools=PoolConfig.from_epic(web_conf),
fan_mode=FanModeConfig.from_epic(web_conf),
temperature=TemperatureConfig.from_epic(web_conf),
mining_mode=MiningModeConfig.from_epic(web_conf),
)
@classmethod
def from_vnish(
cls, web_settings: dict, web_presets: list[dict], web_perf_summary: dict
) -> "MinerConfig":
"""Constructs a MinerConfig object from web settings for VNish miners."""
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, web_presets, web_perf_summary
),
)
@classmethod
def from_auradine(cls, web_conf: dict) -> "MinerConfig":
"""Constructs a MinerConfig object from web configuration for Auradine miners."""
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"]),
)
@classmethod
def from_mara(cls, web_miner_config: dict) -> "MinerConfig":
return cls(
pools=PoolConfig.from_mara(web_miner_config),
fan_mode=FanModeConfig.from_mara(web_miner_config),
mining_mode=MiningModeConfig.from_mara(web_miner_config),
)
@classmethod
def from_espminer(cls, web_system_info: dict) -> "MinerConfig":
return cls(
pools=PoolConfig.from_espminer(web_system_info),
fan_mode=FanModeConfig.from_espminer(web_system_info),
)
@classmethod
def from_iceriver(cls, web_userpanel: dict) -> "MinerConfig":
return cls(
pools=PoolConfig.from_iceriver(web_userpanel),
)
@classmethod
def from_luxos(
cls,
rpc_tempctrl: dict,
rpc_fans: dict,
rpc_pools: dict,
rpc_groups: dict,
rpc_config: dict,
rpc_profiles: dict,
) -> "MinerConfig":
return cls(
temperature=TemperatureConfig.from_luxos(rpc_tempctrl=rpc_tempctrl),
fan_mode=FanModeConfig.from_luxos(
rpc_tempctrl=rpc_tempctrl, rpc_fans=rpc_fans
),
pools=PoolConfig.from_luxos(rpc_pools=rpc_pools, rpc_groups=rpc_groups),
mining_mode=MiningModeConfig.from_luxos(
rpc_config=rpc_config, rpc_profiles=rpc_profiles
),
)
@classmethod
def from_hammer(cls, *args, **kwargs) -> "MinerConfig":
return cls.from_am_modern(*args, **kwargs)

150
pyasic/config/base.py Normal file
View File

@@ -0,0 +1,150 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from __future__ import annotations
from enum import Enum
from pydantic import BaseModel
class MinerConfigOption(Enum):
@classmethod
def from_dict(cls, dict_conf: dict | None):
return cls.default()
def as_am_modern(self) -> dict:
return self.value.as_am_modern()
def as_hiveon_modern(self) -> dict:
return self.value.as_hiveon_modern()
def as_am_old(self) -> dict:
return self.value.as_am_old()
def as_wm(self) -> dict:
return self.value.as_wm()
def as_inno(self) -> dict:
return self.value.as_inno()
def as_goldshell(self) -> dict:
return self.value.as_goldshell()
def as_avalon(self) -> dict:
return self.value.as_avalon()
def as_bosminer(self) -> dict:
return self.value.as_bosminer()
def as_boser(self) -> dict:
return self.value.as_boser
def as_epic(self) -> dict:
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 as_mara(self) -> dict:
return self.value.as_mara()
def as_espminer(self) -> dict:
return self.value.as_espminer()
def as_luxos(self) -> dict:
return self.value.as_luxos()
def as_elphapex(self) -> dict:
return self.value.as_elphapex()
def __call__(self, *args, **kwargs):
return self.value(*args, **kwargs)
@classmethod
def default(cls):
pass
def __getitem__(self, item):
try:
return getattr(self, item)
except AttributeError:
raise KeyError
class MinerConfigValue(BaseModel):
@classmethod
def from_dict(cls, dict_conf: dict | None):
return cls()
def as_dict(self) -> dict:
return self.model_dump()
def as_am_modern(self) -> dict:
return {}
def as_hiveon_modern(self) -> dict:
return {}
def as_am_old(self) -> dict:
return {}
def as_wm(self) -> dict:
return {}
def as_inno(self) -> dict:
return {}
def as_goldshell(self) -> dict:
return {}
def as_avalon(self) -> dict:
return {}
def as_bosminer(self) -> dict:
return {}
def as_boser(self) -> dict:
return {}
def as_epic(self) -> dict:
return {}
def as_vnish(self) -> dict:
return {}
def as_auradine(self) -> dict:
return {}
def as_mara(self) -> dict:
return {}
def as_espminer(self) -> dict:
return {}
def as_luxos(self) -> dict:
return {}
def as_elphapex(self) -> dict:
return {}
def __getitem__(self, item):
try:
return getattr(self, item)
except AttributeError:
raise KeyError

421
pyasic/config/fans.py Normal file
View File

@@ -0,0 +1,421 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from __future__ import annotations
from typing import TypeVar, Union
from pydantic import Field
from pyasic.config.base import MinerConfigOption, MinerConfigValue
class FanModeNormal(MinerConfigValue):
mode: str = Field(init=False, default="normal")
minimum_fans: int = 1
minimum_speed: int = 0
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "FanModeNormal":
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)
@classmethod
def from_bosminer(cls, toml_fan_conf: dict):
cls_conf = {}
if toml_fan_conf.get("min_fans") is not None:
cls_conf["minimum_fans"] = toml_fan_conf["min_fans"]
return cls(**cls_conf)
def as_am_modern(self) -> dict:
return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"}
def as_hiveon_modern(self) -> dict:
return {"bitmain-fan-ctrl": False, "bitmain-fan-pwn": "100"}
def as_elphapex(self) -> dict:
return {"fc-fan-ctrl": False, "fc-fan-pwn": "100"}
def as_bosminer(self) -> dict:
return {
"temp_control": {"mode": "auto"},
"fan_control": {"min_fans": self.minimum_fans},
}
def as_epic(self) -> dict:
return {
"fans": {
"Auto": {
"Idle Speed": (
self.minimum_speed if not self.minimum_speed == 0 else 100
)
}
}
}
def as_mara(self) -> dict:
return {
"general-config": {"environment-profile": "AirCooling"},
"advance-config": {
"override-fan-control": False,
"fan-fixed-percent": 0,
},
}
def as_espminer(self) -> dict:
return {"autoFanspeed": 1}
def as_luxos(self) -> dict:
return {"fanset": {"speed": -1, "min_fans": self.minimum_fans}}
def as_vnish(self) -> dict:
return {
"cooling": {
"fan_min_count": self.minimum_fans,
"fan_min_duty": self.minimum_speed,
"mode": {
"name": "auto",
"param": None, # Target temp, must be set later...
},
}
}
class FanModeManual(MinerConfigValue):
mode: str = Field(init=False, default="manual")
speed: int = 100
minimum_fans: int = 1
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "FanModeManual":
cls_conf = {}
if dict_conf.get("speed") is not None:
cls_conf["speed"] = dict_conf["speed"]
if dict_conf.get("minimum_fans") is not None:
cls_conf["minimum_fans"] = dict_conf["minimum_fans"]
return cls(**cls_conf)
@classmethod
def from_bosminer(cls, toml_fan_conf: dict) -> "FanModeManual":
cls_conf = {}
if toml_fan_conf.get("min_fans") is not None:
cls_conf["minimum_fans"] = toml_fan_conf["min_fans"]
if toml_fan_conf.get("speed") is not None:
cls_conf["speed"] = toml_fan_conf["speed"]
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:
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwm": str(self.speed)}
def as_hiveon_modern(self) -> dict:
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwm": str(self.speed)}
def as_elphapex(self) -> dict:
return {"fc-fan-ctrl": True, "fc-fan-pwm": str(self.speed)}
def as_bosminer(self) -> dict:
return {
"temp_control": {"mode": "manual"},
"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}}}
def as_mara(self) -> dict:
return {
"general-config": {"environment-profile": "AirCooling"},
"advance-config": {
"override-fan-control": True,
"fan-fixed-percent": self.speed,
},
}
def as_espminer(self) -> dict:
return {"autoFanspeed": 0, "fanspeed": self.speed}
def as_luxos(self) -> dict:
return {"fanset": {"speed": self.speed, "min_fans": self.minimum_fans}}
def as_vnish(self) -> dict:
return {
"cooling": {
"fan_min_count": self.minimum_fans,
"fan_min_duty": self.speed,
"mode": {
"name": "manual",
"param": self.speed, # Speed value
},
}
}
class FanModeImmersion(MinerConfigValue):
mode: str = Field(init=False, default="immersion")
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "FanModeImmersion":
return cls()
def as_am_modern(self) -> dict:
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwm": "0"}
def as_hiveon_modern(self) -> dict:
return {"bitmain-fan-ctrl": True, "bitmain-fan-pwm": "0"}
def as_elphapex(self) -> dict:
return {"fc-fan-ctrl": True, "fc-fan-pwm": "0"}
def as_bosminer(self) -> dict:
return {
"fan_control": {"min_fans": 0},
}
def as_auradine(self) -> dict:
return {"fan": {"percentage": 0}}
def as_mara(self) -> dict:
return {"general-config": {"environment-profile": "OilImmersionCooling"}}
def as_luxos(self) -> dict:
return {"fanset": {"speed": 0, "min_fans": 0}}
def as_vnish(self) -> dict:
return {"cooling": {"mode": {"name": "immers"}}}
class FanModeConfig(MinerConfigOption):
normal = FanModeNormal
manual = FanModeManual
immersion = FanModeImmersion
@classmethod
def default(cls):
return cls.normal()
@classmethod
def from_dict(cls, dict_conf: dict | None):
if dict_conf is None:
return cls.default()
mode = dict_conf.get("mode")
if mode is None:
return cls.default()
cls_attr = getattr(cls, mode)
if cls_attr is not None:
return cls_attr().from_dict(dict_conf)
@classmethod
def from_am_modern(cls, web_conf: dict):
if web_conf.get("bitmain-fan-ctrl") is not None:
fan_manual = web_conf["bitmain-fan-ctrl"]
if fan_manual:
speed = int(web_conf["bitmain-fan-pwm"])
if speed == 0:
return cls.immersion()
return cls.manual(speed=speed)
else:
return cls.normal()
else:
return cls.default()
@classmethod
def from_hiveon_modern(cls, web_conf: dict):
if web_conf.get("bitmain-fan-ctrl") is not None:
fan_manual = web_conf["bitmain-fan-ctrl"]
if fan_manual:
speed = int(web_conf["bitmain-fan-pwm"])
if speed == 0:
return cls.immersion()
return cls.manual(speed=speed)
else:
return cls.normal()
else:
return cls.default()
@classmethod
def from_elphapex(cls, web_conf: dict):
if web_conf.get("fc-fan-ctrl") is not None:
fan_manual = web_conf["fc-fan-ctrl"]
if fan_manual:
speed = int(web_conf["fc-fan-pwm"])
if speed == 0:
return cls.immersion()
return cls.manual(speed=speed)
else:
return cls.normal()
else:
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
def from_bosminer(cls, toml_conf: dict):
try:
mode = toml_conf["temp_control"]["mode"]
fan_config = toml_conf.get("fan_control", {})
if mode == "auto":
return cls.normal().from_bosminer(fan_config)
elif mode == "manual":
if toml_conf.get("fan_control"):
return cls.manual().from_bosminer(fan_config)
return cls.manual()
elif mode == "disabled":
return cls.immersion()
except KeyError:
pass
try:
min_fans = toml_conf["fan_control"]["min_fans"]
except KeyError:
return cls.default()
if min_fans == 0:
return cls.immersion()
return cls.normal(minimum_fans=min_fans)
@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(minimum_fans=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)
if "disabled" in keys:
conf = {}
if "fanSpeedRatio" in temperature_conf["disabled"].keys():
conf["speed"] = int(temperature_conf["disabled"]["fanSpeedRatio"])
return cls.manual(**conf)
return cls.default()
@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:
pass
return cls.default()
@classmethod
def from_mara(cls, web_config: dict):
try:
mode = web_config["general-config"]["environment-profile"]
if mode == "AirCooling":
if web_config["advance-config"]["override-fan-control"]:
return cls.manual(
speed=web_config["advance-config"]["fan-fixed-percent"]
)
return cls.normal()
return cls.immersion()
except LookupError:
pass
return cls.default()
@classmethod
def from_espminer(cls, web_system_info: dict):
if web_system_info["autofanspeed"] == 1:
return cls.normal()
else:
return cls.manual(speed=web_system_info["fanspeed"])
@classmethod
def from_luxos(cls, rpc_fans: dict, rpc_tempctrl: dict):
try:
mode = rpc_tempctrl["TEMPCTRL"][0]["Mode"]
if mode == "Manual":
speed = rpc_fans["FANS"][0]["Speed"]
min_fans = rpc_fans["FANCTRL"][0]["MinFans"]
if min_fans == 0 and speed == 0:
return cls.immersion()
return cls.manual(
speed=speed,
minimum_fans=min_fans,
)
return cls.normal(
minimum_fans=rpc_fans["FANCTRL"][0]["MinFans"],
)
except LookupError:
pass
return cls.default()
FanMode = TypeVar(
"FanMode",
bound=Union[FanModeNormal, FanModeManual, FanModeImmersion],
)

View File

@@ -0,0 +1,838 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from __future__ import annotations
from dataclasses import field
from typing import TypeVar, Union
from pyasic import settings
from pyasic.config.base import MinerConfigOption, MinerConfigValue
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
DpsHashrateTarget,
DpsPowerTarget,
DpsTarget,
HashrateTargetMode,
PerformanceMode,
Power,
PowerTargetMode,
SaveAction,
SetDpsRequest,
SetPerformanceModeRequest,
TeraHashrate,
TunerPerformanceMode,
)
from .algo import TunerAlgo, TunerAlgoType
from .presets import MiningPreset
from .scaling import ScalingConfig
class MiningModeNormal(MinerConfigValue):
mode: str = field(init=False, default="normal")
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "MiningModeNormal":
return cls()
def as_am_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_hiveon_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_elphapex(self) -> dict:
return {"miner-mode": 0}
def as_wm(self) -> dict:
return {"mode": self.mode}
def as_auradine(self) -> dict:
return {"mode": {"mode": self.mode}}
def as_epic(self) -> dict:
return {"ptune": {"enabled": False}}
def as_goldshell(self) -> dict:
return {"settings": {"level": 0}}
def as_mara(self) -> dict:
return {
"mode": {
"work-mode-selector": "Stock",
}
}
def as_luxos(self) -> dict:
return {"autotunerset": {"enabled": False}}
def as_bosminer(self) -> dict:
return {"autotuning": {"enabled": True}}
class MiningModeSleep(MinerConfigValue):
mode: str = field(init=False, default="sleep")
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "MiningModeSleep":
return cls()
def as_am_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "1"}
return {"miner-mode": 1}
def as_hiveon_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "1"}
return {"miner-mode": 1}
def as_elphapex(self) -> dict:
return {"miner-mode": 1}
def as_wm(self) -> dict:
return {"mode": self.mode}
def as_auradine(self) -> dict:
return {"mode": {"sleep": "on"}}
def as_epic(self) -> dict:
return {"ptune": {"algo": "Sleep", "target": 0}}
def as_goldshell(self) -> dict:
return {"settings": {"level": 3}}
def as_mara(self) -> dict:
return {
"mode": {
"work-mode-selector": "Sleep",
}
}
class MiningModeLPM(MinerConfigValue):
mode: str = field(init=False, default="low")
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "MiningModeLPM":
return cls()
def as_am_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "3"}
return {"miner-mode": 3}
def as_hiveon_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "3"}
return {"miner-mode": 3}
def as_elphapex(self) -> dict:
return {"miner-mode": 3}
def as_wm(self) -> dict:
return {"mode": self.mode}
def as_auradine(self) -> dict:
return {"mode": {"mode": "eco"}}
def as_goldshell(self) -> dict:
return {"settings": {"level": 1}}
class MiningModeHPM(MinerConfigValue):
mode: str = field(init=False, default="high")
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHPM":
return cls()
def as_am_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_hiveon_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_elphapex(self) -> dict:
return {"miner-mode": 0}
def as_wm(self) -> dict:
return {"mode": self.mode}
def as_auradine(self) -> dict:
return {"mode": {"mode": "turbo"}}
class MiningModePowerTune(MinerConfigValue):
class Config:
arbitrary_types_allowed = True
mode: str = field(init=False, default="power_tuning")
power: int | None = None
algo: TunerAlgoType = field(default_factory=TunerAlgo.default)
scaling: ScalingConfig | None = None
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "MiningModePowerTune":
cls_conf = {}
if dict_conf.get("power"):
cls_conf["power"] = dict_conf["power"]
if dict_conf.get("algo"):
cls_conf["algo"] = TunerAlgo.from_dict(dict_conf["algo"])
if dict_conf.get("scaling"):
cls_conf["scaling"] = ScalingConfig.from_dict(dict_conf["scaling"])
return cls(**cls_conf)
def as_am_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_hiveon_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_elphapex(self) -> dict:
return {"miner-mode": 0}
def as_wm(self) -> dict:
if self.power is not None:
return {"mode": self.mode, self.mode: {"wattage": self.power}}
return {}
def as_bosminer(self) -> dict:
tuning_cfg = {"enabled": True, "mode": "power_target"}
if self.power is not None:
tuning_cfg["power_target"] = self.power
cfg = {"autotuning": tuning_cfg}
if self.scaling is not None:
scaling_cfg = {"enabled": True}
if self.scaling.step is not None:
scaling_cfg["power_step"] = self.scaling.step
if self.scaling.minimum is not None:
scaling_cfg["min_power_target"] = self.scaling.minimum
if self.scaling.shutdown is not None:
scaling_cfg = {**scaling_cfg, **self.scaling.shutdown.as_bosminer()}
cfg["performance_scaling"] = scaling_cfg
return cfg
def as_boser(self) -> dict:
cfg = {
"set_performance_mode": SetPerformanceModeRequest(
save_action=SaveAction.SAVE_AND_APPLY,
mode=PerformanceMode(
tuner_mode=TunerPerformanceMode(
power_target=PowerTargetMode(
power_target=Power(watt=self.power)
)
)
),
),
}
if self.scaling is not None:
sd_cfg = {}
if self.scaling.shutdown is not None:
sd_cfg = self.scaling.shutdown.as_boser()
power_target_kwargs = {}
if self.scaling.step is not None:
power_target_kwargs["power_step"] = Power(self.scaling.step)
if self.scaling.minimum is not None:
power_target_kwargs["min_power_target"] = Power(self.scaling.minimum)
cfg["set_dps"] = SetDpsRequest(
save_action=SaveAction.SAVE_AND_APPLY,
enable=True,
**sd_cfg,
target=DpsTarget(power_target=DpsPowerTarget(**power_target_kwargs)),
)
return cfg
def as_auradine(self) -> dict:
return {"mode": {"mode": "custom", "tune": "power", "power": self.power}}
def as_mara(self) -> dict:
return {
"mode": {
"work-mode-selector": "Auto",
"concorde": {
"mode-select": "PowerTarget",
"power-target": self.power,
},
}
}
def as_luxos(self) -> dict:
return {"autotunerset": {"enabled": True}}
class MiningModeHashrateTune(MinerConfigValue):
class Config:
arbitrary_types_allowed = True
mode: str = field(init=False, default="hashrate_tuning")
hashrate: int | None = None
algo: TunerAlgoType = field(default_factory=TunerAlgo.default)
scaling: ScalingConfig | None = None
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "MiningModeHashrateTune":
cls_conf = {}
if dict_conf.get("hashrate"):
cls_conf["hashrate"] = dict_conf["hashrate"]
if dict_conf.get("algo"):
cls_conf["algo"] = TunerAlgo.from_dict(dict_conf["algo"])
if dict_conf.get("scaling"):
cls_conf["scaling"] = ScalingConfig.from_dict(dict_conf["scaling"])
return cls(**cls_conf)
def as_am_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_hiveon_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_elphapex(self) -> dict:
return {"miner-mode": 0}
def as_bosminer(self) -> dict:
conf = {"enabled": True, "mode": "hashrate_target"}
if self.hashrate is not None:
conf["hashrate_target"] = self.hashrate
return {"autotuning": conf}
def as_boser(self) -> dict:
cfg = {
"set_performance_mode": SetPerformanceModeRequest(
save_action=SaveAction.SAVE_AND_APPLY,
mode=PerformanceMode(
tuner_mode=TunerPerformanceMode(
hashrate_target=HashrateTargetMode(
hashrate_target=TeraHashrate(
terahash_per_second=self.hashrate
)
)
)
),
)
}
if self.scaling is not None:
sd_cfg = {}
if self.scaling.shutdown is not None:
sd_cfg = self.scaling.shutdown.as_boser()
hashrate_target_kwargs = {}
if self.scaling.step is not None:
hashrate_target_kwargs["hashrate_step"] = TeraHashrate(
self.scaling.step
)
if self.scaling.minimum is not None:
hashrate_target_kwargs["min_hashrate_target"] = TeraHashrate(
self.scaling.minimum
)
cfg["set_dps"] = SetDpsRequest(
save_action=SaveAction.SAVE_AND_APPLY,
enable=True,
**sd_cfg,
target=DpsTarget(
hashrate_target=DpsHashrateTarget(**hashrate_target_kwargs)
),
)
return cfg
def as_auradine(self) -> dict:
return {"mode": {"mode": "custom", "tune": "ths", "ths": self.hashrate}}
def as_epic(self) -> dict:
mode = {
"ptune": {
"algo": self.algo.as_epic(),
"target": self.hashrate,
}
}
if self.scaling is not None:
if self.scaling.minimum is not None:
mode["ptune"]["min_throttle"] = self.scaling.minimum
if self.scaling.step is not None:
mode["ptune"]["throttle_step"] = self.scaling.step
return mode
def as_mara(self) -> dict:
return {
"mode": {
"work-mode-selector": "Auto",
"concorde": {
"mode-select": "Hashrate",
"hash-target": self.hashrate,
},
}
}
def as_luxos(self) -> dict:
return {"autotunerset": {"enabled": True}}
class MiningModePreset(MinerConfigValue):
mode: str = field(init=False, default="preset")
active_preset: MiningPreset
available_presets: list[MiningPreset] = field(default_factory=list)
def as_vnish(self) -> dict:
return {"overclock": {**self.active_preset.as_vnish()}}
@classmethod
def from_vnish(
cls,
web_overclock_settings: dict,
web_presets: list[dict],
web_perf_summary: dict,
) -> "MiningModePreset":
active_preset = web_perf_summary.get("current_preset")
if active_preset is None:
for preset in web_presets:
if preset["name"] == web_overclock_settings["preset"]:
active_preset = preset
return cls(
active_preset=MiningPreset.from_vnish(active_preset),
available_presets=[MiningPreset.from_vnish(p) for p in web_presets],
)
@classmethod
def from_luxos(cls, rpc_config: dict, rpc_profiles: dict) -> "MiningModePreset":
active_preset = cls.get_active_preset_from_luxos(rpc_config, rpc_profiles)
return cls(
active_preset=active_preset,
available_presets=[
MiningPreset.from_luxos(p) for p in rpc_profiles["PROFILES"]
],
)
@classmethod
def get_active_preset_from_luxos(
cls, rpc_config: dict, rpc_profiles: dict
) -> MiningPreset:
active_preset = None
active_profile = rpc_config["CONFIG"][0]["Profile"]
for profile in rpc_profiles["PROFILES"]:
if profile["Profile Name"] == active_profile:
active_preset = profile
return MiningPreset.from_luxos(active_preset)
class ManualBoardSettings(MinerConfigValue):
freq: float
volt: float
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "ManualBoardSettings":
return cls(freq=dict_conf["freq"], volt=dict_conf["volt"])
def as_am_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_hiveon_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_elphapex(self) -> dict:
return {"miner-mode": 0}
def as_vnish(self) -> dict:
return {"freq": self.freq}
class MiningModeManual(MinerConfigValue):
mode: str = field(init=False, default="manual")
global_freq: float
global_volt: float
boards: dict[int, ManualBoardSettings] = field(default_factory=dict)
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "MiningModeManual":
return cls(
global_freq=dict_conf["global_freq"],
global_volt=dict_conf["global_volt"],
boards={i: ManualBoardSettings.from_dict(dict_conf[i]) for i in dict_conf},
)
def as_am_modern(self) -> dict:
if settings.get("antminer_mining_mode_as_str", False):
return {"miner-mode": "0"}
return {"miner-mode": 0}
def as_elphapex(self) -> dict:
return {"miner-mode": 0}
def as_vnish(self) -> dict:
chains = [b.as_vnish() for b in self.boards.values() if b.freq != 0]
return {
"overclock": {
"chains": chains if chains != [] else None,
"globals": {
"freq": int(self.global_freq),
"volt": int(self.global_volt),
},
}
}
@classmethod
def from_vnish(cls, web_overclock_settings: dict) -> "MiningModeManual":
# will raise KeyError if it cant find the settings, values cannot be empty
voltage = web_overclock_settings["globals"]["volt"]
freq = web_overclock_settings["globals"]["freq"]
boards = {
idx: ManualBoardSettings(
freq=board["freq"],
volt=voltage if not board["freq"] == 0 else 0,
)
for idx, board in enumerate(web_overclock_settings["chains"])
}
return cls(global_freq=freq, global_volt=voltage, boards=boards)
@classmethod
def from_epic(cls, epic_conf: dict) -> "MiningModeManual":
voltage = 0
freq = 0
if epic_conf.get("HwConfig") is not None:
freq = epic_conf["HwConfig"]["Boards Target Clock"][0]["Data"]
if epic_conf.get("Power Supply Stats") is not None:
voltage = epic_conf["Power Supply Stats"]["Target Voltage"]
boards = {}
if epic_conf.get("HBs") is not None:
boards = {
board["Index"]: ManualBoardSettings(
freq=board["Core Clock Avg"], volt=board["Input Voltage"]
)
for board in epic_conf["HBs"]
}
return cls(global_freq=freq, global_volt=voltage, boards=boards)
def as_mara(self) -> dict:
return {
"mode": {
"work-mode-selector": "Fixed",
"fixed": {
"frequency": str(self.global_freq),
"voltage": self.global_volt,
},
}
}
class MiningModeConfig(MinerConfigOption):
normal = MiningModeNormal
low = MiningModeLPM
high = MiningModeHPM
sleep = MiningModeSleep
power_tuning = MiningModePowerTune
hashrate_tuning = MiningModeHashrateTune
preset = MiningModePreset
manual = MiningModeManual
@classmethod
def default(cls):
return cls.normal()
@classmethod
def from_dict(cls, dict_conf: dict | None):
if dict_conf is None:
return cls.default()
mode = dict_conf.get("mode")
if mode is None:
return cls.default()
cls_attr = getattr(cls, mode)
if cls_attr is not None:
return cls_attr().from_dict(dict_conf)
@classmethod
def from_am_modern(cls, web_conf: dict):
if web_conf.get("bitmain-work-mode") is not None:
work_mode = web_conf["bitmain-work-mode"]
if work_mode == "":
return cls.default()
if int(work_mode) == 0:
return cls.normal()
elif int(work_mode) == 1:
return cls.sleep()
elif int(work_mode) == 3:
return cls.low()
return cls.default()
@classmethod
def from_hiveon_modern(cls, web_conf: dict):
if web_conf.get("bitmain-work-mode") is not None:
work_mode = web_conf["bitmain-work-mode"]
if work_mode == "":
return cls.default()
if int(work_mode) == 0:
return cls.normal()
elif int(work_mode) == 1:
return cls.sleep()
elif int(work_mode) == 3:
return cls.low()
return cls.default()
@classmethod
def from_elphapex(cls, web_conf: dict):
if web_conf.get("fc-work-mode") is not None:
work_mode = web_conf["fc-work-mode"]
if work_mode == "":
return cls.default()
if int(work_mode) == 0:
return cls.normal()
elif int(work_mode) == 1:
return cls.sleep()
elif int(work_mode) == 3:
return cls.low()
return cls.default()
@classmethod
def from_epic(cls, web_conf: dict):
try:
tuner_running = web_conf["PerpetualTune"]["Running"]
if tuner_running:
algo_info = web_conf["PerpetualTune"]["Algorithm"]
if algo_info.get("VoltageOptimizer") is not None:
scaling_cfg = None
if "Throttle Step" in algo_info["VoltageOptimizer"]:
scaling_cfg = ScalingConfig(
minimum=algo_info["VoltageOptimizer"].get(
"Min Throttle Target"
),
step=algo_info["VoltageOptimizer"].get("Throttle Step"),
)
return cls.hashrate_tuning(
hashrate=algo_info["VoltageOptimizer"].get("Target"),
algo=TunerAlgo.voltage_optimizer(),
scaling=scaling_cfg,
)
elif algo_info.get("BoardTune") is not None:
scaling_cfg = None
if "Throttle Step" in algo_info["BoardTune"]:
scaling_cfg = ScalingConfig(
minimum=algo_info["BoardTune"].get("Min Throttle Target"),
step=algo_info["BoardTune"].get("Throttle Step"),
)
return cls.hashrate_tuning(
hashrate=algo_info["BoardTune"].get("Target"),
algo=TunerAlgo.board_tune(),
scaling=scaling_cfg,
)
else:
return cls.hashrate_tuning(
hashrate=algo_info["ChipTune"].get("Target"),
algo=TunerAlgo.chip_tune(),
)
else:
return MiningModeManual.from_epic(web_conf)
except KeyError:
return cls.default()
@classmethod
def from_bosminer(cls, toml_conf: dict):
if toml_conf.get("autotuning") is None:
return cls.default()
autotuning_conf = toml_conf["autotuning"]
if autotuning_conf.get("enabled") is None:
return cls.default()
if not autotuning_conf["enabled"]:
return cls.default()
if autotuning_conf.get("psu_power_limit") is not None:
# old autotuning conf
return cls.power_tuning(
power=autotuning_conf["psu_power_limit"],
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
)
if autotuning_conf.get("mode") is not None:
# new autotuning conf
mode = autotuning_conf["mode"]
if mode == "power_target":
if autotuning_conf.get("power_target") is not None:
return cls.power_tuning(
power=autotuning_conf["power_target"],
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
)
return cls.power_tuning(
scaling=ScalingConfig.from_bosminer(toml_conf, mode="power"),
)
if mode == "hashrate_target":
if autotuning_conf.get("hashrate_target") is not None:
return cls.hashrate_tuning(
hashrate=autotuning_conf["hashrate_target"],
scaling=ScalingConfig.from_bosminer(toml_conf, mode="hashrate"),
)
return cls.hashrate_tuning(
scaling=ScalingConfig.from_bosminer(toml_conf, mode="hashrate"),
)
return cls.default()
@classmethod
def from_vnish(
cls, web_settings: dict, web_presets: list[dict], web_perf_summary: 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 MiningModePreset.from_vnish(
mode_settings, web_presets, web_perf_summary
)
@classmethod
def from_boser(cls, grpc_miner_conf: dict):
try:
tuner_conf = grpc_miner_conf["tuner"]
if not tuner_conf.get("enabled", False):
return cls.default()
except LookupError:
return cls.default()
if tuner_conf.get("tunerMode") is not None:
if tuner_conf["tunerMode"] == 1:
if tuner_conf.get("powerTarget") is not None:
return cls.power_tuning(
power=tuner_conf["powerTarget"]["watt"],
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power"),
)
return cls.power_tuning(
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power")
)
if tuner_conf["tunerMode"] == 2:
if tuner_conf.get("hashrateTarget") is not None:
return cls.hashrate_tuning(
hashrate=int(tuner_conf["hashrateTarget"]["terahashPerSecond"]),
scaling=ScalingConfig.from_boser(
grpc_miner_conf, mode="hashrate"
),
)
return cls.hashrate_tuning(
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="hashrate"),
)
if tuner_conf.get("powerTarget") is not None:
return cls.power_tuning(
power=tuner_conf["powerTarget"]["watt"],
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="power"),
)
if tuner_conf.get("hashrateTarget") is not None:
return cls.hashrate_tuning(
hashrate=int(tuner_conf["hashrateTarget"]["terahashPerSecond"]),
scaling=ScalingConfig.from_boser(grpc_miner_conf, mode="hashrate"),
)
return cls.default()
@classmethod
def from_auradine(cls, web_mode: dict):
try:
mode_data = web_mode["Mode"][0]
if mode_data.get("Sleep") == "on":
return cls.sleep()
if mode_data.get("Mode") == "normal":
return cls.normal()
if mode_data.get("Mode") == "eco":
return cls.low()
if mode_data.get("Mode") == "turbo":
return cls.high()
if mode_data.get("Ths") is not None:
return cls.hashrate_tuning(hashrate=mode_data["Ths"])
if mode_data.get("Power") is not None:
return cls.power_tuning(power=mode_data["Power"])
except LookupError:
return cls.default()
@classmethod
def from_mara(cls, web_config: dict):
try:
mode = web_config["mode"]["work-mode-selector"]
if mode == "Fixed":
fixed_conf = web_config["mode"]["fixed"]
return cls.manual(
global_freq=int(fixed_conf["frequency"]),
global_volt=fixed_conf["voltage"],
)
elif mode == "Stock":
return cls.normal()
elif mode == "Sleep":
return cls.sleep()
elif mode == "Auto":
auto_conf = web_config["mode"]["concorde"]
auto_mode = auto_conf["mode-select"]
if auto_mode == "Hashrate":
return cls.hashrate_tuning(hashrate=auto_conf["hash-target"])
elif auto_mode == "PowerTarget":
return cls.power_tuning(power=auto_conf["power-target"])
except LookupError:
pass
return cls.default()
@classmethod
def from_luxos(cls, rpc_config: dict, rpc_profiles: dict):
preset_info = MiningModePreset.from_luxos(rpc_config, rpc_profiles)
return cls.preset(
active_preset=preset_info.active_preset,
available_presets=preset_info.available_presets,
)
MiningMode = TypeVar(
"MiningMode",
bound=Union[
MiningModeNormal,
MiningModeHPM,
MiningModeLPM,
MiningModeSleep,
MiningModeManual,
MiningModePowerTune,
MiningModeHashrateTune,
MiningModePreset,
],
)

View File

@@ -0,0 +1,66 @@
from __future__ import annotations
from dataclasses import field
from typing import TypeVar, Union
from pyasic.config.base import MinerConfigOption, MinerConfigValue
class StandardTuneAlgo(MinerConfigValue):
mode: str = field(init=False, default="standard")
def as_epic(self) -> str:
return VOptAlgo().as_epic()
class VOptAlgo(MinerConfigValue):
mode: str = field(init=False, default="voltage_optimizer")
def as_epic(self) -> str:
return "VoltageOptimizer"
class BoardTuneAlgo(MinerConfigValue):
mode: str = field(init=False, default="board_tune")
def as_epic(self) -> str:
return "BoardTune"
class ChipTuneAlgo(MinerConfigValue):
mode: str = field(init=False, default="chip_tune")
def as_epic(self) -> str:
return "ChipTune"
class TunerAlgo(MinerConfigOption):
standard = StandardTuneAlgo
voltage_optimizer = VOptAlgo
board_tune = BoardTuneAlgo
chip_tune = ChipTuneAlgo
@classmethod
def default(cls) -> TunerAlgoType:
return cls.standard()
@classmethod
def from_dict(cls, dict_conf: dict | None) -> TunerAlgoType:
mode = dict_conf.get("mode")
if mode is None:
return cls.default()
cls_attr = getattr(cls, mode)
if cls_attr is not None:
return cls_attr().from_dict(dict_conf)
TunerAlgoType = TypeVar(
"TunerAlgoType",
bound=Union[
StandardTuneAlgo,
VOptAlgo,
BoardTuneAlgo,
ChipTuneAlgo,
],
)

View File

@@ -0,0 +1,54 @@
from pyasic.config.base import MinerConfigValue
class MiningPreset(MinerConfigValue):
name: str | None = None
power: int | None = None
hashrate: int | None = None
tuned: bool | None = None
modded_psu: bool | None = None
frequency: int | None = None
voltage: float | None = None
def as_vnish(self) -> dict:
if self.name is not None:
return {"preset": self.name}
return {}
@classmethod
def from_vnish(cls, web_preset: dict):
name = web_preset["name"]
hr_power_split = web_preset["pretty"].split("~")
if len(hr_power_split) == 1:
power = None
hashrate = None
else:
power = hr_power_split[0].replace("watt", "").strip()
hashrate = (
hr_power_split[1]
.replace("TH", "")
.replace("GH", "")
.replace("MH", "")
.replace(" LC", "")
.strip()
)
tuned = web_preset["status"] == "tuned"
modded_psu = web_preset["modded_psu_required"]
return cls(
name=name,
power=power,
hashrate=hashrate,
tuned=tuned,
modded_psu=modded_psu,
)
@classmethod
def from_luxos(cls, profile: dict):
return cls(
name=profile["Profile Name"],
power=profile["Watts"],
hashrate=round(profile["Hashrate"]),
tuned=profile["IsTuned"],
frequency=profile["Frequency"],
voltage=profile["Voltage"],
)

View File

@@ -0,0 +1,129 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from __future__ import annotations
from pyasic.config.base import MinerConfigValue
class ScalingShutdown(MinerConfigValue):
enabled: bool = False
duration: int | None = None
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "ScalingShutdown":
return cls(
enabled=dict_conf.get("enabled", False), duration=dict_conf.get("duration")
)
@classmethod
def from_bosminer(cls, power_scaling_conf: dict):
sd_enabled = power_scaling_conf.get("shutdown_enabled")
if sd_enabled is not None:
return cls(
enabled=sd_enabled, duration=power_scaling_conf.get("shutdown_duration")
)
return None
@classmethod
def from_boser(cls, power_scaling_conf: dict):
sd_enabled = power_scaling_conf.get("shutdownEnabled")
if sd_enabled is not None:
try:
return cls(
enabled=sd_enabled,
duration=power_scaling_conf["shutdownDuration"]["hours"],
)
except KeyError:
return cls(enabled=sd_enabled)
return None
def as_bosminer(self) -> dict:
cfg = {"shutdown_enabled": self.enabled}
if self.duration is not None:
cfg["shutdown_duration"] = self.duration
return cfg
def as_boser(self) -> dict:
return {"enable_shutdown": self.enabled, "shutdown_duration": self.duration}
class ScalingConfig(MinerConfigValue):
step: int | None = None
minimum: int | None = None
shutdown: ScalingShutdown | None = None
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "ScalingConfig":
cls_conf = {
"step": dict_conf.get("step"),
"minimum": dict_conf.get("minimum"),
}
shutdown = dict_conf.get("shutdown")
if shutdown is not None:
cls_conf["shutdown"] = ScalingShutdown.from_dict(shutdown)
return cls(**cls_conf)
@classmethod
def from_bosminer(cls, toml_conf: dict, mode: str | None = None):
if mode == "power":
return cls._from_bosminer_power(toml_conf)
if mode == "hashrate":
# not implemented yet
pass
@classmethod
def _from_bosminer_power(cls, toml_conf: dict):
power_scaling = toml_conf.get("power_scaling")
if power_scaling is None:
power_scaling = toml_conf.get("performance_scaling")
if power_scaling is not None:
enabled = power_scaling.get("enabled")
if not enabled:
return None
power_step = power_scaling.get("power_step")
min_power = power_scaling.get("min_psu_power_limit")
if min_power is None:
min_power = power_scaling.get("min_power_target")
sd_mode = ScalingShutdown.from_bosminer(power_scaling)
return cls(step=power_step, minimum=min_power, shutdown=sd_mode)
@classmethod
def from_boser(cls, grpc_miner_conf: dict, mode: str | None = None):
if mode == "power":
return cls._from_boser_power(grpc_miner_conf)
if mode == "hashrate":
# not implemented yet
pass
@classmethod
def _from_boser_power(cls, grpc_miner_conf: dict):
try:
dps_conf = grpc_miner_conf["dps"]
if not dps_conf.get("enabled", False):
return None
except LookupError:
return None
conf = {"shutdown": ScalingShutdown.from_boser(dps_conf)}
if dps_conf.get("minPowerTarget") is not None:
conf["minimum"] = dps_conf["minPowerTarget"]["watt"]
if dps_conf.get("powerStep") is not None:
conf["step"] = dps_conf["powerStep"]["watt"]
return cls(**conf)

691
pyasic/config/pools.py Normal file
View File

@@ -0,0 +1,691 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from __future__ import annotations
import random
import string
from typing import List
from pydantic import Field
from pyasic.config.base import MinerConfigValue
from pyasic.web.braiins_os.proto.braiins.bos.v1 import (
PoolConfiguration,
PoolGroupConfiguration,
Quota,
SaveAction,
SetPoolGroupsRequest,
)
class Pool(MinerConfigValue):
url: str
user: str
password: str
def as_am_modern(self, user_suffix: str | None = None) -> dict:
return {
"url": self.url,
"user": f"{self.user}{user_suffix or ''}",
"pass": self.password,
}
def as_hiveon_modern(self, user_suffix: str | None = None) -> dict:
return {
"url": self.url,
"user": f"{self.user}{user_suffix or ''}",
"pass": self.password,
}
def as_elphapex(self, user_suffix: str | None = None) -> dict:
return {
"url": self.url,
"user": f"{self.user}{user_suffix or ''}",
"pass": self.password,
}
def as_wm(self, idx: int = 1, user_suffix: str | None = None) -> dict:
return {
f"pool_{idx}": self.url,
f"worker_{idx}": f"{self.user}{user_suffix or ''}",
f"passwd_{idx}": self.password,
}
def as_am_old(self, idx: int = 1, user_suffix: str | None = None) -> dict:
return {
f"_ant_pool{idx}url": self.url,
f"_ant_pool{idx}user": f"{self.user}{user_suffix or ''}",
f"_ant_pool{idx}pw": self.password,
}
def as_goldshell(self, user_suffix: str | None = None) -> dict:
return {
"url": self.url,
"user": f"{self.user}{user_suffix or ''}",
"pass": self.password,
}
def as_avalon(self, user_suffix: str | None = None) -> str:
return ",".join([self.url, f"{self.user}{user_suffix or ''}", self.password])
def as_inno(self, idx: int = 1, user_suffix: str | None = None) -> dict:
return {
f"Pool{idx}": self.url,
f"UserName{idx}": f"{self.user}{user_suffix or ''}",
f"Password{idx}": self.password,
}
def as_bosminer(self, user_suffix: str | None = None) -> dict:
return {
"url": self.url,
"user": f"{self.user}{user_suffix or ''}",
"password": self.password,
}
def as_auradine(self, user_suffix: str | None = None) -> dict:
return {
"url": self.url,
"user": f"{self.user}{user_suffix or ''}",
"pass": self.password,
}
def as_epic(self, user_suffix: str | None = None):
return {
"pool": self.url,
"login": f"{self.user}{user_suffix or ''}",
"password": self.password,
}
def as_mara(self, user_suffix: str | None = None) -> dict:
return {
"url": self.url,
"user": f"{self.user}{user_suffix or ''}",
"pass": self.password,
}
def as_espminer(self, user_suffix: str | None = None) -> dict:
return {
"stratumURL": self.url,
"stratumUser": f"{self.user}{user_suffix or ''}",
"stratumPassword": self.password,
}
def as_boser(self, user_suffix: str | None = None) -> PoolConfiguration:
return PoolConfiguration(
url=self.url,
user=f"{self.user}{user_suffix or ''}",
password=self.password,
enabled=True,
)
def as_vnish(self, user_suffix: str | None = None) -> dict:
return {
"url": self.url,
"user": f"{self.user}{user_suffix or ''}",
"pass": self.password,
}
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "Pool":
return cls(
url=dict_conf["url"], user=dict_conf["user"], password=dict_conf["password"]
)
@classmethod
def from_api(cls, api_pool: dict) -> "Pool":
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
def from_am_modern(cls, web_pool: dict) -> "Pool":
return cls(
url=web_pool["url"], user=web_pool["user"], password=web_pool["pass"]
)
@classmethod
def from_hiveon_modern(cls, web_pool: dict) -> "Pool":
return cls(
url=web_pool["url"], user=web_pool["user"], password=web_pool["pass"]
)
@classmethod
def from_elphapex(cls, web_pool: dict) -> "Pool":
return cls(
url=web_pool["url"], user=web_pool["user"], password=web_pool["pass"]
)
# TODO: check if this is accurate, user/username, pass/password
@classmethod
def from_goldshell(cls, web_pool: dict) -> "Pool":
return cls(
url=web_pool["url"], user=web_pool["user"], password=web_pool["pass"]
)
@classmethod
def from_inno(cls, web_pool: dict) -> "Pool":
return cls(
url=web_pool["url"], user=web_pool["user"], password=web_pool["pass"]
)
@classmethod
def from_bosminer(cls, toml_pool_conf: dict) -> "Pool":
return cls(
url=toml_pool_conf["url"],
user=toml_pool_conf["user"],
password=toml_pool_conf.get("password", ""),
)
@classmethod
def from_vnish(cls, web_pool: dict) -> "Pool":
return cls(
url="stratum+tcp://" + 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"],
)
@classmethod
def from_mara(cls, web_pool: dict) -> "Pool":
return cls(
url=web_pool["url"],
user=web_pool["user"],
password=web_pool["pass"],
)
@classmethod
def from_espminer(cls, web_system_info: dict) -> "Pool":
url = f"stratum+tcp://{web_system_info['stratumURL']}:{web_system_info['stratumPort']}"
return cls(
url=url,
user=web_system_info["stratumUser"],
password=web_system_info.get("stratumPassword", ""),
)
@classmethod
def from_luxos(cls, rpc_pools: dict) -> "Pool":
return cls.from_api(rpc_pools)
@classmethod
def from_iceriver(cls, web_pool: dict) -> "Pool":
return cls(
url=web_pool["addr"],
user=web_pool["user"],
password=web_pool["pass"],
)
class PoolGroup(MinerConfigValue):
pools: list[Pool] = Field(default_factory=list)
quota: int = 1
name: str | None = None
def __post_init__(self):
if self.name is None:
self.name = "".join(
random.choice(string.ascii_uppercase + string.digits) for _ in range(6)
) # generate random pool group name in case it isn't set
def as_am_modern(self, user_suffix: str | None = None) -> list:
pools = []
idx = 0
while idx < 3:
if len(self.pools) > idx:
pools.append(self.pools[idx].as_am_modern(user_suffix=user_suffix))
else:
pools.append(Pool(url="", user="", password="").as_am_modern())
idx += 1
return pools
def as_hiveon_modern(self, user_suffix: str | None = None) -> list:
pools = []
idx = 0
while idx < 3:
if len(self.pools) > idx:
pools.append(self.pools[idx].as_hiveon_modern(user_suffix=user_suffix))
else:
pools.append(Pool(url="", user="", password="").as_hiveon_modern())
idx += 1
return pools
def as_elphapex(self, user_suffix: str | None = None) -> list:
pools = []
idx = 0
while idx < 3:
if len(self.pools) > idx:
pools.append(self.pools[idx].as_elphapex(user_suffix=user_suffix))
else:
pools.append(Pool(url="", user="", password="").as_elphapex())
idx += 1
return pools
def as_wm(self, user_suffix: str | None = None) -> dict:
pools = {}
idx = 0
while idx < 3:
if len(self.pools) > idx:
pools.update(
**self.pools[idx].as_wm(idx=idx + 1, user_suffix=user_suffix)
)
else:
pools.update(**Pool(url="", user="", password="").as_wm(idx=idx + 1))
idx += 1
return pools
def as_am_old(self, user_suffix: str | None = None) -> dict:
pools = {}
idx = 0
while idx < 3:
if len(self.pools) > idx:
pools.update(
**self.pools[idx].as_am_old(idx=idx + 1, user_suffix=user_suffix)
)
else:
pools.update(
**Pool(url="", user="", password="").as_am_old(idx=idx + 1)
)
idx += 1
return pools
def as_goldshell(self, user_suffix: str | None = None) -> list:
return [pool.as_goldshell(user_suffix) for pool in self.pools]
def as_avalon(self, user_suffix: str | None = None) -> str:
if len(self.pools) > 0:
return self.pools[0].as_avalon(user_suffix=user_suffix)
return Pool(url="", user="", password="").as_avalon()
def as_inno(self, user_suffix: str | None = None) -> dict:
pools = {}
idx = 0
while idx < 3:
if len(self.pools) > idx:
pools.update(
**self.pools[idx].as_inno(idx=idx + 1, user_suffix=user_suffix)
)
else:
pools.update(**Pool(url="", user="", password="").as_inno(idx=idx + 1))
idx += 1
return pools
def as_bosminer(self, user_suffix: str | None = None) -> dict:
if len(self.pools) > 0:
conf = {
"name": self.name,
"pool": [
pool.as_bosminer(user_suffix=user_suffix) for pool in self.pools
],
}
if self.quota is not None:
conf["quota"] = self.quota
return conf
return {"name": "Group", "pool": []}
def as_auradine(self, user_suffix: str | None = None) -> list:
return [p.as_auradine(user_suffix=user_suffix) for p in self.pools]
def as_epic(self, user_suffix: str | None = None) -> list:
return [p.as_epic(user_suffix=user_suffix) for p in self.pools]
def as_mara(self, user_suffix: str | None = None) -> list:
return [p.as_mara(user_suffix=user_suffix) for p in self.pools]
def as_espminer(self, user_suffix: str | None = None) -> dict:
return self.pools[0].as_espminer(user_suffix=user_suffix)
def as_boser(self, user_suffix: str | None = None) -> PoolGroupConfiguration:
return PoolGroupConfiguration(
name=self.name,
quota=Quota(value=self.quota),
pools=[p.as_boser() for p in self.pools],
)
def as_vnish(self, user_suffix: str | None = None) -> dict:
return {"pools": [p.as_vnish(user_suffix=user_suffix) for p in self.pools]}
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "PoolGroup":
cls_conf = {}
if dict_conf.get("quota") is not None:
cls_conf["quota"] = dict_conf["quota"]
if dict_conf.get("name") is not None:
cls_conf["name"] = dict_conf["name"]
cls_conf["pools"] = [Pool.from_dict(p) for p in dict_conf["pools"]]
return cls(**cls_conf)
@classmethod
def from_api(cls, api_pool_list: list) -> "PoolGroup":
pools = []
for pool in api_pool_list:
pools.append(Pool.from_api(pool))
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
def from_am_modern(cls, web_pool_list: list) -> "PoolGroup":
pools = []
for pool in web_pool_list:
pools.append(Pool.from_am_modern(pool))
return cls(pools=pools)
@classmethod
def from_hiveon_modern(cls, web_pool_list: list) -> "PoolGroup":
pools = []
for pool in web_pool_list:
pools.append(Pool.from_hiveon_modern(pool))
return cls(pools=pools)
@classmethod
def from_elphapex(cls, web_pool_list: list) -> "PoolGroup":
pools = []
for pool in web_pool_list:
pools.append(Pool.from_elphapex(pool))
return cls(pools=pools)
@classmethod
def from_goldshell(cls, web_pools: list) -> "PoolGroup":
return cls(pools=[Pool.from_goldshell(p) for p in web_pools])
@classmethod
def from_inno(cls, web_pools: list) -> "PoolGroup":
return cls(pools=[Pool.from_inno(p) for p in web_pools])
@classmethod
def from_bosminer(cls, toml_group_conf: dict) -> "PoolGroup":
if toml_group_conf.get("pool") is not None:
return cls(
name=toml_group_conf["name"],
quota=toml_group_conf.get("quota", 1),
pools=[Pool.from_bosminer(p) for p in toml_group_conf["pool"]],
)
return cls()
@classmethod
def from_vnish(cls, web_settings_pools: dict) -> "PoolGroup":
return cls(
pools=[Pool.from_vnish(p) for p in web_settings_pools if p["url"] != ""]
)
@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()
@classmethod
def from_mara(cls, web_config_pools: dict) -> "PoolGroup":
return cls(pools=[Pool.from_mara(pool_conf) for pool_conf in web_config_pools])
@classmethod
def from_espminer(cls, web_system_info: dict) -> "PoolGroup":
return cls(pools=[Pool.from_espminer(web_system_info)])
@classmethod
def from_iceriver(cls, web_userpanel: dict) -> "PoolGroup":
return cls(
pools=[
Pool.from_iceriver(web_pool)
for web_pool in web_userpanel["data"]["pools"]
]
)
class PoolConfig(MinerConfigValue):
groups: List[PoolGroup] = Field(default_factory=list)
@classmethod
def default(cls) -> "PoolConfig":
return cls()
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "PoolConfig":
if dict_conf is None:
return cls.default()
return cls(groups=[PoolGroup.from_dict(g) for g in dict_conf["groups"]])
@classmethod
def simple(cls, pools: list[Pool | dict[str, str]]) -> "PoolConfig":
group_pools = []
for pool in pools:
if isinstance(pool, dict):
pool = Pool(**pool)
group_pools.append(pool)
return cls(groups=[PoolGroup(pools=group_pools)])
def as_am_modern(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return {"pools": self.groups[0].as_am_modern(user_suffix=user_suffix)}
return {"pools": PoolGroup().as_am_modern()}
def as_hiveon_modern(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return {"pools": self.groups[0].as_hiveon_modern(user_suffix=user_suffix)}
return {"pools": PoolGroup().as_hiveon_modern()}
def as_elphapex(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return {"pools": self.groups[0].as_elphapex(user_suffix=user_suffix)}
return {"pools": PoolGroup().as_elphapex()}
def as_wm(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return {"pools": self.groups[0].as_wm(user_suffix=user_suffix)}
return {"pools": PoolGroup().as_wm()}
def as_am_old(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return self.groups[0].as_am_old(user_suffix=user_suffix)
return PoolGroup().as_am_old()
def as_goldshell(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return {"pools": self.groups[0].as_goldshell(user_suffix=user_suffix)}
return {"pools": PoolGroup().as_goldshell()}
def as_avalon(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return {"pools": self.groups[0].as_avalon(user_suffix=user_suffix)}
return {"pools": PoolGroup().as_avalon()}
def as_inno(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return self.groups[0].as_inno(user_suffix=user_suffix)
return PoolGroup().as_inno()
def as_bosminer(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return {
"group": [g.as_bosminer(user_suffix=user_suffix) for g in self.groups]
}
return {"group": [PoolGroup().as_bosminer()]}
def as_boser(self, user_suffix: str | None = None) -> dict:
return {
"set_pool_groups": SetPoolGroupsRequest(
save_action=SaveAction.SAVE_AND_APPLY,
pool_groups=[g.as_boser(user_suffix=user_suffix) for g in self.groups],
)
}
def as_auradine(self, user_suffix: str | None = 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 = 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,
}
}
def as_mara(self, user_suffix: str | None = None) -> dict:
if len(self.groups) > 0:
return {"pools": self.groups[0].as_mara(user_suffix=user_suffix)}
return {"pools": []}
def as_espminer(self, user_suffix: str | None = None) -> dict:
return self.groups[0].as_espminer(user_suffix=user_suffix)
def as_luxos(self, user_suffix: str | None = None) -> dict:
return {}
def as_vnish(self, user_suffix: str | None = None) -> dict:
return self.groups[0].as_vnish(user_suffix=user_suffix)
@classmethod
def from_api(cls, api_pools: dict) -> "PoolConfig":
try:
pool_data = api_pools["POOLS"]
except KeyError:
return PoolConfig.default()
pool_data = sorted(pool_data, key=lambda x: int(x["POOL"]))
return cls(groups=[PoolGroup.from_api(pool_data)])
@classmethod
def from_epic(cls, web_conf: dict) -> "PoolConfig":
pool_data = web_conf["StratumConfigs"]
return cls(groups=[PoolGroup.from_epic(pool_data)])
@classmethod
def from_am_modern(cls, web_conf: dict) -> "PoolConfig":
try:
pool_data = web_conf["pools"]
except KeyError:
return cls(groups=[])
return cls(groups=[PoolGroup.from_am_modern(pool_data)])
@classmethod
def from_hiveon_modern(cls, web_conf: dict) -> "PoolConfig":
try:
pool_data = web_conf["pools"]
except KeyError:
return cls(groups=[])
return cls(groups=[PoolGroup.from_hiveon_modern(pool_data)])
@classmethod
def from_elphapex(cls, web_conf: dict) -> "PoolConfig":
pool_data = web_conf["pools"]
return cls(groups=[PoolGroup.from_elphapex(pool_data)])
@classmethod
def from_goldshell(cls, web_pools: list) -> "PoolConfig":
return cls(groups=[PoolGroup.from_goldshell(web_pools)])
@classmethod
def from_inno(cls, web_pools: list) -> "PoolConfig":
return cls(groups=[PoolGroup.from_inno(web_pools)])
@classmethod
def from_bosminer(cls, toml_conf: dict) -> "PoolConfig":
if toml_conf.get("group") is None:
return cls()
return cls(groups=[PoolGroup.from_bosminer(g) for g in toml_conf["group"]])
@classmethod
def from_vnish(cls, web_settings: dict) -> "PoolConfig":
try:
return cls(groups=[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()
@classmethod
def from_mara(cls, web_config: dict) -> "PoolConfig":
return cls(groups=[PoolGroup.from_mara(web_config["pools"])])
@classmethod
def from_espminer(cls, web_system_info: dict) -> "PoolConfig":
return cls(groups=[PoolGroup.from_espminer(web_system_info)])
@classmethod
def from_iceriver(cls, web_userpanel: dict) -> "PoolConfig":
return cls(groups=[PoolGroup.from_iceriver(web_userpanel)])
@classmethod
def from_luxos(cls, rpc_groups: dict, rpc_pools: dict) -> "PoolConfig":
return cls(
groups=[
PoolGroup(
pools=[
Pool.from_luxos(pool)
for pool in rpc_pools["POOLS"]
if pool["GROUP"] == group["GROUP"]
],
name=group["Name"],
quota=group["Quota"],
)
for group in rpc_groups["GROUPS"]
]
)

View File

@@ -0,0 +1,155 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from __future__ import annotations
from pyasic.config.base import MinerConfigValue
class TemperatureConfig(MinerConfigValue):
target: int | None = None
hot: int | None = None
danger: int | None = None
@classmethod
def default(cls):
return cls()
def as_bosminer(self) -> dict:
temp_cfg = {}
if self.target is not None:
temp_cfg["target_temp"] = self.target
if self.hot is not None:
temp_cfg["hot_temp"] = self.hot
if self.danger is not None:
temp_cfg["dangerous_temp"] = self.danger
if len(temp_cfg) == 0:
return {}
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"]["critical"] = self.danger
if self.hot is not None:
temps_config["temps"]["shutdown"] = self.hot
return temps_config
def as_luxos(self) -> dict:
return {"tempctrlset": [self.target or "", self.hot or "", self.danger or ""]}
def as_vnish(self) -> dict:
return {"misc": {"restart_temp": self.danger}}
@classmethod
def from_dict(cls, dict_conf: dict | None) -> "TemperatureConfig":
return cls(
target=dict_conf.get("target"),
hot=dict_conf.get("hot"),
danger=dict_conf.get("danger"),
)
@classmethod
def from_bosminer(cls, toml_conf: dict) -> "TemperatureConfig":
temp_control = toml_conf.get("temp_control")
if temp_control is not None:
return cls(
target=temp_control.get("target_temp"),
hot=temp_control.get("hot_temp"),
danger=temp_control.get("dangerous_temp"),
)
return cls()
@classmethod
def from_epic(cls, web_conf: dict) -> "TemperatureConfig":
try:
dangerous_temp = web_conf["Misc"]["Critical Temp"]
except KeyError:
dangerous_temp = None
try:
hot_temp = web_conf["Misc"]["Shutdown Temp"]
except KeyError:
hot_temp = None
# Need to do this in two blocks to avoid KeyError if one is missing
try:
target_temp = web_conf["Fans"]["Fan Mode"]["Auto"]["Target Temperature"]
except KeyError:
target_temp = None
return cls(target=target_temp, hot=hot_temp, danger=dangerous_temp)
@classmethod
def from_vnish(cls, web_settings: dict) -> "TemperatureConfig":
try:
dangerous_temp = web_settings["misc"]["restart_temp"]
except KeyError:
dangerous_temp = None
try:
if web_settings["miner"]["cooling"]["mode"]["name"] == "auto":
return cls(
target=web_settings["miner"]["cooling"]["mode"]["param"],
danger=dangerous_temp,
)
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()
@classmethod
def from_luxos(cls, rpc_tempctrl: dict) -> "TemperatureConfig":
try:
tempctrl_config = rpc_tempctrl["TEMPCTRL"][0]
return cls(
target=tempctrl_config.get("Target"),
hot=tempctrl_config.get("Hot"),
danger=tempctrl_config.get("Dangerous"),
)
except LookupError:
pass
return cls.default()

View File

@@ -13,84 +13,26 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
import copy
import json
import logging
import time
from dataclasses import asdict, dataclass, field, fields
from datetime import datetime, timezone
from typing import Any, List, Union
from typing import Any
from pydantic import BaseModel, Field, computed_field
from pyasic.config import MinerConfig
from pyasic.config.mining import MiningModePowerTune
from pyasic.data.pools import PoolMetrics, Scheme
from pyasic.device.algorithm.hashrate import AlgoHashRateType
from .boards import HashBoard
from .device import DeviceInfo
from .error_codes import BraiinsOSError, InnosiliconError, WhatsminerError, X19Error
from .error_codes.base import BaseMinerError
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 ideal 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
class MinerData:
class MinerData(BaseModel):
"""A Dataclass to standardize data returned from miners (specifically `AnyMiner().get_data()`)
Attributes:
@@ -98,82 +40,100 @@ class MinerData:
datetime: The time and date this data was generated.
uptime: The uptime of the miner in seconds.
mac: The MAC address of the miner as a str.
device_info: Info about the device, such as model, make, and firmware.
model: The model of the miner as a str.
make: The make of the miner as a str.
firmware: The firmware on the miner as a str.
algo: The mining algorithm of the miner as a str.
api_ver: The current api version on the miner as a str.
fw_ver: The current firmware version on the miner as a str.
hostname: The network hostname of the miner as a str.
hashrate: The hashrate of the miner in TH/s as a float. Calculated automatically.
_hashrate: Backup for hashrate found via API instead of hashboards.
nominal_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.
expected_hashrate: The factory nominal hashrate of the miner in TH/s as a float.
sticker_hashrate: The factory sticker hashrate of the miner as a float.
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.
env_temp: The environment temps as a float.
wattage: Current power draw of the miner as an int.
voltage: Current output voltage of the PSU as an float.
wattage_limit: Power limit of the miner as an int.
fans: A list of fans on the miner with their speeds.
expected_fans: The number of fans expected on a miner.
fan_psu: The speed of the PSU on the fan if the miner collects it.
total_chips: The total number of chips on all boards. Calculated automatically.
ideal_chips: The ideal number of chips in the miner as an int.
percent_ideal_chips: The percent of total chips out of the ideal count. Calculated automatically.
percent_ideal_hashrate: The percent of total hashrate out of the ideal hashrate. Calculated automatically.
percent_ideal_wattage: The percent of total wattage out of the ideal wattage. Calculated automatically.
expected_chips: The expected number of chips in the miner as an int.
percent_expected_chips: The percent of total chips out of the expected count. 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.
nominal: Whether the number of chips in the miner is nominal. Calculated automatically.
pool_split: The pool split as a str.
pool_1_url: The first pool url on the miner as a str.
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.
config: The parsed config of the miner, using [`MinerConfig`][pyasic.config.MinerConfig].
errors: A list of errors on the miner.
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_fract: Same as efficiency, but is not rounded to integer. Calculated automatically.
is_mining: Whether the miner is mining.
pools: A list of PoolMetrics instances, each representing metrics for a pool.
"""
# general
ip: str
datetime: datetime = None
uptime: int = None
mac: str = None
model: str = None
make: str = None
api_ver: str = None
fw_ver: str = None
hostname: str = None
hashrate: float = field(init=False)
_hashrate: float = None
nominal_hashrate: float = None
hashboards: List[HashBoard] = field(default_factory=list)
ideal_hashboards: int = None
temperature_avg: int = field(init=False)
env_temp: float = None
wattage: int = None
wattage_limit: int = None
fans: List[Fan] = field(default_factory=list)
fan_psu: int = None
total_chips: int = field(init=False)
ideal_chips: int = None
percent_ideal_chips: float = field(init=False)
percent_ideal_hashrate: float = field(init=False)
percent_ideal_wattage: float = field(init=False)
nominal: bool = field(init=False)
pool_split: str = "0"
pool_1_url: str = "Unknown"
pool_1_user: str = "Unknown"
pool_2_url: str = ""
pool_2_user: str = ""
errors: List[
Union[WhatsminerError, BraiinsOSError, X19Error, InnosiliconError]
] = field(default_factory=list)
fault_light: Union[bool, None] = None
efficiency: int = field(init=False)
raw_datetime: datetime = Field(
exclude=True, default_factory=datetime.now(timezone.utc).astimezone, repr=False
)
# about
device_info: DeviceInfo | None = None
mac: str | None = None
api_ver: str | None = None
fw_ver: str | None = None
hostname: str | None = None
# hashrate
raw_hashrate: AlgoHashRateType = Field(exclude=True, default=None, repr=False)
# sticker
sticker_hashrate: AlgoHashRateType | None = None
# expected
expected_hashrate: AlgoHashRateType | None = None
expected_hashboards: int | None = None
expected_chips: int | None = None
expected_fans: int | None = None
# temperature
env_temp: float | None = None
# power
wattage: int | None = None
voltage: float | None = None
raw_wattage_limit: int | None = Field(exclude=True, default=None, repr=False)
# fans
fans: list[Fan] = Field(default_factory=list)
fan_psu: int | None = None
# boards
hashboards: list[HashBoard] = Field(default_factory=list)
# config
config: MinerConfig | None = None
fault_light: bool | None = None
# errors
errors: list[BaseMinerError] = Field(default_factory=list)
# mining state
is_mining: bool = True
uptime: int | None = None
# pools
pools: list[PoolMetrics] = Field(default_factory=list)
@classmethod
def fields(cls):
return [f.name for f in fields(cls)]
def __post_init__(self):
self.datetime = datetime.now(timezone.utc).astimezone()
def fields(cls) -> set:
all_fields = set(cls.model_fields.keys())
all_fields.update(set(cls.model_computed_fields.keys()))
return all_fields
def get(self, __key: str, default: Any = None):
try:
@@ -201,19 +161,19 @@ class MinerData:
def __floordiv__(self, other):
cp = copy.deepcopy(self)
for key in self:
for key in self.fields():
item = getattr(self, key)
if isinstance(item, int):
setattr(cp, key, item // other)
if isinstance(item, float):
setattr(cp, key, round(item / other, 2))
setattr(cp, key, item / other)
return cp
def __add__(self, other):
if not isinstance(other, MinerData):
raise TypeError("Cannot add MinerData to non MinerData type.")
cp = copy.deepcopy(self)
for key in self:
for key in self.fields():
item = getattr(self, key)
other_item = getattr(other, key)
if item is None:
@@ -233,23 +193,37 @@ class MinerData:
setattr(cp, key, item & other_item)
return cp
@computed_field # type: ignore[misc]
@property
def hashrate(self): # noqa - Skip PyCharm inspection
def hashrate(self) -> AlgoHashRateType | None:
if len(self.hashboards) > 0:
hr_data = []
for item in self.hashboards:
if item.hashrate is not None:
hr_data.append(item.hashrate)
if len(hr_data) > 0:
return round(sum(hr_data), 2)
return self._hashrate
return sum(hr_data, start=self.device_info.algo.hashrate(rate=0))
return self.raw_hashrate
@hashrate.setter
def hashrate(self, val):
self._hashrate = val
self.raw_hashrate = val
@computed_field # type: ignore[misc]
@property
def total_chips(self): # noqa - Skip PyCharm inspection
def wattage_limit(self) -> int | None:
if self.config is not None:
if isinstance(self.config.mining_mode, MiningModePowerTune):
return self.config.mining_mode.power
return self.raw_wattage_limit
@wattage_limit.setter
def wattage_limit(self, val: int):
self.raw_wattage_limit = val
@computed_field # type: ignore[misc]
@property
def total_chips(self) -> int | None:
if len(self.hashboards) > 0:
chip_data = []
for item in self.hashboards:
@@ -259,58 +233,45 @@ class MinerData:
return sum(chip_data)
return None
@total_chips.setter
def total_chips(self, val):
pass
@computed_field # type: ignore[misc]
@property
def nominal(self): # noqa - Skip PyCharm inspection
if self.total_chips is None or self.ideal_chips is None:
def nominal(self) -> bool | None:
if self.total_chips is None or self.expected_chips is None:
return None
return self.ideal_chips == self.total_chips
@nominal.setter
def nominal(self, val):
pass
return self.expected_chips == self.total_chips
@computed_field # type: ignore[misc]
@property
def percent_ideal_chips(self): # noqa - Skip PyCharm inspection
if self.total_chips is None or self.ideal_chips is None:
def percent_expected_chips(self) -> int | None:
if self.total_chips is None or self.expected_chips is None:
return None
if self.total_chips == 0 or self.ideal_chips == 0:
if self.total_chips == 0 or self.expected_chips == 0:
return 0
return round((self.total_chips / self.ideal_chips) * 100)
@percent_ideal_chips.setter
def percent_ideal_chips(self, val):
pass
return round((self.total_chips / self.expected_chips) * 100)
@computed_field # type: ignore[misc]
@property
def percent_ideal_hashrate(self): # noqa - Skip PyCharm inspection
if self.hashrate is None or self.nominal_hashrate is None:
def percent_expected_hashrate(self) -> int | None:
if self.hashrate is None or self.expected_hashrate is None:
return None
if self.hashrate == 0 or self.nominal_hashrate == 0:
try:
return round((self.hashrate / self.expected_hashrate) * 100)
except ZeroDivisionError:
return 0
return round((self.hashrate / self.nominal_hashrate) * 100)
@percent_ideal_hashrate.setter
def percent_ideal_hashrate(self, val):
pass
@computed_field # type: ignore[misc]
@property
def percent_ideal_wattage(self): # noqa - Skip PyCharm inspection
def percent_expected_wattage(self) -> int | None:
if self.wattage_limit is None or self.wattage is None:
return None
if self.wattage_limit == 0 or self.wattage == 0:
try:
return round((self.wattage / self.wattage_limit) * 100)
except ZeroDivisionError:
return 0
return round((self.wattage / self.wattage_limit) * 100)
@percent_ideal_wattage.setter
def percent_ideal_wattage(self, val):
pass
@computed_field # type: ignore[misc]
@property
def temperature_avg(self): # noqa - Skip PyCharm inspection
def temperature_avg(self) -> int | None:
total_temp = 0
temp_count = 0
for hb in self.hashboards:
@@ -321,25 +282,67 @@ class MinerData:
return None
return round(total_temp / temp_count)
@temperature_avg.setter
def temperature_avg(self, val):
pass
@computed_field # type: ignore[misc]
@property
def efficiency(self): # noqa - Skip PyCharm inspection
def efficiency(self) -> int | None:
efficiency = self._efficiency(0)
if efficiency is None:
return None
else:
return int(efficiency)
@computed_field # type: ignore[misc]
@property
def efficiency_fract(self) -> float | None:
return self._efficiency(2)
def _efficiency(self, ndigits: int) -> float | None:
if self.hashrate is None or self.wattage is None:
return None
if self.hashrate == 0 or self.wattage == 0:
return 0
return round(self.wattage / self.hashrate)
try:
return round(self.wattage / float(self.hashrate), ndigits)
except ZeroDivisionError:
return 0.0
@efficiency.setter
def efficiency(self, val):
pass
@computed_field # type: ignore[misc]
@property
def datetime(self) -> str:
return self.raw_datetime.isoformat()
@computed_field # type: ignore[misc]
@property
def timestamp(self) -> int:
return int(time.mktime(self.raw_datetime.timetuple()))
@computed_field # type: ignore[misc]
@property
def make(self) -> str | None:
if self.device_info.make is not None:
return str(self.device_info.make)
@computed_field # type: ignore[misc]
@property
def model(self) -> str | None:
if self.device_info.model is not None:
return str(self.device_info.model)
@computed_field # type: ignore[misc]
@property
def firmware(self) -> str | None:
if self.device_info.firmware is not None:
return str(self.device_info.firmware)
@computed_field # type: ignore[misc]
@property
def algo(self) -> str | None:
if self.device_info.algo is not None:
return str(self.device_info.algo)
def keys(self) -> list:
return list(self.model_fields.keys())
def asdict(self) -> dict:
logging.debug(f"MinerData - (To Dict) - Dumping Dict data")
return asdict(self)
return self.model_dump()
def as_dict(self) -> dict:
"""Get this dataclass as a dictionary.
@@ -355,10 +358,7 @@ class MinerData:
Returns:
A JSON version of this class.
"""
logging.debug(f"MinerData - (To JSON) - Dumping JSON data")
data = self.asdict()
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
return json.dumps(data)
return self.model_dump_json()
def as_csv(self) -> str:
"""Get this dataclass as CSV.
@@ -366,9 +366,7 @@ class MinerData:
Returns:
A CSV version of this class with no headers.
"""
logging.debug(f"MinerData - (To CSV) - Dumping CSV data")
data = self.asdict()
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
errs = []
for error in data["errors"]:
errs.append(error["error_message"])
@@ -376,7 +374,9 @@ class MinerData:
data_list = [str(data[item]) for item in data]
return ",".join(data_list)
def as_influxdb(self, measurement_name: str = "miner_data") -> str:
def as_influxdb(
self, measurement_name: str = "miner_data", level_delimiter: str = "."
) -> str:
"""Get this dataclass as [influxdb line protocol](https://docs.influxdata.com/influxdb/v2.4/reference/syntax/line-protocol/).
Parameters:
@@ -385,55 +385,127 @@ class MinerData:
Returns:
A influxdb line protocol version of this class.
"""
logging.debug(f"MinerData - (To InfluxDB) - Dumping InfluxDB data")
tag_data = [measurement_name]
def serialize_int(key: str, value: int) -> str:
return f"{key}={value}"
def serialize_float(key: str, value: float) -> str:
return f"{key}={value}"
def serialize_str(key: str, value: str) -> str:
return f'{key}="{value}"'
def serialize_algo_hash_rate(key: str, value: AlgoHashRateType) -> str:
return f"{key}={round(float(value), 2)}"
def serialize_list(key: str, value: list[Any]) -> str | None:
if len(value) == 0:
return None
list_field_data = []
for idx, list_field_val in enumerate(value):
item_serialization_func = serialization_map.get(
type(list_field_val), lambda _k, _v: None
)
item_serialized = item_serialization_func(
f"{key}{level_delimiter}{idx}", list_field_val
)
if item_serialized is not None:
list_field_data.append(item_serialized)
continue
for dt in serialization_map_instance:
if item_serialized is None:
if isinstance(list_field_val, dt):
item_serialized = serialization_map_instance[dt](
f"{key}{level_delimiter}{idx}", list_field_val
)
if item_serialized is not None:
list_field_data.append(item_serialized)
return ",".join(list_field_data)
def serialize_miner_error(key: str, value: BaseMinerError):
return value.as_influxdb(key, level_delimiter=level_delimiter)
def serialize_fan(key: str, value: Fan) -> str:
return f"{key}{level_delimiter}speed={value.speed}"
def serialize_hashboard(key: str, value: HashBoard) -> str:
return value.as_influxdb(key, level_delimiter=level_delimiter)
def serialize_bool(key: str, value: bool):
return f"{key}={str(value).lower()}"
def serialize_pool_metrics(key: str, value: PoolMetrics):
return value.as_influxdb(key, level_delimiter=level_delimiter)
include = [
"uptime",
"expected_hashrate",
"hashrate",
"hashboards",
"temperature_avg",
"env_temp",
"wattage",
"wattage_limit",
"voltage",
"fans",
"expected_fans",
"fan_psu",
"total_chips",
"expected_chips",
"efficiency",
"fault_light",
"is_mining",
"errors",
"pools",
]
serialization_map_instance = {
AlgoHashRateType: serialize_algo_hash_rate,
BaseMinerError: serialize_miner_error,
}
serialization_map = {
int: serialize_int,
float: serialize_float,
str: serialize_str,
bool: serialize_bool,
list: serialize_list,
Fan: serialize_fan,
HashBoard: serialize_hashboard,
PoolMetrics: serialize_pool_metrics,
}
tag_data = [
measurement_name,
f"ip={str(self.ip)}",
f"mac={str(self.mac)}",
f"make={str(self.make)}",
f"model={str(self.model)}",
f"firmware={str(self.firmware)}",
f"algo={str(self.algo)}",
]
field_data = []
tags = ["ip", "mac", "model", "hostname"]
for attribute in self:
if attribute in tags:
escaped_data = self.get(attribute, "Unknown").replace(" ", "\\ ")
tag_data.append(f"{attribute}={escaped_data}")
for field in include:
field_val = getattr(self, field)
serialization_func = serialization_map.get(
type(field_val), lambda _k, _v: None
)
serialized = serialization_func(field, field_val)
if serialized is not None:
field_data.append(serialized)
continue
elif str(attribute).startswith("_"):
continue
elif isinstance(self[attribute], str):
field_data.append(f'{attribute}="{self[attribute]}"')
continue
elif isinstance(self[attribute], bool):
field_data.append(f"{attribute}={str(self[attribute]).lower()}")
continue
elif isinstance(self[attribute], int):
field_data.append(f"{attribute}={self[attribute]}")
continue
elif isinstance(self[attribute], float):
field_data.append(f"{attribute}={self[attribute]}")
continue
elif attribute == "errors":
for idx, item in enumerate(self[attribute]):
field_data.append(f'error_{idx+1}="{item.error_message}"')
elif attribute == "hashboards":
for idx, item in enumerate(self[attribute]):
field_data.append(
f"hashboard_{idx+1}_hashrate={item.get('hashrate', 0.0)}"
)
field_data.append(
f"hashboard_{idx+1}_temperature={item.get('temp', 0)}"
)
field_data.append(
f"hashboard_{idx+1}_chip_temperature={item.get('chip_temp', 0)}"
)
field_data.append(f"hashboard_{idx+1}_chips={item.get('chips', 0)}")
field_data.append(
f"hashboard_{idx+1}_expected_chips={item.get('expected_chips', 0)}"
)
elif attribute == "fans":
for idx, item in enumerate(self[attribute]):
if item.speed is not None:
field_data.append(f"fan_{idx+1}={item.speed}")
for datatype in serialization_map_instance:
if serialized is None:
if isinstance(field_val, datatype):
serialized = serialization_map_instance[datatype](
field, field_val
)
if serialized is not None:
field_data.append(serialized)
tags_str = ",".join(tag_data)
field_str = ",".join(field_data)
timestamp = str(int(time.mktime(self.datetime.timetuple()) * 1e9))
tags_str = ",".join(tag_data).replace(" ", "\\ ")
field_str = ",".join(field_data).replace(" ", "\\ ")
timestamp = str(self.timestamp * 10**9)
return " ".join([tags_str, field_str, timestamp])

137
pyasic/data/boards.py Normal file
View File

@@ -0,0 +1,137 @@
# ------------------------------------------------------------------------------
# Copyright 2022 Upstream Data Inc -
# -
# Licensed under the Apache License, Version 2.0 (the "License"); -
# you may not use this file except in compliance with the License. -
# You may obtain a copy of the License at -
# -
# http://www.apache.org/licenses/LICENSE-2.0 -
# -
# Unless required by applicable law or agreed to in writing, software -
# distributed under the License is distributed on an "AS IS" BASIS, -
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from __future__ import annotations
from typing import Any
from pydantic import BaseModel
from pyasic.device.algorithm.hashrate import AlgoHashRateType
class HashBoard(BaseModel):
"""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.
inlet_temp: Inlet temperature for hydro asics as an int
outlet_temp: Outlet temperature for hydro asics as an int
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.
tuned: Whether the board is tuned as a bool.
active: Whether the board is currently tuning as a bool.
voltage: Current input voltage of the board as a float.
"""
slot: int = 0
hashrate: AlgoHashRateType | None = None
inlet_temp: float | None = None
outlet_temp: float | None = None
temp: float | None = None
chip_temp: float | None = None
chips: int | None = None
expected_chips: int | None = None
serial_number: str | None = None
missing: bool = True
tuned: bool | None = None
active: bool | None = None
voltage: float | None = None
@classmethod
def fields(cls) -> set:
all_fields = set(cls.model_fields.keys())
all_fields.update(set(cls.model_computed_fields.keys()))
return all_fields
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}")
def as_influxdb(self, key_root: str, level_delimiter: str = ".") -> str:
def serialize_int(key: str, value: int) -> str:
return f"{key}={value}"
def serialize_float(key: str, value: float) -> str:
return f"{key}={value}"
def serialize_str(key: str, value: str) -> str:
return f'{key}="{value}"'
def serialize_algo_hash_rate(key: str, value: AlgoHashRateType) -> str:
return f"{key}={round(float(value), 2)}"
def serialize_bool(key: str, value: bool):
return f"{key}={str(value).lower()}"
serialization_map_instance = {
AlgoHashRateType: serialize_algo_hash_rate,
}
serialization_map = {
int: serialize_int,
float: serialize_float,
str: serialize_str,
bool: serialize_bool,
}
include = [
"hashrate",
"temp",
"chip_temp",
"chips",
"expected_chips",
"tuned",
"active",
"voltage",
]
field_data = []
for field in include:
field_val = getattr(self, field)
serialization_func = serialization_map.get(
type(field_val), lambda _k, _v: None
)
serialized = serialization_func(
f"{key_root}{level_delimiter}{field}", field_val
)
if serialized is not None:
field_data.append(serialized)
continue
for datatype in serialization_map_instance:
if serialized is None:
if isinstance(field_val, datatype):
serialized = serialization_map_instance[datatype](
f"{key_root}{level_delimiter}{field}", field_val
)
if serialized is not None:
field_data.append(serialized)
return ",".join(field_data)

31
pyasic/data/device.py Normal file
View File

@@ -0,0 +1,31 @@
from pydantic import BaseModel, ConfigDict, field_serializer
from pyasic.device.algorithm import MinerAlgoType
from pyasic.device.firmware import MinerFirmware
from pyasic.device.makes import MinerMake
from pyasic.device.models import MinerModelType
class DeviceInfo(BaseModel):
model_config = ConfigDict(arbitrary_types_allowed=True)
make: MinerMake | None = None
model: MinerModelType | None = None
firmware: MinerFirmware | None = None
algo: type[MinerAlgoType] | None = None
@field_serializer("make")
def serialize_make(self, make: MinerMake, _info):
return str(make)
@field_serializer("model")
def serialize_model(self, model: MinerModelType, _info):
return str(model)
@field_serializer("firmware")
def serialize_firmware(self, firmware: MinerFirmware, _info):
return str(firmware)
@field_serializer("algo")
def serialize_algo(self, algo: MinerAlgoType, _info):
return str(algo)

View File

@@ -13,12 +13,10 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from dataclasses import asdict, dataclass, fields
from pyasic.data.error_codes.base import BaseMinerError
@dataclass
class X19Error:
class X19Error(BaseMinerError):
"""A Dataclass to handle error codes of X19 miners.
Attributes:
@@ -28,10 +26,3 @@ class X19Error:
error_message: str
error_code: int = 0
@classmethod
def fields(cls):
return fields(cls)
def asdict(self):
return asdict(self)

View File

@@ -18,9 +18,15 @@ from typing import TypeVar
from .bos import BraiinsOSError
from .innosilicon import InnosiliconError
from .vnish import VnishError
from .whatsminer import WhatsminerError
from .X19 import X19Error
MinerErrorData = TypeVar(
"MinerErrorData", WhatsminerError, BraiinsOSError, X19Error, InnosiliconError
"MinerErrorData",
WhatsminerError,
BraiinsOSError,
X19Error,
InnosiliconError,
VnishError,
)

View File

@@ -0,0 +1,32 @@
from pydantic import BaseModel
class BaseMinerError(BaseModel):
@classmethod
def fields(cls):
return list(cls.model_fields.keys())
def asdict(self) -> dict:
return self.model_dump()
def as_dict(self) -> dict:
"""Get this dataclass as a dictionary.
Returns:
A dictionary version of this class.
"""
return self.asdict()
def as_influxdb(self, root_key: str, level_delimiter: str = ".") -> str:
field_data = []
if self.error_code is not None:
field_data.append(
f"{root_key}{level_delimiter}error_code={self.error_code}"
)
if self.error_message is not None:
field_data.append(
f'{root_key}{level_delimiter}error_message="{self.error_message}"'
)
return ",".join(field_data)

View File

@@ -14,11 +14,10 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from dataclasses import asdict, dataclass, fields
from pyasic.data.error_codes.base import BaseMinerError
@dataclass
class BraiinsOSError:
class BraiinsOSError(BaseMinerError):
"""A Dataclass to handle error codes of BraiinsOS+ miners.
Attributes:
@@ -28,10 +27,3 @@ class BraiinsOSError:
error_message: str
error_code: int = 0
@classmethod
def fields(cls):
return fields(cls)
def asdict(self):
return asdict(self)

View File

@@ -14,11 +14,13 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from dataclasses import asdict, dataclass, field, fields
from pydantic import computed_field
from pyasic.data.error_codes.base import BaseMinerError
@dataclass
class InnosiliconError:
class InnosiliconError(BaseMinerError):
"""A Dataclass to handle error codes of Innosilicon miners.
Attributes:
@@ -27,25 +29,14 @@ class InnosiliconError:
"""
error_code: int
error_message: str = field(init=False)
@classmethod
def fields(cls):
return fields(cls)
@computed_field # type: ignore[misc]
@property
def error_message(self): # noqa - Skip PyCharm inspection
def error_message(self) -> str: # noqa - Skip PyCharm inspection
if self.error_code in ERROR_CODES:
return ERROR_CODES[self.error_code]
return "Unknown error type."
@error_message.setter
def error_message(self, val):
pass
def asdict(self):
return asdict(self)
ERROR_CODES = {
21: "The PLUG signal of the hash board is not detected.",

View File

@@ -0,0 +1,28 @@
# ------------------------------------------------------------------------------
# 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.data.error_codes.base import BaseMinerError
class VnishError(BaseMinerError):
"""A Dataclass to handle error codes of Vnish miners.
Attributes:
error_message: The error message as a string.
error_code: The error code as an int. 0 if the message is not assigned a code.
"""
error_message: str
error_code: int = 0

View File

@@ -13,12 +13,12 @@
# See the License for the specific language governing permissions and -
# limitations under the License. -
# ------------------------------------------------------------------------------
from pydantic import computed_field
from dataclasses import asdict, dataclass, field, fields
from pyasic.data.error_codes.base import BaseMinerError
@dataclass
class WhatsminerError:
class WhatsminerError(BaseMinerError):
"""A Dataclass to handle error codes of Whatsminers.
Attributes:
@@ -27,14 +27,10 @@ class WhatsminerError:
"""
error_code: int
error_message: str = field(init=False)
@classmethod
def fields(cls):
return fields(cls)
@computed_field # type: ignore[misc]
@property
def error_message(self): # noqa - Skip PyCharm inspection
def error_message(self) -> str: # noqa - Skip PyCharm inspection
if len(str(self.error_code)) == 6 and not str(self.error_code)[:1] == "1":
err_type = int(str(self.error_code)[:2])
err_subtype = int(str(self.error_code)[2:3])
@@ -74,13 +70,6 @@ class WhatsminerError:
except KeyError:
return "Unknown error type."
@error_message.setter
def error_message(self, val):
pass
def asdict(self):
return asdict(self)
ERROR_CODES = {
1: { # Fan error

View File

@@ -14,22 +14,31 @@
# limitations under the License. -
# ------------------------------------------------------------------------------
from pyasic.miners.makes import WhatsMiner
from typing import Any
from pydantic import BaseModel
class M20PV10(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M20P V10"
self.nominal_chips = 156
self.fan_count = 2
class Fan(BaseModel):
"""A Dataclass to standardize fan data.
Attributes:
speed: The speed of the fan.
"""
class M20PV30(WhatsMiner): # noqa - ignore ABC method implementation
def __init__(self, ip: str, api_ver: str = "0.0.0"):
super().__init__(ip, api_ver)
self.ip = ip
self.model = "M20P V30"
self.nominal_chips = 148
self.fan_count = 2
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}")

142
pyasic/data/pools.py Normal file
View File

@@ -0,0 +1,142 @@
from enum import Enum
from typing import Optional
from urllib.parse import urlparse
from pydantic import BaseModel, computed_field, model_serializer
from typing_extensions import Self
class Scheme(Enum):
STRATUM_V1 = "stratum+tcp"
STRATUM_V2 = "stratum2+tcp"
STRATUM_V1_SSL = "stratum+ssl"
class PoolUrl(BaseModel):
scheme: Scheme
host: str
port: int
pubkey: Optional[str] = None
@model_serializer
def serialize(self):
return str(self)
def __str__(self) -> str:
if self.scheme == Scheme.STRATUM_V2 and self.pubkey:
return f"{self.scheme.value}://{self.host}:{self.port}/{self.pubkey}"
else:
return f"{self.scheme.value}://{self.host}:{self.port}"
@classmethod
def from_str(cls, url: str) -> Self | None:
parsed_url = urlparse(url)
if not parsed_url.hostname:
return None
if not parsed_url.scheme.strip() == "":
scheme = Scheme(parsed_url.scheme)
else:
scheme = Scheme.STRATUM_V1
host = parsed_url.hostname
port = parsed_url.port
pubkey = parsed_url.path.lstrip("/") if scheme == Scheme.STRATUM_V2 else None
return cls(scheme=scheme, host=host, port=port, pubkey=pubkey)
class PoolMetrics(BaseModel):
"""A dataclass to standardize pool metrics returned from miners.
Attributes:
accepted: Number of accepted shares.
rejected: Number of rejected shares.
get_failures: Number of failures in obtaining work from the pool.
remote_failures: Number of failures communicating with the pool server.
active: Indicates if the miner is connected to the stratum server.
Alive : Indicates if a pool is alive.
url: URL of the pool.
index: Index of the pool.
user: Username for the pool.
pool_rejected_percent: Percentage of rejected shares by the pool.
pool_stale_percent: Percentage of stale shares by the pool.
"""
url: PoolUrl | None
accepted: int | None = None
rejected: int | None = None
get_failures: int | None = None
remote_failures: int | None = None
active: bool | None = None
alive: bool | None = None
index: int | None = None
user: str | None = None
@computed_field # type: ignore[misc]
@property
def pool_rejected_percent(self) -> float: # noqa - Skip PyCharm inspection
"""Calculate and return the percentage of rejected shares"""
return self._calculate_percentage(self.rejected, self.accepted + self.rejected)
@computed_field # type: ignore[misc]
@property
def pool_stale_percent(self) -> float: # noqa - Skip PyCharm inspection
"""Calculate and return the percentage of stale shares."""
return self._calculate_percentage(
self.get_failures, self.accepted + self.rejected
)
@staticmethod
def _calculate_percentage(value: int, total: int) -> float:
"""Calculate the percentage."""
if value is None or total is None:
return 0
if total == 0:
return 0
return (value / total) * 100
def as_influxdb(self, key_root: str, level_delimiter: str = ".") -> str:
def serialize_int(key: str, value: int) -> str:
return f"{key}={value}"
def serialize_float(key: str, value: float) -> str:
return f"{key}={value}"
def serialize_str(key: str, value: str) -> str:
return f'{key}="{value}"'
def serialize_pool_url(key: str, value: str) -> str:
return f'{key}="{str(value)}"'
def serialize_bool(key: str, value: bool):
return f"{key}={str(value).lower()}"
serialization_map = {
int: serialize_int,
float: serialize_float,
str: serialize_str,
bool: serialize_bool,
PoolUrl: serialize_pool_url,
}
include = [
"url",
"accepted",
"rejected",
"active",
"alive",
"user",
]
field_data = []
for field in include:
field_val = getattr(self, field)
serialization_func = serialization_map.get(
type(field_val), lambda _k, _v: None
)
serialized = serialization_func(
f"{key_root}{level_delimiter}{field}", field_val
)
if serialized is not None:
field_data.append(serialized)
return ",".join(field_data)

View File

@@ -0,0 +1,4 @@
from .algorithm import MinerAlgo
from .firmware import MinerFirmware
from .makes import MinerMake
from .models import MinerModel

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