Closed gav1111 closed 1 year ago
Global command for lights is faultlight{on/off}, see the docs here.
Handling LPM is a bit tougher. There are machines that use LPM, some machines that have Autotuning and fine grained control, and some other machines that allow frequency and voltage control. You best bet is to call miner.get_config
, and then set config.autotuning_wattage
and config.miner_mode
. The docs don't show miner_mode, I will have to update that, but if you click the view source code here you must set it to a variant of the enum X19PowerMode. See docs here..
The opposite of the above goes for resetting it.
I think I'm going to mark this as completed, but for reference -
Fault light commands exist as fault_light_on
and fault_light_off
Setting LPM/NPM with a method is not planned, because I feel that should be delegated to the user where it is much less opaque what the function is actually doing. I feel it is more counterintuitive to have a set_LPM
command on miners which support autotuning, since it would cause a side effect (downclocking) that isn't expected when a miner doesn't have LPM.
LPM/NPM can also easily be accomplished with MinerConfig
and the get_config
method, then setting autotuning_wattage
and miner_mode
, which makes it very clear to the user what they are doing and allows proper customization.
flashing works great thanks, setting low power still figuring that out
Can I have a little assistance in helping to script how to set low power mode on S19 antminers with new firmware which has low power mode. I am trying the following to get the get_config per what you say above, but getting get_config isnt defined:
import asyncio
from pyasic import get_miner
from pyasic import MinerConfig
async def get_api_commands(miner_ip: str):
# Get the miner
miner = await get_miner(miner_ip)
# List all available commands
# Can also be called explicitly with the function miner.api.get_commands()
print(miner.api.commands)
if __name__ == "__main__":
asyncio.run(get_config("172.16.1.86"))
The get_config()
method is called on a miner object. Call miner = await get_miner(IP)
first, then call cfg = await miner.get_config()
Yep thank you, I figured that one out now and I see that it can be either 'miner_mode=<X19PowerMode.Normal: 0>' or 'miner_mode=<X19PowerMode.LPM: 3>' Then how do I issue it send_config to switch from normal to lpm?
from pyasic.config import X19PowerMode
import pyasic
async def set_lpm(ip: str):
miner = await pyasic.get_miner(ip)
cfg = await miner.get_config()
cfg.miner_mode = X19PowerMode.LPM
await miner.send_config(cfg)
async def set_normal(ip: str):
miner = await pyasic.get_miner(ip)
cfg = await miner.get_config()
cfg.miner_mode = X19PowerMode.Normal
await miner.send_config(cfg)
I think its working, I had to add await miner.reboot() after the send_config otherwise it was just hanging, and then it goes through the following which I dont think I ve seen before, and after a few minutes back up and running
2023-06-29 22:49:19 enable_power_calibration,calibration date:211208.
2023-06-29 22:49:20 power type version: 0x0075
2023-06-29 22:49:21 disable power watchdog: 0x0000
2023-06-29 22:49:22 Initializing the power, please wait, this may take up to 2 minutes...
2023-06-29 22:52:23 Slept 180 seconds, diff = 4.
2023-06-29 22:52:27 set_voltage_by_steps to 1500.
2023-06-29 22:52:37 start up min temp by 75a = 38
I am using the following python to set a compatible miner into low power mode
import sys
import asyncio
from pyasic.config import X19PowerMode
import pyasic
IP = sys.argv[1]
async def set_lpm(ip: str):
miner = await pyasic.get_miner(ip)
cfg = await miner.get_config()
cfg.miner_mode = X19PowerMode.LPM
await miner.send_config(cfg)
await miner.reboot()
if __name__ == "__main__":
asyncio.run(set_lpm(IP))
yesterday it was working for S19 Pro, but I am not sure for S19j Pro, today on 3 occasions it didnt set 3 S19j Pro into low power mode, and I had to do it manually. How should I try to debug it?
S19j Pro reports the setting in the same way, just refuses to set it
miner_mode=<X19PowerMode.LPM: 3>
Does it let you set it via the web interface? Some miners don't support sleep mode for whatever reason.
Yes I had to do it via gui. It went into low power mode by choosing it via gui. So it’s not sleep mode I’m working on right now but the new low power that ant miner introduced dec 2022. Should I try setting it into sleep mode via script to see if it will react to that?
On Sat, Jul 1, 2023 at 01:22, UpstreamData @.***> wrote:
Does it let you set it via the web interface? Some miners don't support sleep mode for whatever reason.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you modified the open/close state.Message ID: @.***>
I am setting power back to normal now via script. S19 pro set via script, s19j pro didn’t and I had to go into gui to do it manually
On Sat, Jul 1, 2023 at 01:22, UpstreamData @.***> wrote:
Does it let you set it via the web interface? Some miners don't support sleep mode for whatever reason.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you modified the open/close state.Message ID: @.***>
I managed to get the following error, maybe will be of help to understand:
Command failed: python3 /home/nodered/py/lpm.py 192.168.0.7
Traceback (most recent call last):
File "/home/nodered/py/lpm.py", line 16, in <module>
asyncio.run(set_lpm(IP))
File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
return future.result()
File "/home/nodered/py/lpm.py", line 10, in set_lpm
cfg = await miner.get_config()
AttributeError: 'NoneType' object has no attribute 'get_config'
and here is the code
~/pyasic$ cat lpm.py
import sys
import asyncio
from pyasic.config import X19PowerMode
import pyasic
IP = sys.argv[1]
async def set_lpm(ip: str):
miner = await pyasic.get_miner(ip)
cfg = await miner.get_config()
cfg.miner_mode = X19PowerMode.LPM
await miner.send_config(cfg)
await miner.reboot()
if __name__ == "__main__":
asyncio.run(set_lpm(IP))
so is it not responding to pyasic.get_miner()?
Maybe in that case it didnt, but it prints cfg without any issues, config just doesnt "stick":
:~/temp/pyasic$ python3 find_powermode.py 192.168.0.7
MinerConfig(pool_groups=[_PoolGroup(quota=1, group_name='QYR225', pools=[_Pool(url='.com:3333', username='sa.1', password=''), _Pool(url='', username='', password=''), _Pool(url='', username='', password='')])], temp_mode='auto', temp_target=70.0, temp_hot=80.0, temp_dangerous=100.0, minimum_fans=None, fan_speed=None, asicboost=None, miner_mode=<X19PowerMode.Normal: 0>, autotuning_enabled=True, autotuning_mode=None, autotuning_wattage=None, autotuning_hashrate=None, dps_enabled=None, dps_power_step=None, dps_min_power=None, dps_shutdown_enabled=None, dps_shutdown_duration=None)
so is it not responding to pyasic.get_miner()?
It appears it's not responding, yeah. Your first script isn't getting the config at all (you can show this by printing the config right after you try to get it, it won't even make it there), but your second script is working fine.
I wonder if it could somehow be related to environments or something, if one of the scripts is running as root and the other as your user and they are on different versions of pyasic? Try sudo pip install -U pyasic
and pip install -U pyasic
and see if it changes anything?
I think the one I got an error for was a one off. I run the python script from node-red. If I run the script for an S19 Pro, it works, if I run it for S19j Pro it doesnt work (no error, just executes with code=0, but no effect on the miner)
It's possible they have different values for LPM across miners? Can you send the result of await miner.web.get_miner_conf()
before and after manually setting LPM via the web interface on the miner that isn't working?
here is low power mode on S19j Pro:
{'pools': [{'url': ':3333', 'user': 'sa', 'pass': ''}, {'url': '', 'user': '', 'pass': ''}, {'url': '', 'user': '', 'pass': ''}], 'api-listen': True, 'api-network': True, 'api-groups': 'A:stats:pools:devs:summary:version', 'api-allow': 'A:0/0,W:*', 'bitmain-fan-ctrl': False, 'bitmain-fan-pwm': '100', 'bitmain-use-vil': True, 'bitmain-freq': '400', 'bitmain-voltage': '1360', 'bitmain-ccdelay': '0', 'bitmain-pwth': '1', 'bitmain-work-mode': '3', 'bitmain-freq-level': '100'}
and normal power mode on S19j Pro is:
{'pools': [{'url': '333', 'user': 'sa', 'pass': ''}, {'url': '', 'user': '', 'pass': ''}, {'url': '', 'user': '', 'pass': ''}], 'api-listen': True, 'api-network': True, 'api-groups': 'A:stats:pools:devs:summary:version', 'api-allow': 'A:0/0,W:*', 'bitmain-fan-ctrl': False, 'bitmain-fan-pwm': '100', 'bitmain-use-vil': True, 'bitmain-freq': '400', 'bitmain-voltage': '1360', 'bitmain-ccdelay': '0', 'bitmain-pwth': '1', 'bitmain-work-mode': '0', 'bitmain-freq-level': '100'}
ccdelay and pwth are new to me, maybe I have to add them when submitting... I'll see what I can figure out, but it's seeming like they might have changed something.
S19 Pro also has those, but the script works on them
{'pools': [{'url': '..:', 'user': '.', 'pass': '123'}, {'url': '..:', 'user': '', 'pass': '123'}, {'url': '..:', 'user': '.', 'pass': '123'}], 'api-listen': True, 'api-network': True, 'api-groups': 'A:stats:pools:devs:summary:version', 'api-allow': 'A:0/0,W:*', 'bitmain-fan-ctrl': False, 'bitmain-fan-pwm': '100', 'bitmain-use-vil': True, 'bitmain-freq': '400', 'bitmain-voltage': '1420', 'bitmain-ccdelay': '0', 'bitmain-pwth': '1', 'bitmain-work-mode': '0', 'bitmain-freq-level': '100'}
Can you try updating the config and tracking the network request it sends to set_miner_conf.cgi
via the web interface? Settings page, CTRL+SHIFT+I, Dev tools "Network" tab, should be recording, if not hit record top left, then hit the submit button. It should output the request it sends to that page, I'm looking for the payload data. Trying to figure out if something changed in some new version of firmware or something.
{ "bitmain-fan-ctrl": false, "bitmain-fan-pwm": "100", "miner-mode": 3, "freq-level": "100", "pools": [ { "url": "xxx", "user": "xx.xxx", "pass": "" }, { "url": "", "user": "", "pass": "" }, { "url": "", "user": "", "pass": "" } ] }
is this what you wanted to see, or do I need to do something else?
Yep, that's perfect. Sorry, been away for the past few days so responding when I can. I have to do some testing now, it looks the same but it might be an issue with setting bitmain-freq. We shall see.
and this is the payload for setting low power mode for S19 Pro
{
"bitmain-fan-ctrl": false,
"bitmain-fan-pwm": "100",
"miner-mode": 3,
"freq-level": "100",
"pools": [
{
"url": "",
"user": "",
"pass": ""
},
{
"url": "",
"user": "",
"pass": ""
},
{
"url": "",
"user": "",
"pass": "123"
}
]
}
arent they the same? So we havent figured it?
Yeah same thing. My guess is that some miners respond differently to setting frequency mode. I'll test later.
Can you test with v0.36.12? Seems like it may have been an issue with some versions not liking a string formatted miner mode value.
I upgraded to 0.37 and I am getting some general errors, what I can see right away is that hashrate isnt reported correctly
make="AntMiner",hashrate=30.24
should be 100
however, with 0.37 it appears that I was able to set low power mode for an s19j pro, will report if it still works on others
Good catch on the hashrate, I'll get that fixed here shortly.
Fixed the addition issue in 0.37.1
upgraded to 0.37.1, hashrate works. Setting S19j Pro into low power doesnt work. Setting S19 Pro into low power still works. I dont know why script worked on 0.37 for one particular S19j Pro, I tried 0.37 on another S19j Pro and it didnt work
What firmware version are they on? Can you get them all on the same firmware version (preferably the latest version) and test? I think what happened is they changed the value sent to power mode from a string to an integer, or vice versa, and so it has to either be quoted or unquoted depending on the version of the firmware.
It doesn’t set it to low power but it does something because it goes through power recalibration
On Fri, Jul 7, 2023 at 21:10, UpstreamData @.***> wrote:
Fixed the addition issue in 0.37.1
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you modified the open/close state.Message ID: @.***>
S19 Pro: Firmware Version Mon Dec 26 17:10:01 CST 2022 S19j Pro that worked with 0.37: Firmware Version Mon Dec 26 19:16:16 CST 2022 S19j Pro that didnt work with 0.37.1 or 0.37: Firmware Version Mon Dec 26 17:19:30 CST 2022 S19j Pro that didnt work with 0.37.1: Firmware Version Mon Dec 26 19:24:49 CST 2022
I didnt think they were on different firmwares, I only have one file for all of them: Antminer-S19j-Pro-merge-release-20221226125147.bmu I ll try to run this file on them again but not sure if it ll change anything
I did firmware upgrade on this one S19j Pro that didnt work with 0.37.1 or 0.37: Firmware Version Mon Dec 26 17:19:30 CST 2022 with the file name above, it didnt change anything. I dont know why they report different time if they are upgraded to the same firmware file.
This is what I like to call a Bitmain moment. Seems like they have a merge release which downloads from a server and gets slightly different builds based on some arbitrary information on the miner. This means it will likely be nearly impossible to rectify this, as it's not really possible to tell what is supposed to be sent for any given system. Your best bet might be to set up a dict mapping to whether it needs to be a string or an int, then manually calling miner.web.set_miner_conf on the miners with the result of config.as_x19 and setting miner_mode to either a str or int. I'll spend some time here writing something up.
Do you think running python3 lpm.py 192.168.0.21 s19j pro can be sufficient to get it to work? And then in lpm.py for s19j pro an integer is set and if s19 pro a string? Or can script choose because ip is passed so it can just query without model argument?
On Fri, Jul 7, 2023 at 23:00, UpstreamData @.***> wrote:
This is what I like to call a Bitmain moment. Seems like they have a merge release which downloads from a server and gets slightly different builds based on some arbitrary information on the miner. This means it will likely be nearly impossible to rectify this, as it's not really possible to tell what is supposed to be sent for any given system. Your best bet might be to set up a dict mapping to whether it needs to be a string or an int, then manually calling miner.web.set_miner_conf on the miners with the result of config.as_x19 and setting miner_mode to either a str or int. I'll spend some time here writing something up.
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you modified the open/close state.Message ID: @.***>
I wouldn't, I would pass either str or int as a value to the script, so ./LPM.py 192.168.1.10 int
, but it makes more sense IMO to map it out.
and because I am not that proficient to program it properly, I could just run the script twice, once with int and once with str, and then reboot and it will give the necessary result.
Here ya go. You can use this using either a map like the top, or it can be slightly modified to take "int"
or "str"
as an argument to the file and it will still work, you just have to pass it into mode_type
instead of the value in the dict.
import pyasic
import asyncio
from pyasic.config import X19PowerMode
MINER_MODE_TYPES = {
"10.0.1.6": int, # uses int type
"192.168.1.11": str, # uses str type
"172.16.1.16": "str" # uses str type from string
}
async def send_config(miner: pyasic.AnyMiner, cfg: pyasic.MinerConfig, mode_type):
new_cfg = cfg.as_x19()
if isinstance(mode_type, type):
new_cfg["miner-mode"] = mode_type(cfg.miner_mode.value)
elif isinstance(mode_type, str):
if mode_type == "str":
new_cfg["miner-mode"] = str(cfg.miner_mode.value)
elif mode_type == "int":
new_cfg["miner-mode"] = int(cfg.miner_mode.value)
data = await miner.web.set_miner_conf(cfg)
if data:
if data.get("code") == "M000":
return
for i in range(7):
data = await miner.get_config()
if data == cfg:
break
await asyncio.sleep(1)
async def set_lpm(ip: str):
miner = await pyasic.get_miner(ip)
config = await miner.get_config()
config.miner_mode = X19PowerMode.LPM
await send_config(miner, config, MINER_MODE_TYPES.get(ip, str))
async def set_normal(ip: str):
miner = await pyasic.get_miner(ip)
config = await miner.get_config()
config.miner_mode = X19PowerMode.Normal
await send_config(miner, config, MINER_MODE_TYPES.get(ip, str))
async def main():
await set_lpm("10.0.1.6")
await set_normal("192.168.1.11")
asyncio.run(main())
Thank you. Using your script I am trying to do some more testing, I am running the following script
import sys
import asyncio
from pyasic.config import X19PowerMode
import pyasic
IP = sys.argv[1]
async def set_lpm(ip: str):
miner = await pyasic.get_miner(ip)
cfg = await miner.get_config()
cfg.miner_mode = X19PowerMode.LPM
new_cfg = cfg.as_x19()
new_cfg["miner-mode"] = str(cfg.miner_mode.value)
print(new_cfg)
data = await miner.web.set_miner_conf(new_cfg)
print(data)
if __name__ == "__main__":
asyncio.run(set_lpm(IP))
it set low power for s19 pro and they returned data as {'stats': 'success', 'code': 'M000', 'msg': 'OK!'}
for s19j pro it hasnt failed to set low power, but sometimes I need to call this script twice, maybe 30seconds apart, they always return None
but seems to set low power. Does it give you any clues?
That's what this part is designed to do, it should ensure theyre set into LPM.
if data:
if data.get("code") == "M000":
return
for i in range(7):
data = await miner.get_config()
if data == cfg:
break
await asyncio.sleep(1)
I ll ask about the loop tomorrow, but what do you think about them all setting to low power mode when passing miner_mode value as string?
I ll ask about the loop tomorrow, but what do you think about them all setting to low power mode when passing miner_mode value as string?
Not sure what you mean by this?
What I wanted to ask about the loop, is how does it ensure the setting sticks? Does it do set_miner_conf again if data != cfg?
Just replace the break
and return
in that code with return True
, then you can check if the result is True
and retry if needed.
Is there a global command to 1) switch on and off flashing lights to identify miner 2) set the miner into low power mode (for new antminer firmwares for example) 3) take the miner out of low power mode back into normal power mode
on each miner for different miner apis?