jbuehl/solaredge

Limitations of semonitor and RS232

Opened this issue · 7 comments

I have an SE10000 and an RPI2 running CentOS 7 with the requisite python libraries. My Inverter has the mini USB connector, so I'm using that connected to my RPI2. I've had success using semonitor to read the encryption key so I know that the RS232 interface works. I've also run a command query using semonitor for function 322 and it returns what you'd expect.

Like many others, my goal is to get inverter and optimizer data. I've read every issue (open and closed) in this project with RS232 in the body and the documentation, but it's unclear to me whether I can use RS232 in place of grabbing the data via ethernet. I have the Server set to RS232 and power cycled the inverter. I also sent the command to set unencrypted mode and restart the inverter.

Now when I run python solaredge/semonitor.py -s 7d104338 -t 2 /dev/ttyUSB0 -vvvv I get:

append: False
baudrate: 115200
commands:
datasource: /dev/ttyUSB0
follow: False
following: True
interface: None
keyfile: None
logfile: stderr
master: False
outfile: stdout
ports: 22222,22221,80
record: None
slaves: 7d104338
type: 2
updatefile: None
verbose: 4
xerror: False
opening /dev/ttyUSB0
/dev/ttyUSB0 --> message: 2 length: 22
data:       12 34 56 79 00 00 ff ff a5 01 38 43 10 7d fe ff
data:       ff ff 01 05 26 94
dataLen:    0000
dataLenInv: ffff
sequence:   01a5
source:     7d104338
dest:       fffffffe
function:   0501
/dev/ttyUSB0 --> message: 3 length: 22
data:       12 34 56 79 00 00 ff ff a5 01 38 43 10 7d fe ff
data:       ff ff 01 05 26 94
dataLen:    0000
dataLenInv: ffff
sequence:   01a5
source:     7d104338
dest:       fffffffe
function:   0501
/dev/ttyUSB0 --> message: 4 length: 74
data:       12 34 56 79 34 00 cb ff ff ff 38 43 10 7d fe ff
data:       ff ff c2 03 00 00 2c 00 18 7d 78 5b 00 00 00 00
data:       00 e0 86 45 00 e0 86 45 ff ff 7f ff ff ff 7f ff
data:       ff ff 7f ff ff ff 7f ff ff ff 7f ff ff ff 7f ff
data:       ff ff 7f ff ff ff 7f ff fe 69
dataLen:    0034
dataLenInv: ffcb
sequence:   ffff
source:     7d104338
dest:       fffffffe
function:   03c2
Unknown function 0x03c2

Function 0x0501 looks like the inverter trying to get the time. I see that responding to function 501 is coded into semonitor, but it looks like I'm only reading from the inverter and not actually responding to its queries. Is this not implemented for RS232? No idea what function 3c2 is.
I see no other functions other than 501 and 3c2. My guess is that the inverter is refusing to send other updates until it can set the time.

To sum up:

  • Can I get optimizer data via RS232 or is RS232 only really useful for getting the encryption key and enabling unencrypted mode?
  • Possibly related to Q1: can I use semonitor via RS232 the same way one would use it via ethernet to respond to time/dns/dhcp queries?
  • Am I using the right options to semonitor to get what I want (or at least try)?
  • Anything else I'm missing/should try?

Thanks,
-Jason

An assumption in semonitor was that RS232 would be used for maintenance purposes and data reporting would be done via RS485 or ethernet, so that's why it isn't responding to the 501 command. You could try modifying semonitor.py (line 91) to make it work differently, or you could get a RS485-USB dongle and use that interface instead. No idea what the 3c2 command is either.

In issue #8 on Mar 12, 2016 you mentioned:

@martynwendon - You should be able to specify the USB COM port as the input to semonitor, however I don't yet know how to get the inverter to send logging data to the RS232 port. In the case of the network it just sends the data messages to the SE server and in the case of RS485 there is a command that the master sends that prompts the inverter to send the data, however that command is ignored on the RS232 port. I will figure that out shortly.

Did you ever make any progress on this? I'd be happy if I could just poll for inverter and optimizer data via RS232.

No I didn't, but reading further in issue #8 on Mar 17 it appears that @martynwendon encountered the same problem and got it working by specifying master mode. You can try this but you will also have to specify RS485 (-t 4 -m).

Obviously that bug didn't get fixed, probably because nobody else is using RS232.

Did as you suggested with the -t 4 -m flags and have been able to obtain the periodic optimizer & inverter status updates. I still get those function 302s quite regularly, but they're ignored.

I did find an issue with se2state and I'll open this in a different issue if you'd like.

This json blob was logged by semonitor to inverter_sample.json via tee(1):

