pyasic icon indicating copy to clipboard operation
pyasic copied to clipboard

Support for Avalon Q Home

Open mark0st83 opened this issue 7 months ago • 55 comments

Need Support for the new Canaan AvalonQ Home.

See the Miner HomeAssistant Integration

https://github.com/Schnitzel/hass-miner/issues/545#issue-3134306221

mark0st83 avatar Jun 19 '25 19:06 mark0st83

+1 Running two of those and also would like to see them controlled via home assistant!

c7ph3r10 avatar Jun 29 '25 05:06 c7ph3r10

Yes pls!

R1cco avatar Jun 30 '25 23:06 R1cco

I was just jumping on to say the same thing. Received one of these today and would like to be able to automate it around solar production etc.

ZZR600E3 avatar Jul 04 '25 15:07 ZZR600E3

I was just jumping on to say the same thing. Received one of these today and would like to be able to automate it around solar production etc.

I found a workaround for myself. I documented it in the hass-miner Issues chapter which is linked above. May be you find it helpful as well. The workaround is not home assistant specific.

c7ph3r10 avatar Jul 04 '25 16:07 c7ph3r10

Ok, trying to get around to doing this now, but it seems like they change commands every few versions of miner, so I don't know if what I already have will be consistent. Most of the basic data gathering seems standard, but I'm guessing the softon/softoff commands will need to be tested in order to implement pause/resume.

Would anyone like to try replacing the timestamp parameter in those commands with 0? I want to see if it will accept a timestamp in the past or not, if not we may need to rely on the result of another command from the miner to have an accurate timestamp.

If anyone has one of these and wants help putting together a PR for them, let me know and I can help some more, but this is likely going to be one that I can't do easily without access to one.

b-rowan avatar Jul 21 '25 15:07 b-rowan

Ok, trying to get around to doing this now, but it seems like they change commands every few versions of miner, so I don't know if what I already have will be consistent. Most of the basic data gathering seems standard, but I'm guessing the softon/softoff commands will need to be tested in order to implement pause/resume.

Would anyone like to try replacing the timestamp parameter in those commands with 0? I want to see if it will accept a timestamp in the past or not, if not we may need to rely on the result of another command from the miner to have an accurate timestamp.

If anyone has one of these and wants help putting together a PR for them, let me know and I can help some more, but this is likely going to be one that I can't do easily without access to one.

Hey! In case you need some help in testing something may be I can support in this case. I have three Avalon Qs running with a semi professional load management based on home assistant (see link in the initial post).

Canaan Avalon Q behaves as following regarding softon/softoff:

Szenario 1: Avalon Q has no power although power supply switch is in "on" state. Activation of the power for the power supply makes the device automatically switch to the latest mode (Eco/Standard/Super) it was in when it was turned off. Even if it was send to standby bevore the power supply was disconnected from power it will start with the latest workmode it ran before it was disconnected from power. This szenario has nothing to to with the commands mentioned within my hass-miner post. It´s just to get the full picture.

Szenario 2: Avalon Q is in workmode Eco/Standard/Super. Sending softoff with timestamp '0' echo 'ascset|0,softoff,1:0' | nc 10.0.0.201 4028 leads to this response: STATUS=E,When=1753122013,Code=120,Msg=ASC 0 set failed: failed softoff:time interval is too short,Description=cgminer 4.11.1|# So this does not work. What works is: /bin/bash -c "echo 'ascset|0,softoff,1:$(( $(date +%s) + 5 ))' | nc 10.0.0.201 4028" So use current unix timestamp and add some secods (e.g. 5). Response looks like this: STATUS=I,When=1753122505,Code=118,Msg=ASC 0 set info: success softoff:1753122510,Description=cgminer 4.11.1|#

