Compare commits

...

17 Commits

Author SHA1 Message Date
UpstreamData
59667cf104 bump version number 2022-08-29 09:53:01 -06:00
UpstreamData
3fd1b41bec add support for whatsminer VH60 2022-08-29 09:52:35 -06:00
UpstreamData
6569107f64 bump version number 2022-08-29 09:07:02 -06:00
UpstreamData
9d746a6dcb add errors to MinerData().as_influxdb() 2022-08-29 09:06:20 -06:00
UpstreamData
fce4c07c32 bump version number 2022-08-25 15:34:28 -06:00
UpstreamData
094857758a update MinerData().as_influxdb() to include properties. 2022-08-25 15:34:04 -06:00
UpstreamData
2a49b89849 bump version number 2022-08-25 13:09:19 -06:00
UpstreamData
4ecd135734 fix a bug with incorrect types in miner data 2022-08-25 13:09:03 -06:00
UpstreamData
836defc216 bump version number 2022-08-25 13:04:06 -06:00
UpstreamData
f8f777b5b5 fix tag data to be escaped properly 2022-08-25 13:03:46 -06:00
UpstreamData
b15e0a7363 bump version number 2022-08-25 12:50:55 -06:00
UpstreamData
5c1d06f743 attempt to fix a bug with influx db miner data 2022-08-25 12:50:30 -06:00
UpstreamData
51de56feb3 bump version number 2022-08-25 12:43:05 -06:00
UpstreamData
256a4ac909 fix boolean bug in miner data 2022-08-25 12:39:57 -06:00
UpstreamData
09800c8ad2 bump version number 2022-08-24 15:18:04 -06:00
UpstreamData
83a7d8c60f add MinerData().as_json() 2022-08-24 15:17:36 -06:00
UpstreamData
ee2698be50 update poetry.lock 2022-08-24 13:56:05 -06:00
10 changed files with 58 additions and 16 deletions

View File

@@ -37,6 +37,7 @@ Supported miner types are here on this list. If your miner (or miner version) i
* [M30S++][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlus]: * [M30S++][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlus]:
* [VG30][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG30] * [VG30][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG30]
* [VG40][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG40] * [VG40][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG40]
* [VH60][pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH60]
* [M31S][pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31S] * [M31S][pyasic.miners.whatsminer.btminer.M3X.M31S.BTMinerM31S]
* [M31S+][pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlus]: * [M31S+][pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlus]:
* [VE20][pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE20] * [VE20][pyasic.miners.whatsminer.btminer.M3X.M31S_Plus.BTMinerM31SPlusVE20]

View File

@@ -89,7 +89,7 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## M30S+VG40 ## M30S++VG40
::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG40 ::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVG40
handler: python handler: python
@@ -97,6 +97,14 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## M30S++VH60
::: pyasic.miners.whatsminer.btminer.M3X.M30S_Plus_Plus.BTMinerM30SPlusPlusVH60
handler: python
options:
show_root_heading: false
heading_level: 4
## M31S ## M31S
@@ -130,7 +138,7 @@
show_root_heading: false show_root_heading: false
heading_level: 4 heading_level: 4
## M32 ## M32V20
::: pyasic.miners.whatsminer.btminer.M3X.M32.BTMinerM32V20 ::: pyasic.miners.whatsminer.btminer.M3X.M32.BTMinerM32V20
handler: python handler: python

6
poetry.lock generated
View File