{"inverters": {"7D104338": {"Uptime": 63979, "Temp": 39.40312576293945, "Vac": 246.421875, "Eac": 16.0, "Interval": 300, "Iac": 1.5390625, "Eday": 29386.6796875, "Etot": 29742868.0, "Vdc": 370.0625, "Pac": 214.0, "Time": "23:44:58", "Date": "2018-08-19", "Freq": 59.99581527709961, "ID": "7D104338", "Pmax": 2571.30126953125}}, "meters_0x0022": {"7D104338": {"9_PVProduction": {"TotalE2Grid": 0, "AlwaysZero_off34_int2": 0, "seId": "7D104338", "TotalEfromGrid": 0, "Flag_off20_hex": "00 80", "devLen": 58, "Flag_off28_hex": "00 80", "E2X": 16, "PfromX": NaN, "P2X": 214.0, "Date": "2018-08-19", "AlwaysZero_off18_int2": 0, "Totaloff22_int4": 0, "Totaloff30_int4": 0, "Interval": 300, "EfromX": 0, "seType": "0x0022", "Time": "23:44:58", "onlyIntervalData": 1, "dateTime": 1534722298, "AlwaysZero_off26_int2": 0, "AlwaysZero_off10_int2": 0, "devType": "meters_0x0022", "Flag_off36_hex": "00 80", "Flag_off12_hex": "00 80", "recType": 9}}}, "events": {}, "optimizers": {"103BDB68": {"Uptime": 43207, "Temp": 30.0, "Vmod": 26.5, "Imod": 0.28125, "Eday": 977.5, "Vopt": 24.0, "Time": "23:45:41", "Date": "2018-08-19", "Inverter": 0, "ID": "103BDB68"}, "103695E6": {"Uptime": 43270, "Temp": 30.0, "Vmod": 27.625, "Imod": 0.35000000000000003, "Eday": 1013.25, "Vopt": 24.75, "Time": "23:46:19", "Date": "2018-08-19", "Inverter": 0, "ID": "103695E6"}, "10391D0D": {"Uptime": 43632, "Temp": 30.0, "Vmod": 27.25, "Imod": 0.33125000000000004, "Eday": 991.25, "Vopt": 25.125, "Time": "23:45:42", "Date": "2018-08-19", "Inverter": 0, "ID": "10391D0D"}, "103BFA27": {"Uptime": 43469, "Temp": 30.0, "Vmod": 27.375, "Imod": 0.375, "Eday": 1018.5, "Vopt": 24.125, "Time": "23:46:22", "Date": "2018-08-19", "Inverter": 0, "ID": "103BFA27"}, "10391D90": {"Uptime": 43434, "Temp": 30.0, "Vmod": 25.875, "Imod": 0.25, "Eday": 964.75, "Vopt": 22.375, "Time": "23:45:54", "Date": "2018-08-19", "Inverter": 0, "ID": "10391D90"}, "10315D31": {"Uptime": 43653, "Temp": 30.0, "Vmod": 27.375, "Imod": 0.36250000000000004, "Eday": 1003.25, "Vopt": 23.75, "Time": "23:46:00", "Date": "2018-08-19", "Inverter": 0, "ID": "10315D31"}, "103BF9F7": {"Uptime": 43203, "Temp": 30.0, "Vmod": 26.875, "Imod": 0.25625000000000003, "Eday": 964.0, "Vopt": 24.25, "Time": "23:45:33", "Date": "2018-08-19", "Inverter": 0, "ID": "103BF9F7"}, "103BF999": {"Uptime": 43380, "Temp": 30.0, "Vmod": 27.625, "Imod": 0.36250000000000004, "Eday": 997.0, "Vopt": 24.5, "Time": "23:45:44", "Date": "2018-08-19", "Inverter": 0, "ID": "103BF999"}, "10395C57": {"Uptime": 43502, "Temp": 30.0, "Vmod": 26.0, "Imod": 0.28125, "Eday": 977.25, "Vopt": 22.5, "Time": "23:45:55", "Date": "2018-08-19", "Inverter": 0, "ID": "10395C57"}, "103694DF": {"Uptime": 43639, "Temp": 30.0, "Vmod": 27.875, "Imod": 0.3375, "Eday": 998.25, "Vopt": 24.875, "Time": "23:46:02", "Date": "2018-08-19", "Inverter": 0, "ID": "103694DF"}}}

When I try to use se2state I get this error:

$ cat ~/inverter_sample.json | solaredge/conversion/se2state.py -o solar.json
Traceback (most recent call last):
  File "solaredge/conversion/se2state.py", line 69, in <module>
    stateDict["inverters"].update(inDict["inverters"])
NameError: name 'stateDict' is not defined

Further, when running semonitor | tee | se2state I also see this, the TypeError being of interest:

Exception in thread read thread:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 812, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 765, in run
    self.__target(*self.__args, **self.__kwargs)
  File "solaredge/semonitor.py", line 65, in readData
    logger.info("Failed to parse message: "+ex)
TypeError: cannot concatenate 'str' and 'exceptions.IOError' objects

Just out of curiosity I did validate the JSON using a couple tools online and it did validate, though one did complain because (near as I can tell) in "PfromX": NaN, the string NaN wasn't double quoted.

I poked around se2state a bit by my experience with Python is limited. Seems like that dictionary should have been initialized one way or another, so I'm not sure why it's not defined. I fetched the latest repo a couple days ago when I started working on this again, and did so again this evening -- all is current.

Just a thought re the first stateDict problem.

Does the file mentioned in -o solar.json exist? If not you might need to use the -i argument on your first se2state run (as well as the -o solar.json) to initialise it with zero values. Subsequent runs (without the -i argument !!) would then update the data in the solar.json file.

Caveat - I haven't used se2state myself, I just had a quick look at the code out of curiosity.

Thank you for that valuable insight. I used the json file above and ran se2status -i inverter_sample.json -o solar.json to initialize solar.json.

I had been referencing README.md for usage of that and it does not reference the -i flag. It would be useful to have that updated, have a help flag for se2state, and a blurb that talks about the need to initialize the state file.

I've got an RS485 to USB adapter on order and plan to fiddle with that as well. I would be interested in helping to enhance the RS232 functionality of semonitor.