Szenario 3: Avalon Q was sent to standby via softoff. Power supply is still connected to power. Sending softon with timestemp '0': echo 'ascset|0,softon,1:0' | nc 10.0.0.201 4028 leads to this response: STATUS=I,When=1753158262,Code=118,Msg=ASC 0 set info: success softon:0,Description=cgminer 4.11.1|# so this gives a success response but for whatever reason the miner does NOT start! What also does work is: /bin/bash -c "echo 'ascset|0,softon,1:$(( $(date +%s) + 5 ))' | nc 10.0.0.201 4028" So using unix timestamp solves the problem also with softon. Response is: STATUS=I,When=1753158467,Code=118,Msg=ASC 0 set info: success softon:1753158472,Description=cgminer 4.11.1|#

Szenario 4: Avalon Q is in standby and it shall be switched to a workmode (Eco/Standard/Super). Sending command: echo 'ascset|0,workmode,set,1' | nc 10.0.0.201 4028 Response: STATUS=E,When=1753158766,Code=120,Msg=ASC 0 set failed: idle or current mode 0 is caling. Don't permit switch mode,Description=cgminer 4.11.1|# Conclusion: The miner always needs a softon ahead of using any workmode. Between softon and setting the workmode a delay should be set. In my configuration I use 45 seconds to be on the safe side.

I hope this helps to get softon/soft off managed. If you need further support let mit know. I have three of those running.

Here are some further commands and their responses. May be this helps to get some needed states: Command: echo "summary|0" | nc 10.0.0.201 4028 Response STATUS=S,When=1753159103,Code=11,Msg=Summary,Description=cgminer 4.11.1|SUMMARY,Elapsed=995,MHS av=6187974.81,MHS 5s=0.00,MHS 1m=17746.51,MHS 5m=2693620.78,MHS 15m=3347809.61,Found Blocks=0,Getworks=22,Accepted=11,Rejected=0,Hardware Errors=0,Utility=0.66,Discarded=0,Stale=0,Get Failures=0,Local Work=706,Remote Failures=0,Network Blocks=4,Total MH=6157265100.0000,Work Utility=86445.01,Difficulty Accepted=1286432.00000000,Difficulty Rejected=0.00000000,Difficulty Stale=0.00000000,Best Share=1719834,Device Hardware%=0.0000,Device Rejected%=0.0000,Pool Rejected%=0.0000,Pool Stale%=0.0000,Last getwork=0|#

Command: echo "stats|0" | nc 10.0.0.201 4028 Response: STATUS=S,When=1753159231,Code=70,Msg=CGMiner stats,Description=cgminer 4.11.1|STATS=0,ID=AVALON0,Elapsed=1128,Calls=0,Wait=0.000000,Max=0.000000,Min=99999999.000000,MM ID0:Summary=,HBinfo=|STATS=1,ID=POOL0,Elapsed=1128,Calls=0,Wait=0.000000,Max=0.000000,Min=99999999.000000,Pool Calls=0,Pool Attempts=0,Pool Wait=0.000000,Pool Max=0.000000,Pool Min=99999999.000000,Pool Av=0.000000,Work Had Roll Time=false,Work Can Roll=false,Work Had Expire=false,Work Roll Time=0,Work Diff=65536.00000000,Min Diff=65536.00000000,Max Diff=262144.00000000,Min Diff Count=3,Max Diff Count=1,Times Sent=30,Bytes Sent=4686,Times Recv=57,Bytes Recv=29573,Net Bytes Sent=4686,Net Bytes Recv=29573|#