@@ -17,7 +17,7 @@ trio = ["trio (>=0.16)"]
[[package]] [[package]]
name = "asyncssh" name = "asyncssh"
version = "2.11.0" version = "2.12.0"
description = "AsyncSSH: Asynchronous SSHv2 client and server library" description = "AsyncSSH: Asynchronous SSHv2 client and server library"
category = "main" category = "main"
optional = false optional = false
@@ -218,8 +218,8 @@ anyio = [
{file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"}, {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"},
] ]
asyncssh = [ asyncssh = [
{file = "asyncssh-2.11.0-py3-none-any.whl", hash = "sha256:7302348cbd54c58d3259da17f13e77912de1b005e366b15c8b183d948c8a91a8"}, {file = "asyncssh-2.12.0-py3-none-any.whl", hash = "sha256:6841c4242c606fd51188c974ec2f4887efeec67ecdfa5b84140711dacd985ab3"},
{file = "asyncssh-2.11.0.tar.gz", hash = "sha256:59c36ce77ba9dda8dd57ad875776e7105ddb1fa851bc039bb3aeadeac4f67b56"}, {file = "asyncssh-2.12.0.tar.gz", hash = "sha256:274101322c4b941823aeed8e1ab6e7be5191686c6db2d2bd35afeba30505e780"},
] ]
certifi = [ certifi = [
{file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},

View File

@@ -16,6 +16,7 @@ from typing import Union, List
from dataclasses import dataclass, field, asdict from dataclasses import dataclass, field, asdict
from datetime import datetime, timezone from datetime import datetime, timezone
import time import time
import json
from .error_codes import X19Error, WhatsminerError, BraiinsOSError from .error_codes import X19Error, WhatsminerError, BraiinsOSError
@@ -70,11 +71,11 @@ class MinerData:
model: str = "Unknown" model: str = "Unknown"
hostname: str = "Unknown" hostname: str = "Unknown"
hashrate: float = 0 hashrate: float = 0
left_board_hashrate: float = 0 left_board_hashrate: float = 0.0
center_board_hashrate: float = 0 center_board_hashrate: float = 0.0
right_board_hashrate: float = 0 right_board_hashrate: float = 0.0
temperature_avg: int = field(init=False) temperature_avg: int = field(init=False)
env_temp: float = 0 env_temp: float = 0.0
left_board_temp: int = 0 left_board_temp: int = 0
left_board_chip_temp: int = 0 left_board_chip_temp: int = 0
center_board_temp: int = 0 center_board_temp: int = 0
@@ -118,7 +119,7 @@ class MinerData:
return setattr(self, key, value) return setattr(self, key, value)
def __iter__(self): def __iter__(self):
return iter([item for item in self.__dict__]) return iter([item for item in self.asdict()])
@property @property
def total_chips(self): # noqa - Skip PyCharm inspection def total_chips(self): # noqa - Skip PyCharm inspection
@@ -177,6 +178,11 @@ class MinerData:
def asdict(self): def asdict(self):
return asdict(self) return asdict(self)
def as_json(self):
data = self.asdict()
data["datetime"] = str(int(time.mktime(data["datetime"].timetuple())))
return json.dumps(data)
def as_influxdb(self, measurement_name: str = "miner_data"): def as_influxdb(self, measurement_name: str = "miner_data"):
tag_data = [measurement_name] tag_data = [measurement_name]
field_data = [] field_data = []
@@ -184,7 +190,8 @@ class MinerData:
tags = ["ip", "mac", "model", "hostname"] tags = ["ip", "mac", "model", "hostname"]
for attribute in self: for attribute in self:
if attribute in tags: if attribute in tags:
tag_data.append(f"{attribute}={self[attribute]}") escaped_data = self[attribute].replace(" ", "\\ ")
tag_data.append(f"{attribute}={escaped_data}")
continue continue
if isinstance(self[attribute], str): if isinstance(self[attribute], str):
field_data.append(f'{attribute}="{self[attribute]}"') field_data.append(f'{attribute}="{self[attribute]}"')
@@ -193,7 +200,7 @@ class MinerData:
field_data.append(f"{attribute}={str(self[attribute]).lower()}") field_data.append(f"{attribute}={str(self[attribute]).lower()}")
continue continue
if isinstance(self[attribute], int): if isinstance(self[attribute], int):
field_data.append(f"{attribute}={self[attribute]}i") field_data.append(f"{attribute}={self[attribute]}")
continue continue
if isinstance(self[attribute], float): if isinstance(self[attribute], float):
field_data.append(f"{attribute}={self[attribute]}") field_data.append(f"{attribute}={self[attribute]}")
@@ -201,6 +208,9 @@ class MinerData:
if attribute == "fault_light" and not self[attribute]: if attribute == "fault_light" and not self[attribute]:
field_data.append(f"{attribute}=false") field_data.append(f"{attribute}=false")
continue continue
if attribute == "errors":
for idx, item in enumerate(self[attribute]):
field_data.append(f'error_{idx+1}="{item.error_message}"')
tags_str = ",".join(tag_data) tags_str = ",".join(tag_data)
field_str = ",".join(field_data) field_str = ",".join(field_data)

View File

@@ -152,6 +152,7 @@ ERROR_CODES = {
2020: "Pool 0 connection failed.", 2020: "Pool 0 connection failed.",
2021: "Pool 1 connection failed.", 2021: "Pool 1 connection failed.",
2022: "Pool 2 connection failed.", 2022: "Pool 2 connection failed.",
2023: "Pool 3 connection failed.",
2030: "High rejection rate on pool.", 2030: "High rejection rate on pool.",
2040: "The pool does not support asicboost mode.", 2040: "The pool does not support asicboost mode.",
2310: "Hashrate is too low.", 2310: "Hashrate is too low.",

View File

@@ -28,7 +28,7 @@ class M30SPlusPlusVG30(BaseMiner):
def __init__(self, ip: str): def __init__(self, ip: str):
super().__init__() super().__init__()
self.ip = ip self.ip = ip
self.model = "M30S++ V30" self.model = "M30S++ VG30"
self.nominal_chips = 111 self.nominal_chips = 111
self.fan_count = 2 self.fan_count = 2
@@ -37,6 +37,15 @@ class M30SPlusPlusVG40(BaseMiner):
def __init__(self, ip: str): def __init__(self, ip: str):
super().__init__() super().__init__()
self.ip = ip self.ip = ip
self.model = "M30S++ V40" self.model = "M30S++ VG40"
self.nominal_chips = 117 self.nominal_chips = 117
self.fan_count = 2 self.fan_count = 2
class M30SPlusPlusVH60(BaseMiner):
def __init__(self, ip: str):
super().__init__()
self.ip = ip
self.model = "M30S++ VH60"
self.nominal_chips = 78
self.fan_count = 2

View File

@@ -14,7 +14,12 @@
from .M30S import M30S, M30SVE10, M30SVE20, M30SVG20, M30SV50 from .M30S import M30S, M30SVE10, M30SVE20, M30SVG20, M30SV50
from .M30S_Plus import M30SPlus, M30SPlusVG60, M30SPlusVE40, M30SPlusVF20 from .M30S_Plus import M30SPlus, M30SPlusVG60, M30SPlusVE40, M30SPlusVF20
from .M30S_Plus_Plus import M30SPlusPlus, M30SPlusPlusVG30, M30SPlusPlusVG40 from .M30S_Plus_Plus import (
M30SPlusPlus,
M30SPlusPlusVG30,
M30SPlusPlusVG40,
M30SPlusPlusVH60,
)
from .M31S import M31S from .M31S import M31S
from .M31S_Plus import M31SPlus, M31SPlusVE20 from .M31S_Plus import M31SPlus, M31SPlusVE20

View File

@@ -17,6 +17,7 @@ from pyasic.miners._types import ( # noqa - Ignore access to _module
M30SPlusPlus, M30SPlusPlus,
M30SPlusPlusVG40, M30SPlusPlusVG40,
M30SPlusPlusVG30, M30SPlusPlusVG30,
M30SPlusPlusVH60,
) )
@@ -36,3 +37,9 @@ class BTMinerM30SPlusPlusVG40(BTMiner, M30SPlusPlusVG40):
def __init__(self, ip: str) -> None: def __init__(self, ip: str) -> None:
super().__init__(ip) super().__init__(ip)
self.ip = ip self.ip = ip
class BTMinerM30SPlusPlusVH60(BTMiner, M30SPlusPlusVH60):
def __init__(self, ip: str) -> None:
super().__init__(ip)
self.ip = ip

View File

@@ -29,6 +29,7 @@ from .M30S_Plus_Plus import (
BTMinerM30SPlusPlus, BTMinerM30SPlusPlus,
BTMinerM30SPlusPlusVG40, BTMinerM30SPlusPlusVG40,
BTMinerM30SPlusPlusVG30, BTMinerM30SPlusPlusVG30,
BTMinerM30SPlusPlusVH60,
) )
from .M31S import BTMinerM31S from .M31S import BTMinerM31S

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "pyasic" name = "pyasic"
version = "0.16.2" version = "0.16.10"
description = "A set of modules for interfacing with many common types of ASIC bitcoin miners, using both their API and SSH." description = "A set of modules for interfacing with many common types of ASIC bitcoin miners, using both their API and SSH."
authors = ["UpstreamData <brett@upstreamdata.ca>"] authors = ["UpstreamData <brett@upstreamdata.ca>"]
repository = "https://github.com/UpstreamData/pyasic" repository = "https://github.com/UpstreamData/pyasic"