Support for Avalon Q Home
Need Support for the new Canaan AvalonQ Home.
See the Miner HomeAssistant Integration
https://github.com/Schnitzel/hass-miner/issues/545#issue-3134306221
+1 Running two of those and also would like to see them controlled via home assistant!
Yes pls!
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 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.
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.
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/softoffcommands 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 thanks for the excellent write-up, that helps a lot.
A couple things -
-
The api complains the "time interval is too short", does anything change if you send 1 instead of 0?
-
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"}'.
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.
- 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.
here is also the case of the
litestatscommand, which used to be juststats
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}#
param is , separated values, device id is likely the first param...
I would try echo '{"command": "ascset", "param": "0,softoff,1:4"}' | nc 10.0.0.201 4028
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}#
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}#
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())
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
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!
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.
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.
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
Maybe you want to try the
helpcommand 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.
@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?
@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...
We should try with workmode, since I have source code for that function at least. Then we can debug from there.
I may be stupid 😆
Try echo '{"command": "ascset", "parameter": "0,help"}' | nc 10.0.0.201 4028
TL;DR: parameter not param is the key.
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}#
Your other commands should now work if you use parameter instead of param!
Your other commands should now work if you use
parameterinstead ofparam!
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
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}#