Command: echo "litestats|0" | nc 10.0.0.201 4028 Response: STATUS=S,When=1753159324,Code=70,Msg=CGMiner stats,Description=cgminer 4.11.1|MM ID0:Summary='STATS':{Ver[Q-25052801_14a19a2] LVer[25052801_14a19a2] BVer[25052801_14a19a2] HashMcu0Ver[Q_hb_v1.1] FanMcuVer[Q_fb_v1.2] CPU[K230] FW[Release] DNA[0201000018f85eaf] STATE[1] MEMFREE[67956] NETFAIL[0 0 0 0 0 0 0 0] SSID[] RSSI[0] NetDevType[0] SYSTEMSTATU[Work: In Work, Hash Board: 1] Elapsed[1247] BOOTBY[0x01.00000000] LW[108661] MH[0] DHW[0] HW[0] DH[6.322%] ITemp[28] HBITemp[59] HBOTemp[62] TMax[71] TAvg[64] TarT[65] Fan1[1237] Fan2[1253] Fan3[1218] Fan4[1244] FanR[37%] SoftOffTime[1753158604] SoftOnTime[1753159097] Filter[16459] FanErr[0] SoloAllowed[1] PS[0 1219 2263 35 812 2264 847] PCOMM_E[0] GHSspd[42841.72] DHspd[6.322%] GHSmm[54083.50] GHSavg[13543.24] WU[189196.82] Freq[277.98] MGHS[13543.24] TA[160] Core[A3197S] BIN[36] PING[17] SoftOFF[4] ECHU[0] ECMM[0] PLL0[6778 5250 5542 6750] SF0[258 276 297 318] CRC[0] COMCRC[0] ATA0[800-65-2264-258-20] LcdOnoff[1] Activation[0] WORKMODE[0] WORKLEVEL[0] MPO[800] CALIALL[7] ADJ[1] Nonce Mask[25]}|#

Command: echo "devs|0" | nc 10.0.0.201 4028 Response: STATUS=S,When=1753159497,Code=9,Msg=1 ASC(s),Description=cgminer 4.11.1|ASC=0,Name=AVALON,ID=0,Enabled=Y,Status=Alive,Temperature=0.00,MHS av=19154818.07,MHS 5s=53248371.52,MHS 1m=56662062.00,MHS 5m=39777109.65,MHS 15m=20549704.26,Accepted=60,Rejected=0,Hardware Errors=0,Utility=2.63,Last Share Pool=0,Last Share Time=1405,Total MH=26247541512.0000,Diff1 Work=6111232,Difficulty Accepted=7250208.00000000,Difficulty Rejected=0.00000000,Last Share Difficulty=524288.00000000,Last Valid Work=1753159496,Device Hardware%=0.0000,Device Rejected%=0.0000,Device Elapsed=1370|#

Command: echo "devdetails|0" | nc 10.0.0.201 4028 Response: STATUS=S,When=1753159596,Code=69,Msg=Device Details,Description=cgminer 4.11.1|DEVDETAILS=0,Name=AVALON,ID=0,Driver=avalon,Kernel=,Model=,Device Path=|#

Command: echo "check|0" | nc 10.0.0.201 4028 Response: STATUS=S,When=1753159658,Code=72,Msg=Check command,Description=cgminer 4.11.1|CHECK,Exists=N,Access=N|#

Command: echo "version|0" | nc 10.0.0.201 4028 Response: STATUS=S,When=1753159712,Code=22,Msg=CGMiner versions,Description=cgminer 4.11.1|VERSION,CGMiner=4.11.1,API=3.7,PROD=Avalon Q,MODEL=Q,HWTYPE=Q_MM1v1_X1,SWTYPE=MM319,LVERSION=25052801_14a19a2,BVERSION=25052801_14a19a2,CGVERSION=25052801_14a19a2,HBMCUVERSION=Q_hb_v1.1,FANMCUVERSION=Q_fb_v1.2,DNA=0201000018f85eaf,MAC=00e04cce67a0|#

That is all I got so far. As said. If you need further support, let me know.

c7ph3r10 avatar Jul 22 '25 04:07 c7ph3r10

@c7ph3r10 thanks for the excellent write-up, that helps a lot.

A couple things -

  1. The api complains the "time interval is too short", does anything change if you send 1 instead of 0?

  2. You can change the format of your commands to make them much easier to parse (have them return a JSON response), by using '{"command": "$", "param": "$"}' instead. For example, the softon command would be '{"command": "ascset", "param": "0,softon,1:0"}'.

b-rowan avatar Jul 22 '25 05:07 b-rowan

