gdwaterworth/Home-Assistant---E-Linter-Logger---Sunsynk

Can't SET inverter, e.g. time1on

Closed this issue · 15 comments

Hi, first of all thank you so much for all the work you've done on this; it's been a steep learning curve for me and so helpful.
I'm trying to write my own automation which is quite a bit simpler than yours as I don't have to worry about load shedding (being in the UK).

I have all the pieces except one: How to actually write settings back to the inverter! I changed the activeset for time1on to true and tried to use your flow but that didn't work for me.

Next I followed your node-red flow and used the same headers and payload. I even get a nice "Success" message back from SunSynk but the setting doesn't change. (See my python program below followed by its disappointing output)

Have you got this to work, and if so what is the secret?

Best wishes, Peter

def set_time1on(on_off):
    url = 'https://api.sunsynk.net/api/v1/common/setting/xxxxxxxx/set'
    #url = 'http://httpbin.org/post'
    payload = {'sn': "xxxxxxxx", 'time1on': on_off}
    headers = {'User-Agent': "Mozilla/5.0(Windows NT 10.0; Win64; x64; rv: 120.0) Gecko/20100101 Firefox/120.0",
           'Accept': "application/json",
           'Accept-Language': "en-US, en; q=0.5",
           'Accept-Encoding': "gzip, deflate, br",
           'Content-Type': "application/json;charset=UTF-8",
           'Authorization': "Bearer "+token,
           'Origin': "https://setting.inteless.com",
           'Connection': "keep-alive",
           'Referer': "https://setting.inteless.com/",
           'Sec-Fetch-Dest': "empty",
           'Sec-Fetch-Mode': "cors",
           'Sec-Fetch-Site': "same-site",
           'TE': "trailers"
           }
    r = requests.post(url, json=payload, headers=headers)
    print(r.json())

get_time1on() # get and print current state of time1on

set_time1on(False)

get_time1on()

time1on: True
{'code': 0, 'msg': 'Success', 'data': None, 'success': True}
time1on: True

Sorry, should have said I'm using your V2 files, and I completely accept it's a work in progress so absolutely no complaints!

Time?on is not working that is why it is still false in the active set. None of the true/false ones are for some reason. Let me know if you specifically get those working. Also note that sometimes it takes time for the change to happen and show

Thanks for taking the time to answer, I'll keep trying and let you know if I get anywhere.

Success! This seems to work. There are two significant differences from how I was trying before:

  1. I've used the entire settings list rather than just the one I want to change
  2. There is an extra header 'Content-Length' which is set to the length of the payload string

Also, as you suggested there is a delay at the SunSynk end before the change registers. For me it is between 4 and 10 seconds but presumably depends on server load.

The python below splits the enormously long payload into lhs and rhs with the time1on setting in the middle. It sets the new value for time1on and then splices it all back together again. Obviously the right way to do it is to query the settings beforehand but at least this is a proof-of-concept.

Hope this helps,

Best wishes, Peter

