Schnitzel / hass-miner

Controll your Bitcoin miner from Home Assistant
MIT License
47 stars 16 forks source link

[Feature Request] Add restart_backend from pyasic as ha service #361

Open pixeldoc2000 opened 1 week ago

pixeldoc2000 commented 1 week ago

I use hass-miner mainly to control my Miner with Braiins Firmware (BOS) to make use of my excess Solar Energy, which works great so far. Thanks for the great ha integration.

My Problem is as follows: I monitor the hashrate and pause and resume the miner if the hashrate drops below e certain level.

Sometime pause and resume does not restart the mining process, when the pool is "dead" according to BOS: grafik

To fix this situation, a restart of bosminer is required, but that is currently not possible via hass-miner. It would be nice to make restart_backend() from pyasic available as a ha service for example, to fix this problem (https://docs.pyasic.org/en/latest/miners/functions/#pyasic.miners.base.MinerProtocol.restart_backend).

Additionally, having the pool status available in HA would be awesome, but also cumbersome?

b-rowan commented 1 week ago

I like the restart backend idea, I'm not 100% sure how that would work regarding home assistants UI, but I assume it would be pretty simple.

Regarding the pool status, there is currently a Summer of Bitcoin project going on that is adding pool metrics to pyasic, so once that is done it will be a lot easier to show the active pool. This is a bit more complicated because there can be multiple active pools (in the case of quota splitting between groups), but I think it could be displayed as Active Pool(s): 1, 4

pixeldoc2000 commented 1 week ago

I'm not 100% sure how that would work regarding home assistants UI, but I assume it would be pretty simple.

My suggesten would be a service like miner.restart_backend , because AFAIK HA UI still has no native momentary button.

The service could than be called by automation or script (button).

b-rowan commented 1 week ago

This is essentially what I'm attempting, but sadly the dev docs for Hass are terrible. I think I have something close to working, but it will have to take in an IP address, rather than allowing you to select a device.

b-rowan commented 1 week ago

Done! Try out v1.1.10.

pixeldoc2000 commented 1 week ago

Awesome, thx a lot! That was fast.

I will test it today and report here.

readme.md should to updated to include the new service calls.

b-rowan commented 1 week ago

Will do. Gonna leave this open for the pools request.

pixeldoc2000 commented 1 week ago

Hm, sadly it does not work as expected:

I did not find a way to capture the commands send via ssh from HA / pyasic. All I can see is the incoming ssh connection with tcpdump on the miner from HA.

Tested with Braiins OS+ Version: 2022-09-27-0-26ba61b9-22.08.1-plus on Antminer S9 (Firmware is pretty old, but the current version for S9).

b-rowan commented 1 week ago

That's really weird, I was able to get it working with my own S9, same firmware version and everything. Is it possible the SSH connection is failing? Did you change the SSH password or something? Usually it should login with root no password...

pixeldoc2000 commented 1 week ago

Yes, changed the root password (of cause).

So i guess ssh session is done with default password "root"?

https://github.com/UpstreamData/pyasic/blob/master/pyasic/ssh/braiins_os.py self.pwd = settings.get("default_bosminer_ssh_password", "root")

b-rowan commented 1 week ago

Try removing and re-adding the miner. It should prompt you for an SSH user and password, try changing it there...

pixeldoc2000 commented 1 week ago

Readded the miner, entered my custom ssh password in HA config flow. SSH connection still did not work.

# tail -f /var/log/syslog
Fri Jun 21 23:07:22 2024 authpriv.warn dropbear[3704]: Bad password attempt for 'root' from 192.168.0.5:56266
Fri Jun 21 23:07:22 2024 authpriv.info dropbear[3704]: Exit before auth from <192.168.0.5:56266>: (user 'root', 1 fails): Exited normally

Changed root to default password "root". Now it works.

Looks like the ssh password from the config flow is not used, instead pyasic probably falls back to the default password "root"?

b-rowan commented 1 week ago

Interesting. That will almost certainly be an issue with pyasic, lemme do some testing.

pixeldoc2000 commented 6 days ago

Yes, seems to be a bug in current pyasic. I have tested it with pyasic 0.57.6 again Braiins OS with non default password.

grafik

With default password it works.

pixeldoc2000 commented 6 days ago

BTW, you forgot to update custom_components/miner/manifest.json for 1.1.10 release.

b-rowan commented 6 days ago

Interestingly, the error you sent is not SSH related, it's web related. If you comment out the web password setting, does that work? It's possible the LUCI endpoints just use the default info, since technically they were removed a few versions before latest for the S9, but there is a special case where they return data manually.

pixeldoc2000 commented 6 days ago

You are right, I forgot.

bosminer_restart is done via ssh. Data is gathered via LUCI API.

Interestingly, the error you sent is not SSH related, it's web related. If you comment out the web password setting, does that work? It's possible the LUCI endpoints just use the default info, since technically they were removed a few versions before latest for the S9, but there is a special case where they return data manually.

I have only tested to get data via LUCI API, not ssh.

If the default password root is set on the miner firmware and settings.update("default_bosminer_web_password", "changeme") is commented out, LUCI API query works. If I change the password of user root on the miner to changeme, LUCI query fails with APIError.

pyasic query

import asyncio
from pyasic import get_miner
from pyasic import settings

#settings.update("default_bosminer_web_password", "changeme")

async def gather_miner_data():
    miner = await get_miner("192.168.0.203")
    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())