For context, the reason I prefer JSON is because pyasic uses that style internally so it is much easier to parse, plus I can run tests against it. There is also the case of the litestats command, which used to be just stats, which returns jumbled garbage as part of the response, making it much much harder to parse if it isn't in JSON.

b-rowan avatar Jul 22 '25 05:07 b-rowan

  1. The api complains the "time interval is too short", does anything change if you send 1 instead of 0?

Changing 0 to 1 does nothing. Same for 2 and three. Response is always: STATUS=E,When=1753219278,Code=120,Msg=ASC 0 set failed: failed softoff:time interval is too short,Description=cgminer 4.11.1|# Starting with 4 response is: STATUS=I,When=1753219427,Code=118,Msg=ASC 0 set info: success softoff:4,Description=cgminer 4.11.1|# However, the miner is NOT going to standby but remains in its current workmode. Testet it up to '10'. Can´t find a pattern. Only a the command with a timestamp works as mentioned above.

2. You can change the format of your commands to make them much easier to parse (have them return a JSON response), by using '{"command": "$", "param": "$"}' instead. For example, the softon command would be '{"command": "ascset", "param": "0,softon,1:0"}'.

As I just sniffered the commands with wireshark I was not aware that JSON works as well. You are right. Something happens when I change the softoff commend e.g. to: echo '{"command": "ascset", "param": "0,softoff,1:4"}' | nc 10.0.0.201 4028 Response is JSON like then: {"STATUS":[{"STATUS":"E","When":1753219952,"Code":15,"Msg":"Missing device id parameter","Description":"cgminer 4.11.1"}],"id":1}#

However, I don´t know how to adjust the command to solve "Missing device id parameter". Tried the following:

echo '{"command": "ascset", "device id": "0",  "param": "softoff,1:4"}' | nc 10.0.0.201 4028
echo '{"command": "ascset", "id": "0",  "param": "softoff,1:4"}' | nc 10.0.0.201 4028
echo '{"command": "ascset", "id":0,  "param": "softoff,1:4"}' | nc 10.0.0.201 4028

Getting "Missing device id parameter" every time. Is there any kind of general JSON commands documentation for cgminer? Really would like to switch to JSON for your mentioned reasons.

c7ph3r10 avatar Jul 22 '25 21:07 c7ph3r10

here is also the case of the litestats command, which used to be just stats

The following command does its work: echo '{"command": "litestats", "param": "0"}' | nc 10.0.0.201 4028

JSON response: {"STATUS":[{"STATUS":"S","When":1753220531,"Code":70,"Msg":"CGMiner stats","Description":"cgminer 4.11.1"}],"STATS":[{"MM ID0:Summary":"'STATS':{Ver[Q-25052801_14a19a2] LVer[25052801_14a19a2] BVer[25052801_14a19a2] HashMcu0Ver[Q_hb_v1.1] FanMcuVer[Q_fb_v1.2] CPU[K230] FW[Release] DNA[0201000018f85eaf] STATE[1] MEMFREE[67952] NETFAIL[0 0 0 0 0 0 0 0] SSID[] RSSI[0] NetDevType[0] SYSTEMSTATU[Work: In Work, Hash Board: 1] Elapsed[1412] BOOTBY[0x01.00000000] LW[737509] MH[0] DHW[0] HW[0] DH[2.337%] ITemp[32] HBITemp[60] HBOTemp[63] TMax[72] TAvg[65] TarT[65] Fan1[1401] Fan2[1373] Fan3[1386] Fan4[1415] FanR[44%] SoftOffTime[10] SoftOnTime[0] Filter[16882] FanErr[0] SoloAllowed[1] PS[0 1217 2250 35 808 2251 834] PCOMM_E[0] GHSspd[54146.67] DHspd[2.337%] GHSmm[55445.83] GHSavg[51528.37] WU[719842.95] Freq[284.98] MGHS[51528.37] TA[160] Core[A3197S] BIN[36] PING[17] SoftOFF[0] ECHU[0] ECMM[0] PLL0[7488 5732 5388 5712] SF0[258 276 297 318] CRC[0] COMCRC[0] ATA0[800-65-2264-258-20] LcdOnoff[1] Activation[0] WORKMODE[0] WORKLEVEL[0] MPO[800] CALIALL[7] ADJ[1] Nonce Mask[25]}"}],"id":1}#

