johanmeijer / grott

Growatt inverter monitor
https://github.com/johanmeijer/grott/wiki
390 stars 108 forks source link

Feature Request: send commands to Growatt inverter #73

Closed tabascoz closed 1 year ago

tabascoz commented 2 years ago

Hi there,

First of all, thank you very much for dedicating your time to this project - i appreciate it much.

I'd like to ask to consider a new functionality to send commands to the devices in proxy mode.

Ex. I run an SFP3500ES and I'd like to set some automated logic with Homeassistant behind standard growatt logic and set device output mode according to particular needs ex. change from SOL to SBU or GRID in case a storm is coming and i need to charge the batteries while i am away from home.

I tried to find a way to do it by using modbus but I'm still on early stages and i thought it might be something easy to implement in Grott.

johanmeijer commented 2 years ago

Okee.... Nice challenge!

At this moment Grott is not able to send commands to the inverter. I do not say I do not want that (I like by example to be able to change sample rate and inverter time) but I still have to find out how the command structure looks like. Grott can recognize and block commands coming from the Growatt server.

If we know what the command should be (if it is possible to switch the output mode by command) we can try to implement it. Do you know if it is possible to sent this command from the growatt.server.com website (via the inverter setting menu)? If that is possible we can try to "catch" the command and see how it looks like.

tabascoz commented 2 years ago

Yes, it is possible - i was thinking about inplementing some debug logging on the python code to extract the package. Everytime i change a parameter from growatt server i see the packages flowing though grott. Will try to log and send it back to you.

Thanks ! count with my full support to test it! :)

tabascoz commented 2 years ago

on grottproxy.py i included the line 126 as below:

           print("\t - " + "Growatt packet received:") ^M                                                                                                                                                             
++       print("\t - " + "data:",data) ^M                                                                                                                                                                           
            print("\t\t ", self.channel[self.s])^M        

This is the result when i issue a command from ShrinePhone:

  1. Change AC Output source to Batt priority:
nov 04 16:09:23 Pro grott[67254]:          - Growatt packet received:
nov 04 16:09:23 Pro grott[67254]:          - data: b'\x00\x01\x00\x06\x00$\x01\x06\n%(G#<CwA_wattGrowattGrowattGrovat\xc3\x99'
nov 04 16:09:23 Pro grott[67254]:                   <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 5279), raddr=('192.168.18.245', 40202)>
nov 04 16:09:23 Pro grott[67254]:          - Data less then minimum record length, data not processed
nov 04 16:09:24 Pro grott[67254]:          - Growatt packet received:
nov 04 16:09:24 Pro grott[67254]:          - data: b'\x00\x01\x00\x06\x00%\x01\x06\n%(G#<CwA_wattGrowattGrowattGrovatt\x84\x92'
nov 04 16:09:24 Pro grott[67254]:                   <socket.socket fd=5, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 59416), raddr=('47.91.67.66', 5279)>
nov 04 16:09:24 Pro grott[67254]:          - Data less then minimum record length, data not processed
  1. Change AC Output source to Photovoltaic & Utilitiy mode:
nov 04 16:10:30 Pro grott[67254]:          - Growatt packet received:
nov 04 16:10:30 Pro grott[67254]:          - data: b'\x00\x01\x00\x06\x00$\x01\x06\n%(G#<CwA_wattGrowattGrowattGrovau\x03X'
nov 04 16:10:30 Pro grott[67254]:                   <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 5279), raddr=('192.168.18.245', 40202)>
nov 04 16:10:30 Pro grott[67254]:          - Data less then minimum record length, data not processed
nov 04 16:10:32 Pro grott[67254]:          - Growatt packet received:
nov 04 16:10:32 Pro grott[67254]:          - data: b'\x00\x01\x00\x06\x00%\x01\x06\n%(G#<CwA_wattGrowattGrowattGrovatuDS'
nov 04 16:10:32 Pro grott[67254]:                   <socket.socket fd=5, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 59416), raddr=('47.91.67.66', 5279)>
nov 04 16:10:32 Pro grott[67254]:          - Data less then minimum record length, data not processed

Looks like it receive two commands for this particular parameter.

johanmeijer commented 2 years ago

