Metadata-Version: 2.4
Name: pyasic-umhost
Version: 0.3.0.dev3
Summary: Fork of pyasic — a simplified and standardized interface for Bitcoin ASICs.
License: Apache 2.0
License-File: LICENSE.txt
Keywords: python,asic,bitcoin,whatsminer,antminer,braiins-os,vnish,luxos
Author: UpstreamData
Author-email: brett@upstreamdata.ca
Requires-Python: >3.10, <4.0
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Dist: aiofiles (>=23.2.1)
Requires-Dist: asyncssh (>=2.20.0)
Requires-Dist: betterproto (==2.0.0b7)
Requires-Dist: cryptography (>=39.0)
Requires-Dist: httpx (>=0.26.0)
Requires-Dist: passlib (>=1.7.4)
Requires-Dist: playwright (>=1.40)
Requires-Dist: pyaml (>=23.12.0)
Requires-Dist: pydantic (>=2.11.0)
Requires-Dist: semver (>=3.0.4,<4.0.0)
Requires-Dist: tomli (>=2.2.1,<3.0.0) ; python_version < "3.11"
Requires-Dist: tomli-w (>=1.0.0)
Description-Content-Type: text/markdown

# pyasic-umhost

*Упрощённый и стандартизированный интерфейс для управления Bitcoin ASIC-майнерами.*

Форк [pyasic](https://github.com/UpstreamData/pyasic) — асинхронная Python-библиотека для обнаружения, опроса и управления ASIC-майнерами (Antminer, Whatsminer, Avalon, Braiins OS, VNish, LuxOS, Goldshell, Auradine, Innosilicon, ePIC, Hiveon, BitAxe, Iceriver, Volcminer и др.).

Форк добавляет:
- **`app.py`** — Streamlit-интерфейс поверх библиотеки.
- **`inspector/`** — инструмент для сбора полного отчёта по майнеру.

Python `>3.10, <4.0`. Лицензия Apache-2.0.

---

## Установка

Дистрибутив называется `pyasic-umhost`, но импортируется как `pyasic`:

```bash
pip install pyasic-umhost
```

```python
import pyasic
```

### Установка для разработки

```bash
poetry install --with dev      # добавьте ,docs для зависимостей mkdocs
pre-commit install
```

### Запуск Streamlit-интерфейса

Streamlit **не** объявлен в зависимостях `pyproject.toml` — установите его отдельно:

```bash
pip install streamlit
streamlit run app.py
```

---

## Быстрый старт

### Поиск майнеров в сети

`MinerNetwork` сканирует подсеть и возвращает список найденных майнеров с уже определённым типом.

```python
import asyncio
from pyasic.network import MinerNetwork


async def scan_miners():
    # любой IP трактуется как подсеть /24 (255 адресов)
    network = MinerNetwork.from_subnet("192.168.1.50/24")  # сеть 192.168.1.0-255
    miners = await network.scan()
    print(miners)


if __name__ == "__main__":
    asyncio.run(scan_miners())
```

### Подключение по известному IP

Если IP уже известен, используйте `get_miner()` — он определит модель майнера или вернёт `UnknownMiner`.

```python
import asyncio
from pyasic import get_miner


async def get_miners():
    # быстрее опрашивать несколько майнеров параллельно через asyncio.gather
    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_data()` возвращает экземпляр `MinerData` со всеми данными, которые удалось собрать. Любое поле доступно как атрибут, например `MinerData().hashrate`.

```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:
        data = await miner.get_data()
        print(data)            # весь датакласс
        print(data.hashrate)   # хешрейт в TH/s


if __name__ == "__main__":
    asyncio.run(gather_miner_data())
```

Для нескольких майнеров запускайте `get_data()` параллельно:

```python
all_data = await asyncio.gather(*[m.get_data() for m in miners])
```

Экземпляры `MinerData` можно складывать и делить на число — удобно для усреднённых данных по парку:

```python
from pyasic import MinerData

data = [MinerData("192.168.1.1"), MinerData("192.168.1.2")]
average = sum(data, start=MinerData("0.0.0.0")) / len(data)
```

---

## Управление майнером

Каждый класс майнера реализует единый набор управляющих методов из `BaseMiner`:
`check_light`, `fault_light_on`, `fault_light_off`, `get_config`, `get_data`, `get_errors`,
`get_hostname`, `get_model`, `reboot`, `restart_backend`, `stop_mining`, `resume_mining`,
`is_mining`, `send_config`, `set_power_limit`.

```python
import asyncio
from pyasic import get_miner


async def control():
    miner = await get_miner("192.168.1.20")

    # включить сигнальный диод
    await miner.fault_light_on()

    # прочитать и записать конфиг
    cfg = await miner.get_config()
    await miner.send_config(cfg)


if __name__ == "__main__":
    asyncio.run(control())
```

`MinerConfig` — это унифицированное представление конфигурации майнера (возврат `get_config()`).
`send_config()` сам конвертирует его в нужный для конкретного майнера формат.

---

## Настройки

Глобальные настройки (`pyasic.settings`) упрощают работу с большими парками — например, общий пароль по умолчанию:

```python
from pyasic import settings

settings.update("default_antminer_web_password", "my_pwd")
```

Значения по умолчанию:

```
"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",

# РАСШИРЕННЫЕ — меняйте только если понимаете, что делаете
"socket_linger_time": 1000,
```

---

## Тесты

Тесты на стандартном `unittest` (не pytest):

```bash
python -m unittest discover -p '*test.py'    # весь набор
ruff check --fix && ruff format              # линт и форматирование
mypy                                         # проверка типов
```

---

## Сборка и публикация на PyPI

Сборка и публикация идут через Poetry. Бэкенд сборки — `poetry-core`.

### 1. Поднять версию

PyPI **не даёт перезалить уже существующую версию**, поэтому перед каждым релизом меняйте `version`
в `[project]` файла `pyproject.toml` (например `0.3.0.dev2` → `0.3.0.dev3` или `0.3.0`).

> Версии вида `0.3.0.devN` — это пре-релизы: `pip install pyasic-umhost` их по умолчанию **не ставит**,
> нужен `pip install --pre pyasic-umhost`. Для обычного релиза используйте чистую версию без `.devN`.

### 2. Настроить токен (один раз)

Получите API-токен на https://pypi.org/manage/account/token/ и сохраните его:

```bash
poetry config pypi-token.pypi pypi-AgEIcHl...ваш_токен
```

### 3. Собрать и опубликовать

```bash
rm -rf dist/        # на всякий случай чистим старые сборки
poetry build        # создаст dist/*.whl и dist/*.tar.gz
poetry publish      # зальёт на PyPI
```

Или одной командой:

```bash
poetry publish --build
```

### Проверка на TestPyPI (необязательно)

Чтобы прогнать релиз без риска для боевого PyPI:

```bash
poetry config repositories.testpypi https://test.pypi.org/legacy/
poetry config pypi-token.testpypi pypi-<test-токен>
poetry publish --build -r testpypi

pip install --pre -i https://test.pypi.org/simple/ pyasic-umhost
```

> **Если `poetry` падает с `Library not loaded: .../Python.framework/...`** — это значит, что Homebrew
> обновил Python и venv самого Poetry сломался. Переустановите Poetry:
> ```bash
> rm -rf "$HOME/Library/Application Support/pypoetry"
> curl -sSL https://install.python-poetry.org | python3 -
> ```