API Result

MinerData(ip='192.168.0.203', datetime='2024-06-26T22:10:10.404915+02:00', timestamp=1719432610, device_info=DeviceInfo(make=<MinerMake.ANTMINER: 'AntMiner'>, model=<AntminerModels.S9: 'S9'>, firmware=<MinerFirmware.BRAIINS_OS: 'BOS+'>, algo=SHA256Algo), make='AntMiner', model='S9', firmware='BOS+', algo='SHA256', mac='0A:3C:F7:19:xx:xx', api_ver='3.7', fw_ver='22.08.1', 
hostname='xxx', hashrate=7.438256345663261 TH/s, expected_hashrate=7.5 TH/s, expected_hashboards=3, expected_chips=189, expected_fans=2, percent_expected_chips=100, percent_expected_hashrate=99, percent_expected_wattage=100, temperature_avg=66, env_temp=None, wattage=750, wattage_limit=750, voltage=None, fans=[Fan(speed=1560), Fan(speed=1560)], fan_psu=None, hashboards=[HashBoard(slot=0, hashrate=2.474525137239756 TH/s, temp=68, chip_temp=80, chips=63, expected_chips=63, serial_number=None, missing=False), HashBoard(slot=1, hashrate=2.4721376180722814 TH/s, temp=66, chip_temp=78, chips=63, expected_chips=63, serial_number=None, missing=False), HashBoard(slot=2, hashrate=2.4915935903512243 TH/s, temp=65, chip_temp=76, chips=63, expected_chips=63, serial_number=None, missing=False)], total_chips=189, nominal=True, config=MinerConfig(pools=PoolConfig(groups=[PoolGroup(pools=[Pool(url='stratum2+tcp://v2.eu.stratum.braiins.com/xxx', user='xxx', password='anything123'), Pool(url='stratum+tcp://stratum.slushpool.com:3333', user='xxx', password='anything123')], quota=1, name='Braiins Pool'), PoolGroup(pools=[Pool(url='stratum+tcp://sha256-eu.unmineable.com:13333', user='BTC:bc1qxxx', password='x'), Pool(url='stratum+tcp://sha256-eu.unmineable.com:3333', user='BTC:bc1qxxxx', password='x')], quota=3, name='unmineable 
BTC'), PoolGroup(pools=[Pool(url='stratum+tcp://sha256-eu.unmineable.com:13333', user='LTC:ltc1qxxx', password='x'), Pool(url='stratum+tcp://sha256-eu.unmineable.com:13333', user='LTC:ltc1qxxx', password='x')], quota=1, name='unmineable LTC')]), fan_mode=FanModeNormal(mode='normal', minimum_fans=1, minimum_speed=0), temperature=TemperatureConfig(target=80.0, hot=90.0, danger=100.0), mining_mode=None, power_scaling=PowerScalingDisabled(mode='disabled')), fault_light=False, errors=[], is_mining=True, uptime=1151, efficiency=101, pools=[])
7.438256345663261 TH/s
pixeldoc2000 commented 6 days ago

I am not able to create a quick test for restart_backend(), as I am not very deep into python.

import asyncio
from pyasic import get_miner
from pyasic import settings

#settings.update("default_bosminer_ssh_password", "changeme")

async def do_restart_backend():
    miner = await get_miner("192.168.0.203")

    # call control function
    result = await miner.restart_backend()

if __name__ == "__main__":
    asyncio.run(do_restart_backend())

Error

Traceback (most recent call last):
  File "z:\xxx\braiinsos\pyasic-test-03.py", line 13, in <module>
    asyncio.run(do_restart_backend())
  File "C:\Users\xxx\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "C:\Users\xxx\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\xxx\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 654, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "z:\xxx\braiinsos\pyasic-test-03.py", line 10, in do_restart_backend
    result = await miner.restart_backend()

Can you help me?

b-rowan commented 6 days ago

I see nothing wrong with that? I think I understand what the issue is though. First thing I should do is fix the LUCI password issues, I wasn't aware they did that...