That is nice. We are to see the command.I am a little bit worried about the format. It is now a mix of binary and string data. I am think I going the mix this up when I try to debug it.

Can you do it again with the original grottproxy.py and minrecl = 1 added in the generic session of the grott.ini file. This should enable printing of all records (in binary format only).

If this does not work I will try to debug your printed data.

One think we also have to think about is how we can trigger Grott to send the commands. We need some kind of interface (API/Dashboard/MQTT read) to "talk" with Grott. I you or somebody else has ideas on this please let me know.

tabascoz commented 2 years ago

Here it is:

1, Change AC Output source to Batt priority:

nov 05 13:21:42 Pro grott[74007]:          - Growatt packet received:
nov 05 13:21:42 Pro grott[74007]:                   <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 5279), raddr=('192.168.18.245', 27553)>
nov 05 13:21:42 Pro grott[74007]:          - Growatt original Data:
nov 05 13:21:42 Pro grott[74007]:                  \x00\x01\x00\x06\x00\x24\x01\x06\x0a\x25\x28\x47\x23\x3c\x43\x77\x41\x5f\x77
nov 05 13:21:42 Pro grott[74007]:                  \x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72
nov 05 13:21:42 Pro grott[74007]:                  \x6f\x76\x61\x74\xc3\x99
nov 05 13:21:42 Pro grott[74007]:          - Grott automatic protocol detection
nov 05 13:21:42 Pro grott[74007]:          - Grott data record length 44
nov 05 13:21:42 Pro grott[74007]:          - layout   :  T060106SPF
nov 05 13:21:42 Pro grott[74007]:          - no matching record layout found, try generic
nov 05 13:21:42 Pro grott[74007]:          - Record layout used :  T060106SPF
nov 05 13:21:42 Pro grott[74007]:          - Growatt data decrypted V2
nov 05 13:21:42 Pro grott[74007]:          - Grott Growatt data decrypted
nov 05 13:21:42 Pro grott[74007]:          - Growatt plain data:
nov 05 13:21:42 Pro grott[74007]:                  00010006002401064d57473042483730333000000000000000000000000000000000000000000
nov 05 13:21:42 Pro grott[74007]:                  0010000b7de
nov 05 13:21:42 Pro grott[74007]:          - Grott data ack record or data record not defined no processing done
nov 05 13:21:43 Pro grott[74007]:          - Growatt packet received:
nov 05 13:21:43 Pro grott[74007]:                   <socket.socket fd=5, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 59428), raddr=('47.91.67.66', 5279)>
nov 05 13:21:43 Pro grott[74007]:          - Growatt original Data:
nov 05 13:21:43 Pro grott[74007]:                  \x00\x01\x00\x06\x00\x25\x01\x06\x0a\x25\x28\x47\x23\x3c\x43\x77\x41\x5f\x77
nov 05 13:21:43 Pro grott[74007]:                  \x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72
nov 05 13:21:43 Pro grott[74007]:                  \x6f\x76\x61\x74\x74\x84\x92
nov 05 13:21:43 Pro grott[74007]:          - Grott automatic protocol detection
nov 05 13:21:43 Pro grott[74007]:          - Grott data record length 45
nov 05 13:21:43 Pro grott[74007]:          - layout   :  T060106SPF
nov 05 13:21:43 Pro grott[74007]:          - no matching record layout found, try generic
nov 05 13:21:43 Pro grott[74007]:          - Record layout used :  T060106SPF
nov 05 13:21:43 Pro grott[74007]:          - Growatt data decrypted V2
nov 05 13:21:43 Pro grott[74007]:          - Grott Growatt data decrypted
nov 05 13:21:43 Pro grott[74007]:          - Growatt plain data:
nov 05 13:21:43 Pro grott[74007]:                  00010006002501064d57473042483730333000000000000000000000000000000000000000000
nov 05 13:21:43 Pro grott[74007]:                  001000000c3e0
nov 05 13:21:43 Pro grott[74007]:          - Grott data ack record or data record not defined no processing done
  1. Change AC Output source to Photovoltaic & Utilitiy mode:
nov 05 13:23:23 Pro grott[74007]:          - Growatt packet received:
nov 05 13:23:23 Pro grott[74007]:                   <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 5279), raddr=('192.168.18.245', 27553)>
nov 05 13:23:23 Pro grott[74007]:          - Growatt original Data:
nov 05 13:23:23 Pro grott[74007]:                  \x00\x01\x00\x06\x00\x24\x01\x06\x0a\x25\x28\x47\x23\x3c\x43\x77\x41\x5f\x77
nov 05 13:23:23 Pro grott[74007]:                  \x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72
nov 05 13:23:23 Pro grott[74007]:                  \x6f\x76\x61\x77\xc2\xd9
nov 05 13:23:23 Pro grott[74007]:          - Grott automatic protocol detection
nov 05 13:23:23 Pro grott[74007]:          - Grott data record length 44
nov 05 13:23:23 Pro grott[74007]:          - layout   :  T060106SPF
nov 05 13:23:23 Pro grott[74007]:          - no matching record layout found, try generic
nov 05 13:23:23 Pro grott[74007]:          - Record layout used :  T060106SPF
nov 05 13:23:23 Pro grott[74007]:          - Growatt data decrypted V2
nov 05 13:23:23 Pro grott[74007]:          - Grott Growatt data decrypted
nov 05 13:23:23 Pro grott[74007]:          - Growatt plain data:
nov 05 13:23:23 Pro grott[74007]:                  00010006002401064d57473042483730333000000000000000000000000000000000000000000
nov 05 13:23:23 Pro grott[74007]:                  0010003b69e
nov 05 13:23:23 Pro grott[74007]:          - Grott data ack record or data record not defined no processing done
nov 05 13:23:24 Pro grott[74007]:          - Growatt packet received:
nov 05 13:23:24 Pro grott[74007]:                   <socket.socket fd=5, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 59428), raddr=('47.91.67.66', 5279)>
nov 05 13:23:24 Pro grott[74007]:          - Growatt original Data:
nov 05 13:23:24 Pro grott[74007]:                  \x00\x01\x00\x06\x00\x25\x01\x06\x0a\x25\x28\x47\x23\x3c\x43\x77\x41\x5f\x77
nov 05 13:23:24 Pro grott[74007]:                  \x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72
nov 05 13:23:24 Pro grott[74007]:                  \x6f\x76\x61\x74\x77\x85\xd2
nov 05 13:23:24 Pro grott[74007]:          - Grott automatic protocol detection
nov 05 13:23:24 Pro grott[74007]:          - Grott data record length 45
nov 05 13:23:24 Pro grott[74007]:          - layout   :  T060106SPF
nov 05 13:23:24 Pro grott[74007]:          - no matching record layout found, try generic
nov 05 13:23:24 Pro grott[74007]:          - Record layout used :  T060106SPF
nov 05 13:23:24 Pro grott[74007]:          - Growatt data decrypted V2
nov 05 13:23:24 Pro grott[74007]:          - Grott Growatt data decrypted
nov 05 13:23:24 Pro grott[74007]:          - Growatt plain data:
nov 05 13:23:24 Pro grott[74007]:                  00010006002501064d57473042483730333000000000000000000000000000000000000000000
nov 05 13:23:24 Pro grott[74007]:                  001000003c2a0
nov 05 13:23:24 Pro grott[74007]:          - Grott data ack record or data record not defined no processing done

I also send another command with a numeric parameter "Battery to Mains operating point" where i set it to 44 volts:

nov 05 13:25:03 Pro grott[74007]:          - Growatt packet received:
nov 05 13:25:03 Pro grott[74007]:                   <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 5279), raddr=('192.168.18.245', 27553)>
nov 05 13:25:03 Pro grott[74007]:          - Growatt original Data:
nov 05 13:25:03 Pro grott[74007]:                  \x00\x01\x00\x06\x00\x24\x01\x06\x0a\x25\x28\x47\x23\x3c\x43\x77\x41\x5f\x77
nov 05 13:25:03 Pro grott[74007]:                  \x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72
nov 05 13:25:03 Pro grott[74007]:                  \x6f\x52\x60\xcc\x2a\xd8
nov 05 13:25:03 Pro grott[74007]:          - Grott automatic protocol detection
nov 05 13:25:03 Pro grott[74007]:          - Grott data record length 44
nov 05 13:25:03 Pro grott[74007]:          - layout   :  T060106SPF
nov 05 13:25:03 Pro grott[74007]:          - no matching record layout found, try generic
nov 05 13:25:03 Pro grott[74007]:          - Record layout used :  T060106SPF
nov 05 13:25:03 Pro grott[74007]:          - Growatt data decrypted V2
nov 05 13:25:03 Pro grott[74007]:          - Grott Growatt data decrypted
nov 05 13:25:03 Pro grott[74007]:          - Growatt plain data:
nov 05 13:25:03 Pro grott[74007]:                  00010006002401064d57473042483730333000000000000000000000000000000000000000000
nov 05 13:25:03 Pro grott[74007]:                  02501b85e9f
nov 05 13:25:03 Pro grott[74007]:          - Grott data ack record or data record not defined no processing done
nov 05 13:25:04 Pro grott[74007]:          - Growatt packet received:
nov 05 13:25:04 Pro grott[74007]:                   <socket.socket fd=5, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.18.2', 59428), raddr=('47.91.67.66', 5279)>
nov 05 13:25:04 Pro grott[74007]:          - Growatt original Data:
nov 05 13:25:04 Pro grott[74007]:                  \x00\x01\x00\x06\x00\x25\x01\x06\x0a\x25\x28\x47\x23\x3c\x43\x77\x41\x5f\x77
nov 05 13:25:04 Pro grott[74007]:                  \x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72\x6f\x77\x61\x74\x74\x47\x72
nov 05 13:25:04 Pro grott[74007]:                  \x6f\x52\x61\x75\xcc\x96\x99
nov 05 13:25:04 Pro grott[74007]:          - Grott automatic protocol detection
nov 05 13:25:04 Pro grott[74007]:          - Grott data record length 45
nov 05 13:25:04 Pro grott[74007]:          - layout   :  T060106SPF
nov 05 13:25:04 Pro grott[74007]:          - no matching record layout found, try generic
nov 05 13:25:04 Pro grott[74007]:          - Record layout used :  T060106SPF
nov 05 13:25:04 Pro grott[74007]:          - Growatt data decrypted V2
nov 05 13:25:04 Pro grott[74007]:          - Grott Growatt data decrypted
nov 05 13:25:04 Pro grott[74007]:          - Growatt plain data:
nov 05 13:25:04 Pro grott[74007]:                  00010006002501064d57473042483730333000000000000000000000000000000000000000000
nov 05 13:25:04 Pro grott[74007]:                  0250001b8d1eb
nov 05 13:25:04 Pro grott[74007]:          - Grott data ack record or data record not defined no processing done

My suggestion on sending commands to grott - at least for testing and alpha stage would be nice to have a (quick and dirty) python command issuing the interaction with the value or command we need to issue - it could be the beginning of an API code.

Final result by monitoring MQTT would be awesome as it would allow a more clean and nice solution for automation.

I tried to find documentation of commands to send but unfortunately, i couldn't find nothing. But it seems that it wont be that difficult to reverse engineer or replay the streams. will put some time on it to document all the strings and most useful commands for automation. If you agree, please let me know the best format to have the data.

Thanks!

johanmeijer commented 2 years ago

Thanks for the records. I am going to try debug it and build it in Grott.

It will take some time while I, as stated, have a find a way how to sent commands to grott and I can only test it in the weekends. My growatt inverter only works when it is generating energy and that is not the best part of the year for it now in the Netherlands.

Next to it I have to do some gitthub administration/validation (committing or declining pull requests) before I can move on with a next release.

Of course I can test with your commands (I have a simple inverter only for Solar panels attached) but can try it with commands (like set time, sample frequentie, set ip address/ports etc) that my inverter understands.

Be aware if you specify blockcmd = true in the .ini file any command coming from the growatt server (except set time) should be blocked.

tabascoz commented 2 years ago

Thanks Johan,

Take your time and I'm fully available to support in anything necessary - also if you need access to my box to debug and test anything you need. I'm running Gentoo so it should be pretty easy to do anything there.