def set_time1on(on_off):
    url = 'https://api.sunsynk.net/api/v1/common/setting/xxxxxxxx/set'
    #url = 'http://httpbin.org/post'

    lhs = '{"sn":"xxxxxxxx","safetyType":"0","battMode":"-1","solarSell":"0","pvMaxLimit":"3600","energyMode":"1","peakAndVallery":"1","sysWorkMode":"2","sellTime1":"00:00","sellTime2":"01:30","sellTime3":"02:00","sellTime4":"02:30","sellTime5":"22:30","sellTime6":"23:00","sellTime1Pac":"5000","sellTime2Pac":"5000","sellTime3Pac":"5000","sellTime4Pac":"5000","sellTime5Pac":"5000","sellTime6Pac":"5000","cap1":"20","cap2":"100","cap3":"20","cap4":"20","cap5":"100","cap6":"20","sellTime1Volt":"58","sellTime2Volt":"58","sellTime3Volt":"49","sellTime4Volt":"49","sellTime5Volt":"49","sellTime6Volt":"49","zeroExportPower":"20","solarMaxSellPower":"6500","mondayOn":true,"tuesdayOn":true,"wednesdayOn":true,"thursdayOn":true,"fridayOn":true,"saturdayOn":true,"sundayOn":true,'
    rhs= ',"time2on":false,"time3on":false,"time4on":false,"time5on":true,"time6on":false,"genTime1on":false,"genTime2on":false,"genTime3on":false,"genTime4on":false,"genTime5on":false,"genTime6on":false}'
    payload = lhs + '"time1on":' + ('true' if on_off else 'false') + rhs # Python would have initial capital
    print(payload)

    headers = {'User-Agent': "Mozilla/5.0(Windows NT 10.0; Win64; x64; rv: 120.0) Gecko/20100101 Firefox/120.0",
           'Accept': "application/json",
           'Accept-Language': "en-GB,en;q=0.5",
           'Accept-Encoding': "gzip, deflate, br",
           'Content-Type': "application/json;charset=UTF-8",
           'Authorization': "Bearer "+token,
           'Content-Length': str(len(payload)),
           'Origin': "https://setting.inteless.com",
           'Connection': "keep-alive",
           'Referer': "https://setting.inteless.com/",
           'Sec-Fetch-Dest': "empty",
           'Sec-Fetch-Mode': "cors",
           'Sec-Fetch-Site': "cross-site",
           'TE': "trailers"
           }
    r = requests.post(url, data=payload, headers=headers)
    print(r.json())

OK I've narrowed it right down (code below works).
Summary:

  1. You DON'T need the Content-Length
  2. You DON'T need most of the other settings, not even the serial number
  3. You DO need time1on and genTime1on
def set_time1on(on_off):
    url = 'https://api.sunsynk.net/api/v1/common/setting/2212052408/set'
    #url = 'http://httpbin.org/post'
    lhs = '{'
    rhs= ',"genTime1on":false}'
    payload = lhs + '"time1on":' + ('true' if on_off else 'false') + rhs # Python would have initial capital
    print(payload)

    headers = {'User-Agent': "Mozilla/5.0(Windows NT 10.0; Win64; x64; rv: 120.0) Gecko/20100101 Firefox/120.0",
           'Accept': "application/json",
           'Accept-Language': "en-GB,en;q=0.5",
           'Accept-Encoding': "gzip, deflate, br",
           'Content-Type': "application/json;charset=UTF-8",
           'Authorization': "Bearer "+token,
           'Origin': "https://setting.inteless.com",
           'Connection': "keep-alive",
           'Referer': "https://setting.inteless.com/",
           'Sec-Fetch-Dest': "empty",
           'Sec-Fetch-Mode': "cors",
           'Sec-Fetch-Site': "cross-site",
           'TE': "trailers"
           }
    r = requests.post(url, data=payload, headers=headers)

Thanks, that's helpful. I have a very simple setup so not aware of the issues with bigger ones.

Around line 93 of the 'Create Inverter Update Request' node, I put in a kludge just to see if it works, which it does. I guess the next step is to do the pairing up of time?on with genTime?on via a mapping vector or a regexp substitution, and also read the current value to send back.

    } else if (BooleanEntities.includes(msg.payload.inverterid)) {
        if ((msg.payload.value === "on") || (msg.payload.value === "off")) 
        {
            if (msg.payload.value === "on") { outputmsg.payload[msg.payload.inverterid] = true;} else {outputmsg.payload[msg.payload.inverterid] = false ;}
            // PBCS: time1on change only accepted if genTime1on sent too
            if (msg.payload.inverterid == "time1on") {outputmsg.payload["genTime1on"] = false;}

I have a few idea's on how to do this. Will work on it

Code is in development branch for automation on gen and charge set automation

Would it be helpful if I test it here, or are you still refining things?

Code to support updates in all gen and charge set fields has been merged into the stable environment