c7ph3r10 avatar Jul 22 '25 21:07 c7ph3r10

param is , separated values, device id is likely the first param...

b-rowan avatar Jul 22 '25 21:07 b-rowan

I would try echo '{"command": "ascset", "param": "0,softoff,1:4"}' | nc 10.0.0.201 4028

b-rowan avatar Jul 22 '25 21:07 b-rowan

guess you prefer this one:

echo '{"command": "stats", "param": "0"}' | nc 10.0.0.201 4028

response: {"STATUS":[{"STATUS":"S","When":1753220674,"Code":70,"Msg":"CGMiner stats","Description":"cgminer 4.11.1"}],"STATS":[{"STATS":0,"ID":"AVALON0","Elapsed":1528,"Calls":0,"Wait":0.000000,"Max":0.000000,"Min":99999999.000000,"MM ID0:Summary":"","HBinfo":""},{"STATS":1,"ID":"POOL0","Elapsed":1528,"Calls":0,"Wait":0.000000,"Max":0.000000,"Min":99999999.000000,"Pool Calls":0,"Pool Attempts":0,"Pool Wait":0.000000,"Pool Max":0.000000,"Pool Min":99999999.000000,"Pool Av":0.000000,"Work Had Roll Time":false,"Work Can Roll":false,"Work Had Expire":false,"Work Roll Time":0,"Work Diff":524288.00000000,"Min Diff":100000.00000000,"Max Diff":524288.00000000,"Min Diff Count":1,"Max Diff Count":2,"Times Sent":45,"Bytes Sent":7131,"Times Recv":75,"Bytes Recv":36197,"Net Bytes Sent":7131,"Net Bytes Recv":36197}],"id":1}#

c7ph3r10 avatar Jul 22 '25 21:07 c7ph3r10

I would try echo '{"command": "ascset", "param": "0,softoff,1:4"}' | nc 10.0.0.201 4028

Still this response:

{"STATUS":[{"STATUS":"E","When":1753220807,"Code":15,"Msg":"Missing device id parameter","Description":"cgminer 4.11.1"}],"id":1}#

c7ph3r10 avatar Jul 22 '25 21:07 c7ph3r10

You could try constructing it with pyasic if you want...

import asyncio

from pyasic import CGMinerRPCAPI

IP = ""


async def main():
    rpc = CGMinerRPCAPI(IP)
    print(await rpc.ascset(0, "softoff", "1:4"))


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

b-rowan avatar Jul 22 '25 21:07 b-rowan

For example, heres some of those similar functions executed by pyasic - https://github.com/UpstreamData/pyasic/blob/aa3d105fcb64b5ceec6704c50e0098d9326ca6fd/pyasic/miners/backends/avalonminer.py#L89-L105

b-rowan avatar Jul 22 '25 21:07 b-rowan

Interestingly enough they released sources for the nano3s, this is (eventually) how those commands get handled - https://github.com/Canaan-Creative/Avalon_Nano3s/blob/04c84d312a4e38c1efa437b086bbcb297749e77a/cg_miner/cgminer/driver-avalon.c#L2907-L2933

This also contains a list of all the commands!

b-rowan avatar Jul 22 '25 21:07 b-rowan

You could try constructing it with pyasic if you want...

I am affraid there are some missig capabilities on my side to do this. Would really have to deep dive into pyasic to do this. Right now I just have an ssh comand prompt on my home assistance instance to shoot the commands.

c7ph3r10 avatar Jul 22 '25 21:07 c7ph3r10