mjdyson commented 2 years ago

Hello, not sure if this is helpful (since it's reverse engineered from the public api), but I've seen a fork of PyPi_Growatt that has added settings functionality. https://github.com/muppet3000/PyPi_GrowattServer/tree/feature/add-settings-functionality

johanmeijer commented 2 years ago

Thanks for the hint. I am going to look at it!

tabascoz commented 2 years ago

Hello, not sure if this is helpful (since it's reverse engineered from the public api), but I've seen a fork of PyPi_Growatt that has added settings functionality. https://github.com/muppet3000/PyPi_GrowattServer/tree/feature/add-settings-functionality

Hi - thanks for sharing. I took a look and (if i got it right) the fork took a different approach to send to Growatt server the updates we need. I'm an Iphone user but my device is jailbroken so I need to setup a SSL sniffer to capture traffic of the parameters I'd like to control and call this library for it. But the approach GROTT could implement would be more reliable as we're operating on inverter side and (i believe) less susceptible ( and dependent) on Growatt server woes.

mjdyson commented 2 years ago

That's excellent. Thanks for investigating. I've managed to get some info via mitmproxy if that's useful? Mostly stimulating a settings change on the website and seeing what is sent with the POST. I'm happy to lend a hand if it would be useful info :)

tabascoz commented 2 years ago

Hi @mjdyson - I managed to make it work! a BIG thank you !!

Still on early stages, i used burpsuite as a proxy server in linux and SSL Kill Switch jailbreak tweak to temporary bypass IOS SSL pinning and with proxy settings i was able to capture SSL traffic from ShinePhone app.

For me, I was interested to change AC_Source and Charger_source, so now I'm able to run automations for ex. in case weather forecast shows only rainy days i can configure Growatt to act more like an UPS and prioritize charged batteries in case i lose grid and have little sun available.

To make it work, i have to edit init.py and change default op parameter (line 605) to "storageSPF5000Set2020".

I tweaked examples/setings_example.py as below:

###inverter charger parameters                                                                                                                                                                                       

#0 - PV Prio                                                                                                                                                                                                       
#1 - PV&Uti                                                                                                                                                                                                        
#2 - Only PV                                                                                                                                                                                                       

charger_settings={                                                                                                                                                                                                 
  'param1': 2                                                                                                                                                                                                      
}                                                                                                                                                                                                                  

print("Setting the inverter charger source to:")                                                                                                                                                                  
pp.pprint(charger_settings)                                                                                                                                                                                       
response = api.update_mix_inverter_setting(device_sn, 'storage_spf5000_charge_source', charger_settings)                                                                                                          
print(response)

### ac output source parameters                                                                                                                                                                                      

#0 - Bat Priority                                                                                                                                                                                                  
#1 - PV Priority                                                                                                                                                                                                   
#2 - Uti Priority                                                                                                                                                                                                  
#3 - PV & Uti Priority                                                                                                                                                                                             

charger_settings={                                                                                                                                                                                                 
  'param1': 0                                                                                                                                                                                                      
}                                                                                                                                                                                                                  

print("Setting the inverter AC source to:")                                                                                                                                                                        
pp.pprint(charger_settings)                                                                                                                                                                                        
response = api.update_mix_inverter_setting(device_sn, 'storage_spf5000_ac_output_source', charger_settings)                                                                                                        
print(response)

Johan, I still belive it would be more elegant and reliable to send commands through GROTT. Anytime you need me to test, I'm fully available!

ha-bnst commented 2 years ago

Hi, Has there been any progress on this? I have just installed this inverter and want to do a similar process of controlling charge and output from home assistant.

johanmeijer commented 2 years ago

See discussion #104. With grottserver (beta in 2.7.4). It should be possible.

KasperEdw commented 1 year ago

I went over this page and discussion #104 and I cant see if its possible to send commands to the inverter and how. Any word on this?

johanmeijer commented 1 year ago

Your right is is discussion: #98. Sorry!

RienduPre commented 1 year ago

Has anyone off you got this working?

I want to pause or stop my inverter when my dynamic energy prices are negative.

Thanks, Rien

johanmeijer commented 1 year ago

This is available with Grottserver (see #98).