Interestingly enough they released sources for the nano3s, this is (eventually) how those commands get handled - https://github.com/Canaan-Creative/Avalon_Nano3s/blob/04c84d312a4e38c1efa437b086bbcb297749e77a/cg_miner/cgminer/driver-avalon.c#L2907-L2933

This also contains a list of all the commands!

I asked canaan support wheather there is something like that for the avalon q´s already. Got the response that they will give it to the development team. I am affraid this will take ages.

c7ph3r10 avatar Jul 22 '25 21:07 c7ph3r10

Maybe you want to try the help command with ascset?

echo '{"command": "ascset", "param": "help"}' | nc 10.0.0.201 4028 or maybe echo '{"command": "ascset", "param": "0,help"}' | nc 10.0.0.201 4028

b-rowan avatar Jul 22 '25 22:07 b-rowan

Maybe you want to try the help command with ascset?

Response is: {"STATUS":[{"STATUS":"E","When":1753221666,"Code":15,"Msg":"Missing device id parameter","Description":"cgminer 4.11.1"}],"id":1}#

in both cases. somehow the device id seems to be required for every "write" command.

c7ph3r10 avatar Jul 22 '25 22:07 c7ph3r10

@b-rowan Did not understand what´s your issue right now? Is it just the JSON format? This seems to be solved for every "read" command but not for softoff, softon and workmode, right?

c7ph3r10 avatar Jul 22 '25 22:07 c7ph3r10

@b-rowan Did not understand what´s your issue right now? Is it just the JSON format? This seems to be solved for every "read" command but not for softoff, softon and workmode, right?

Yes kindof, but the issue is if I want to implement these functions (which are used in hass-miner) I will need to understand exactly how to format them...

b-rowan avatar Jul 22 '25 22:07 b-rowan

We should try with workmode, since I have source code for that function at least. Then we can debug from there.

b-rowan avatar Jul 22 '25 22:07 b-rowan

I may be stupid 😆

Try echo '{"command": "ascset", "parameter": "0,help"}' | nc 10.0.0.201 4028

b-rowan avatar Jul 22 '25 22:07 b-rowan

TL;DR: parameter not param is the key.

b-rowan avatar Jul 22 '25 22:07 b-rowan

Try echo '{"command": "ascset", "parameter": "0,help"}' | nc 10.0.0.201 4028

that looks much better: {"STATUS":[{"STATUS":"I","When":1753222454,"Code":118,"Msg":"ASC 0 set info: help|voltage|fan-spd|lcd|hash-sn-read|hash-sn-write|volt-tuning|workmode|worklevel|work_mode_lvl|reboot|softon|softoff|filter-clean|facopts|faclock|activate|solo-allowed|frequency|loop|password|qr_auth|time|","Description":"cgminer 4.11.1"}],"id":1}#

c7ph3r10 avatar Jul 22 '25 22:07 c7ph3r10

Your other commands should now work if you use parameter instead of param!

b-rowan avatar Jul 22 '25 22:07 b-rowan

Your other commands should now work if you use parameter instead of param!

they do:

echo '{"command": "ascset", "parameter": "0,softoff,1:4"}' | nc 10.0.0.201 4028

response: {"STATUS":[{"STATUS":"I","When":1753222577,"Code":118,"Msg":"ASC 0 set info: success softoff:4","Description":"cgminer 4.11.1"}],"id":1}#

just as mentioned: timestamp issue is still there

c7ph3r10 avatar Jul 22 '25 22:07 c7ph3r10

echo '{"command": "ascset", "parameter": "0,workmode,set,1"}' | nc 10.0.0.201 4028

works as well to set the "Standard" Workmode. 0 = Eco, 2 = Super

response: {"STATUS":[{"STATUS":"S","When":1753222670,"Code":119,"Msg":"ASC 0 set OK","Description":"cgminer 4.11.1"}],"id":1}#

c7ph3r10 avatar Jul 22 '25 22:07 c7ph3r10