Mirroring/intercepting SunPower Monitoring Traffic?
Collapse
X
-
Oh, and thanks for the compliment on my front end. I took it as a personal challenge to just replicate what SunPower's portal does. There's a little "Details" link there that takes you to another page that does their fancy Power display, like this: https://imgur.com/a/WUMQl -
Ugh! Well, that is certainly easier. Also, best I can tell, you are correct, it updates every MINUTE! That's awesome, though, and probably much more reliable than my packet sniffing method. Time to move the BeagleBone Black out to the garage (where the PV monitor is). Right now it's just hooked up to my iMac in the garage. I guess I could enable IP forwarding on my mac, but, details of my network, bleh.... Connecting to that URL via a web browser pulls up the JSON data nicely. Success!
Ok, how did you figure out what "Command=" you could send? Are there others?Leave a comment:
-
ehampshire: Oh... you are so very close the easy way to get the data, I'm surprised you missed the clue to it when you were changing your network connection on the pvs5. I checked out the link in your post. It's a nice set-up, I like the front end presentation you developed. I can write the back-end code but I'm not so good at the web stuff so I'm working on that part. My project isn't quite ready for general consumption but I'll give you the rough design and you and others can try it.
First it's necessary to know something about the pvs5 (pv supervisor.) There are two network ports. The one connected to your network just sends data to SunPower and this is the data that you are capturing on the 5 min interval. This network port acts as a DHCP client and gets it's IP address from your network. You can't do much with that port because it just sends the data. The other port (the installers network port) acts as a DHCP server so when the installer connects their laptop to the pvs5, it provides an IP address. I needed to have both ports on my network to get my solution to work. For my installation I didn't want to use wireless so I ran a cat-6 wire for the customer network connection to connect the pvs5 to my switch. This is how SunPower is collecting my data the same way as every one else. I ran another network wire from the pvs5 installers network port to my wiring cabinet. You can't connect the installers network port to your local network because then you would have two DHCP servers on your network and that would just mess things up. To isolate the installers network port I took a raspberry PI, added a second network port on it by attaching a USB-LAN adapter. One of the raspberry pi network ports goes to my LAN and the other goes to the pvs5 installers port. Both network adapters get their LAN address from the network they're attached to. The only other thing I did on the raspberry pi was to set routing between the two interfaces in /etc/ssctl.cnf and I made my LAN DHCP server provide a fixed address to my PI so I would always know what address it was on (in my case I'm giving it a fixed address of 192.168.1.100) Once this is set up you can log into the PI and see what addresses each interfaces got from the network. In my case the installers port network got an address from the 172.27.153.x network (the pvs5 turned out to have an address of 172.27.153.1) and on the other interface on my LAN it got a 192.168.1.100 address as I had set it up to do this in my DHCP. Now to test connectivity from my lan I went to my pc and added a static route (route add 172.27.153.0 mask 255.255.255.0 192.168.1.100) then try to ping 172.27.153.1. If it works then you may want to define that route to be permanent but in my case I didn't want to because of how my collection will ultimately be configured to work.
Now you have connectivity. My pvs5 being at address 172.27.153.1 I can go to my web browser and go to this URL:
What I get back is a very nice JSON format listing of my systems information that looks like this below. I know this blog will probably mess up the nice formatting of the json I have pasted in, sorry. (I have taken out some things to prevent identification of my system and left in only one inverter data)
Now all you have to do is write the code to do the query automatically and store it where you want to. I'm using python to do that part and I'm not quite finished yet so can't share yet but I'll have something in the not too distant future. I also plan to put the whole process in a blog somewhere like the page you have so others can benefit. I hope you found this information interesting and would love to get any feedback.
{ "result":"succeed", "devices":[ { "ISDETAIL":"1", "SERIAL":"PVS5XXXXXXXX", "TYPE":"PVS5-METER-P", "STATE":"working", "STATEDESCR":"Working", "MODEL":"PVS5M0400p", "DESCR":"Power Meter PVS5XXXXXXX", "DEVICE_TYPE":"Power Meter", "SWVER":"4", "PORT":"", "DATATIME":"2017,03,29,21,15,37", "ct_scaler":"50", "energy_total":"0", "power_w":"0", "power_var":"0", "power_va":"0", "power_factor":"1", "freq":"60", "CAL0":"50", "CURTIME":"2017,03,29,21,15,38" }, { "ISDETAIL":"1", "SERIAL":"PVS5XXXXXXXX", "TYPE":"PVS5-METER-C", "STATE":"working", "STATEDESCR":"Working", "MODEL":"PVS5M0400c", "DESCR":"Power Meter PVS5XXXXXXXX", "DEVICE_TYPE":"Power Meter", "SWVER":"4", "PORT":"", "DATATIME":"2017,03,29,21,15,37", "ct_scaler":"100", "energy_total":"-245.07", "power_w":"-4.5647", "power_var":"0.4764", "power_va":"4.6007", "power_factor":"-0.9921", "freq":"60", "CAL0":"100", "CURTIME":"2017,03,29,21,15,38" }, { "ISDETAIL":"1", "SERIAL":"41405XXXXXXXXXX", "TYPE":"SOLARBRIDGE", "STATE":"working", "STATEDESCR":"Working", "MODEL":"AC_Module_Type_C", "DESCR":"Inverter 41405XXXXXXXXXX", "DEVICE_TYPE":"Inverter", "SWVER":"951007408", "PORT":"", "DATATIME":"2017,03,29,21,15,37", "energy_total":"95.1664", "ac_power":"0.2871", "ac_volt":"254.1222", "ac_curr":"1.1623", "dc_power":"0.299", "dc_volt":"52.2409", "dc_curr":"5.698", "heatsink_temp":"57.5", "freq":"59.9772", "CURTIME":"2017,03,29,21,15,38" },
{ "DETAIL":"detail", "STATE":"working", "STATEDESCR":"Working", "SERIAL":"ZT16258XXXXXXXXXXXX", "MODEL":"PV Supervisor PVS5", "HWVER":"3.3", "SWVER":"5.0.0, Build 313", "DEVICE_TYPE":"PVS", "DATATIME":"2017,03,29,21,15,00", "dl_err_count":"0", "dl_comm_err":"395", "dl_skipped_scans":"0", "dl_scan_time":"0", "dl_untransmitted":"0", "dl_uptime":"1354458", "dl_cpu_load":"0.08", "dl_mem_used":"29884", "dl_flash_avail":"12484", "CURTIME":"2017,03,29,21,15,40" } ] }Leave a comment:
-
Yes, based on the serial of my system (PVS5M508095c) I'd say we have the same model supervisor. I'd be interested in knowing how you query it directly, that seems more reliable than the way the rest of us have set it up (by man-in-the-middling the traffic).
I was just about to come back to this thread and post my writeup of what I did. I just finished it yesterday, so it's a bit rough and I need to do some more formatting, but it does link to all the tools I developed for this little project.
Leave a comment:
-
Hi everyone. For those of you who are using the network snooping method of collecting data would you mind telling me how many of you have PV Supervisor PVS5 equipment (SunPower). This is the equipment I have and I'm working on a solution which queries the pv supervisor directly to collect data (I want to collect data every 60 seconds) and I have a working solution now. I'm making a decision if my solution will be a hack job (as in ugly code) because I'm the only one interested in using it or if I'll make it more professional because others may wish to use it.
My solution is using a raspberry PI, Maria database and python code. ThanksLeave a comment:
-
this is how i think my 130 message breaks down:
YYYYMMDDHHMMSS (UTC) inverter serial # inverter name just a tab total lifetime nrg (kwh) peak AC power just a tab ?? - sometimes just a tab avg dc voltage avg dc current inverter heatsink, degC frequency ? reactive power 130 20170115201000 XXXXXXXXXX SMA-SB-5000TL-US-22 9485.6914 2.713 1.3638 283.8639 4.8077 34.335 59.98 290Leave a comment:
-
Thanks, astroboy! That's actually pretty useful as you've figured out more fields than I certainly have. How did you know some what some of the values were, like the Temperature and DC Volts? Also, can you explain what $sm_freq and $peak_pwr is? An example line from your tcpdump would be helpful too (ie. the full line like below).
For instance, here's one of mine that just went by:
I know we have different inverters (looks like you have a Sunnyboy string inverter, I have micro inverters, so I get 24 of these 130 lines to match the number of panels I have). If I assume that the 3rd to the last is the temp (like yours), that would be 20C = 68F. Doesn't seem that likely as it's only 32F out there, unless the panels heat up a lot compared to ambient temperature (the sun is behind clouds, so again, doubtful).
in my case the temperature is the inverter heatsink temperature, so 68F is probably a normal temperature for the heatsink at 32F ambient. i assume that they want to monitor this because once it reaches 80C+ it's probably time to shut down the inverter or at least drop the power output to avoid damage to the power transistors in the inverter. do your 130s show some variation in those temperatures? i would expect that since each inverter has its own heatsink...
sm_freq is apparently the inverter's AC waveform frequency. peak_pwr is the peak output power seen during the 5 minutes that the 130 sample covers. rather than trying to convert this to an energy, and since the monitor outputs the cumulative generated energy since commissioning and PVOutput accepts a cumulative energy value, i stopped trying to compute the interval energy and just report the cumulative power to PVO.
i'll find a 130 line later today, i need to step out soon.
Leave a comment:
-
Thanks, astroboy! That's actually pretty useful as you've figured out more fields than I certainly have. How did you know some what some of the values were, like the Temperature and DC Volts? Also, can you explain what $sm_freq and $peak_pwr is? An example line from your tcpdump would be helpful too (ie. the full line like below).
For instance, here's one of mine that just went by:
130 20170114185000 414051637006544 AC_Module_Type_C 20.9279 0.0491 244.7866 0.4237 0.0515 58.1278 0.8935 20.375 59.997 0Leave a comment:
-
i am parsing 130 with the following code (kind of a mess, and i don't know what all the fields mean)
# message 130 seems to have missing fields when the sun
# goes down, hence the complexity of this match
# expression. it was created from a daytime and evening
# message 130 using regrxr.com.
my ($sm_time, $sm_tot_kwh, $peak_pwr, $dummy1,
$dummy2, $dummy3, $dc_volts, $dummy4,
$dummy5, $dummy6, $inv_temp_c, $dummy7, $sm_freq) =
$_ =~ m/130\s+(\d+)\s+\d+\s+SMA-SB-5000TL-US-22\s+(\d+\.\d+)\s((\d+.\d+)|\d)\s+((\d+\.\d+)|\d)\ s((\d+\.\d+)|\d)\s((\d+\.\d+)|\d)\s((\d+\.\d+)|\d+ )\s((\d+\.\d+)|\d)\s\d/;
if ((not defined $sm_time) or (not defined $peak_pwr) or
(not defined $sm_tot_kwh) or (not defined $dc_volts) or
(not defined $inv_temp_c)) {
# OK, give up...
$bad_parse = 1;
}
Leave a comment:
-
Not trying to be a troll here, but the first question is elementary. Not sure how you've gone this far without knowing about variables and date grabbing functions. It is even discussed at the top of page 5.
good luck, there is a lot of critical technical discussion in the last couple pages I order to make this script your own.
Also, the main point of my post was asking if anyone had figured out what all those other columns are. I understand you guys are processing what is sent up to SunPower and getting more detailed info for the net and production values, but is there any use for the rest of the data?Leave a comment:
-
I had a question about your regular expressions. I'm terrible at regex, it confuses me. I did have to modify your regex to look for 2017 in the timestamp, but I'm wondering if there's a better way to write the regex so it doesn't have to be modified yearly.
...
It looks like each of my panels are reporting on the 130 lines, so I can break those out into my own DB / web portal. I'm having a hard time deciphering the rest of the lines, though. I believe the 1st number (ie. "18.5466" in the first 130 line) is the Watts, the 2nd number (ie. "0.0417") is the kWh, but those are mostly guesses.
...
I get lost after that as to what the rest of the values are.
As for your second, the answer was provided by Rob above in his code itself:
if ($msg == 140) { # this is a net metering message, and $value is net metering value in (IIRC) W averaged over the 5-minute interval
# consumption = (corresponding production) + net
}
else { # this is a production message, and $value is a production valuein (IIRC) W averaged over the 5-minute interval
}
the hardest part is in what he wrote next
>>> (One of) the (many) trick(s) involved herein is how you deal with calculating consumption from net and production... They do not necessarily arrive in the same packet (although they often do) nor does production (130) always arrive before net (140).
and the following paragraph about handling the kwh value provided in the dump about net, production, and corresponding production row dump.
good luck, there is a lot of critical technical discussion in the last couple pages I order to make this script your own.Last edited by cebury; 01-08-2017, 02:16 AM.Leave a comment:
-
Well, SunPower finally fixed my PV Monitor so I could actually start looking at this data. Took them 3 weeks, but finally got up and running yesterday. So, I'm now doing a combination of tcpdump for the raw data and getting your Perl working. Not sure if it was cutting/pasting or what, but your code needed some tweaking to get running. I'm now re-acquainting myself with Perl and trying to write to a file after proving I could display things to the screen. I'll be glad to share what I have going so far if people are interested. I am planning on fleshing things out more and making a github project or something to share this with others so people who don't necessarily know how to code can work with it.
One problem I'm seeing at the moment is I think my PV monitor is using my wireless network instead of the networking power adapter I'm setup to sniff the traffic on. =( Also, this is hard to do during winter when the sun isn't shining much, let alone hack on it after dark.
I had a question about your regular expressions. I'm terrible at regex, it confuses me. I did have to modify your regex to look for 2017 in the timestamp, but I'm wondering if there's a better way to write the regex so it doesn't have to be modified yearly.My slightly modified section of your code:
# Then to process the packet payload:
sub process_packet_payload {
my $data = $_[0];
my @lines = split(/\n/, $data);
foreach my $line (@lines) {
chomp($line);
if (($line =~ /^(140)\t(2017[0-3][0-9][0-9]{2}[0-9]{2}[0-9]{2}[0-9]{2})\t[0-9]+\t[^\s]+\t125\t([-+]?[0-9]*\.?[0-9]+)\t/) ||
($line =~ /^(130)\t(2017[0-3][0-9][0-9]{2}[0-9]{2}[0-9]{2}[0-9]{2})\t[0-9]+\t[^\s]+\t\t([-+]?[0-9]*\.?[0-9]+)\t/) ||
($line =~ /^(100)\t/))
{
my $msg = $1;
my $datetime = $2;
my $value = $3;
if ($msg == 140) { # this is a net metering message, and $value is net metering value in (IIRC) W averaged over the 5-minute interval
# consumption = (corresponding production) + net
#printf $value
printf("net metering message (140):\n%s\n%s\t%s\n", $line, $datetime, $value);
printf $logFileHandle $line;
} elsif ($msg == 130) { # this is a production message, and $value is a production valuein (IIRC) W averaged over the 5-minute interval
printf("production message (130):\n%s\n%s\t%s\n", $line, $datetime, $value);
printf $logFileHandle $line;
} elsif ($msg == 100) { # this is a control message / keep-alive
printf("control message (100):\n%s\n", $line)
}
}
}
}
In terms of looking at the raw data, here's an example:
POST /Data/SMS2DataCollector.aspx HTTP/1.1
Host: collector.sunpowermonitor.com
Content-Type: text/plain
Content-Length: 3261
100 SPMS 10 ZT162585000441C1402 20170107171925
120 20170107171500 ZT162585000441C1402 0 445 0 0 0 81666 0.21 24876 12408
130 20170107171000 414051637009125 AC_Module_Type_C 18.5466 0.0417 245.1503 0.3643 0.044 59.0692 0.7733 1.25 59.9772 0
130 20170107171000 414051636008165 AC_Module_Type_C 17.8875 0.0043 245.1503 0.0495 0.007 27.3882 0.2664 1.25 59.97 0
130 20170107171000 414051637006819 AC_Module_Type_C 17.5753 0.0268 244.6653 0.2376 0.029 42.9776 0.7104 2.75 59.9808 0
130 20170107171000 414051637016710 AC_Module_Type_C 18.4668 0.0296 245.3928 0.2732 0.032 48.3247 0.6882 4.5 59.9844 0
130 20170107171000 414051637008720 AC_Module_Type_C 17.3985 0.0373 245.1503 0.3326 0.04 51.7137 0.7844 -5.5 59.97 0
130 20170107171000 414051637012898 AC_Module_Type_C 18.1023 0.0438 244.9078 0.3643 0.046 62.1067 0.7585 2.25 59.9736 0
130 20170107171000 414051636007015 AC_Module_Type_C 18.4249 0.0395 245.8777 0.3326 0.042 58.1654 0.74 1.25 59.9808 0
130 20170107171000 414051636007642 AC_Module_Type_C 19.0379 0.0389 245.3928 0.3168 0.041 53.6969 0.7844 1.25 59.988 0
130 20170107171000 414051636004672 AC_Module_Type_C 18.4797 0.0224 245.6353 0.2 0.025 34.7185 0.7326 2.75 59.9844 0
130 20170107171000 414051637006461 AC_Module_Type_C 19.6846 0.0449 245.1503 0.3782 0.047 62.0565 0.777 2.75 59.9772 0
130 20170107171000 414051637014641 AC_Module_Type_C 18.4449 0.0241 244.9078 0.1881 0.027 46.4168 0.5883 0.25 59.9916 0
130 20170107171000 414051636008956 AC_Module_Type_C 19.123 0.0444 245.1503 0.4019 0.047 60.977 0.7844 3 59.9916 0
130 20170107171000 414051636006721 AC_Module_Type_C 16.8708 0.0301 244.9078 0.2554 0.033 51.0359 0.6475 1.75 59.9808 0
130 20170107171000 414051637008121 AC_Module_Type_C 19.1139 0.0432 245.6353 0.3623 0.046 57.2993 0.8158 -0.25 59.9808 0
130 20170107171000 414051637011736 AC_Module_Type_C 17.7374 0.0406 245.514 0.3495 0.0435 58.6298 0.7603 3.875 59.9808 0
130 20170107171000 414051636005091 AC_Module_Type_C 17.8792 0.0274 245.3928 0.2386 0.0295 44.4462 0.6919 0.875 59.9808 0
130 20170107171000 414051636005516 AC_Module_Type_C 17.4729 0.0345 245.2715 0.3 0.0375 49.605 0.7714 0.625 59.9808 0
130 20170107171000 414051637006544 AC_Module_Type_C 18.6472 0.031 245.3928 0.2752 0.0335 43.5425 0.7881 3.625 59.9754 0
130 20170107171000 414051637016450 AC_Module_Type_C 19.5269 0.0455 245.7565 0.392 0.048 61.2281 0.8066 2.375 59.988 0
130 20170107171000 414051637008531 AC_Module_Type_C 17.7938 0.0433 245.1503 0.398 0.0455 60.6005 0.7788 1.5 59.9754 0
130 20170107171000 414051637006468 AC_Module_Type_C 16.8098 0.0079 245.6353 0.0821 0.0105 26.0953 0.4458 0.625 59.9826 0
130 20170107171000 414051637008016 AC_Module_Type_C 16.8933 0.0269 245.1503 0.2495 0.0295 40.6932 0.7474 -2.625 59.9772 0
130 20170107171000 414051637006465 AC_Module_Type_C 17.7867 0.0449 245.2715 0.3752 0.0475 60.2992 0.8084 4 59.9772 0
130 20170107171000 414051637007836 AC_Module_Type_C 18.6537 0.031 245.6353 0.2851 0.0335 46.4545 0.74 -0.875 59.988 0
141 20170107171000 PVS5M508095c PVS5M0400c 1 5.6946 5.5807 122.7802 122.6486 0.1709 0.5366 120.27
140 20170107171000 PVS5M508095c PVS5M0400c 125 607 0.7075 0.753 1.3836 0.5104 59.978 0
140 20170107171000 PVS5M508095p PVS5M0400p 50 0 0 0 0 1 59.978 0
102 51oeIKDhOUeah8+9ZCME
It looks like each of my panels are reporting on the 130 lines, so I can break those out into my own DB / web portal. I'm having a hard time deciphering the rest of the lines, though. I believe the 1st number (ie. "18.5466" in the first 130 line) is the Watts, the 2nd number (ie. "0.0417") is the kWh, but those are mostly guesses. I get lost after that as to what the rest of the values are.Leave a comment:
-
During my decoupled post-processing, I just append lines to flat files. Each file is a .csv file with columns for:
- date/time
- consumption (kW)
- production (kW)
- lifetime net (kWh) # this is basically the raw value reported by the 140 message
- lifetime production # just as this is the raw value reported by the 130 message
I keep the .csv files per day, as well as summaries for daily, monthly, and yearly. I keep a directory structure mirroring the dates, i.e.:
2016/12/23.csv
2016/12/daily.csv # contains summary total entries for each day of that month
2016/monthly.csv # contains summary total entries for each month of that year
yearly.csv # contains summary total entries for each year
Because I keep the daily/monthly/yearly, I detect when I pass over midnight, and when I do, I sum up the data for the day and append to the daily. If I'm also passing over a month-end, then I sum up the daily.csv, and append the result to the corresponding monthly.csv. If I'm also passing into a new year, I sum up monthly.csv, and append the result to the corresponding yearly.csv. I could simply calculate all of that on the fly, but hey, I'm running my server on a raspberry pi, so it's better to calculate in advance once, and cache the result, rather than re-calculating each time I need the data.
And yes, a db probably is a more efficient way to store the data, but this was easier at the time, and is human-readable, resilient against corruption, and text formats will outlive db formats...Last edited by robillard; 12-24-2016, 11:14 AM.Leave a comment:
-
That's great info! Thanks! Now to brush up on my Perl.... any chance you'd share your processing script too? Also, I see where you would write to a file, but not what you are writing. I might modify to write to a mySQL DB eventually, but I'm fine with flat files initially.Leave a comment:
-
Hey robillard - any chance you'd be willing to share your code? I'm impressed by what I'm reading you've done in this thread and I'm interested in doing the same. Would save me some time to have a starting place rather than reverse engineering everything like it seems you've already done. Please drop me a line at ehampshire <at> gmail. Thanks!
I cannot easily extract my processing code from the overall script to give you a ready-made solution, because of how I (mis-)architected my solution, as I've de-coupled the traffic sniffing from the data processing, but I'll give a shot at the flow below...
Note that you'll have to run the script sudo, since it needs to put the interface into promiscuous mode. This is one of the (several) reasons why I de-coupled the traffic sniffer from the data processing: I didn't want my entire script running sudo...
So once you've got the traffic echoing to a port on your machine, I'm doing something like this to capture the packets (error handling removed for readability):
Code:use Net::Pcap; use NetPacket::Ethernet; use NetPacket::IP; use NetPacket::TCP; use NetPacket::UDP; # setup pcap filter, so we see only the traffic we want my $srcmacaddr = undef; # add the MAC address of your SunPower supervisor, if you find there is too much traffic without it my $filterbysrcmacaddr = defined($srcmacaddr) ? (" && ether src " . $srcmacaddr) : ""; my $filtertext = "ip && tcp" . " && dst net 204.194.111.66 && dst port 80" . $filterbysrcmacaddr; # find the default interface (or you can set enif to a specific interface, if your sniff traffic comes to a NIC other than the default my $enif = Net::Pcap::lookupdev(\$err); my $err; my $pcap = Net::Pcap::open_live($enif, 65535, 1, 512, \$err); my $filter; Net::Pcap::compile($pcap, \$filter, $filtertext, 1, 0); Net::Pcap::setfilter($pcap, $filter); Net::Pcap::loop($pcap, -1, \&packet_callback, ""); Net::Pcap::close($pcap);
Code:sub packet_callback { my ($ignorerefcon, $hdr, $pkt) = @_; my $ethpkt = NetPacket::Ethernet->decode($pkt); my $ethprot = $ethpkt->{"type"}; my $ethdata = $ethpkt->{"data"}; if ($ethprot == NetPacket::Ethernet::ETH_TYPE_IP) { my $ippkt = NetPacket::IP->decode($ethdata); my $ipprot = $ippkt->{"proto"}; my $ipdata = $ippkt->{"data"}; if ($ipprot == NetPacket::IP::IP_PROTO_TCP) { my $tcpippkt = ($ipprot == NetPacket::IP::IP_PROTO_TCP) ? NetPacket::TCP->decode($ipdata) : NetPacket::UDP->decode($ipdata); my $data = $tcpippkt->{"data"}; process_packet_payload($data); } } }
Code:sub process_packet_payload { my $data = $_[0]; my @lines = split(/\n/, $data); foreach my $line (@lines) { chomp($line); if (($line =~ /^(140)\t(2016[0-3][0-9][0-9]{2}[0-9]{2}[0-9]{2}[0-9]{2})\t[0-9]+\t[^\s]+\t100\t([-+]?[0-9]*\.?[0-9]+)\t/) || ($line =~ /^(130)\t(2016[0-3][0-9][0-9]{2}[0-9]{2}[0-9]{2}[0-9]{2})\t[0-9]+\t[^\s]+\t\t([-+]?[0-9]*\.?[0-9]+)\t/)) { my $msg = $1; my $datetime = $2; my $value = $3; if ($msg == 140) { # this is a net metering message, and $value is net metering value in (IIRC) W averaged over the 5-minute interval # consumption = (corresponding production) + net } else { # this is a production message, and $value is a production valuein (IIRC) W averaged over the 5-minute interval } } } }
Because my process of analyzing the information is decoupled from the actual collection of the data, all I do in the process_packet_payload function (i.e. at scan time) is to append the data to a (rotating) file on disk. Then my decoupled data collection code comes along and scans that data for matching entries. It can thus also calculate deltas from the last collected data sets without having to maintain state in the script (i.e. "$lastprod" and "$lastnet", or more likely a hash of recent prods and nets, in order to deal with discontinuities or out-of-order delivery). Each time my data collection code runs, it determine what the last stable time was (for which we've collected both valid production and net (and consumption) information), and see if it can find values for the next time slot for both production and net, and if so, it can record those values and those become the last stable collected time and values.
I hope this helps...
(And the formatting for the code does not seem to be coming through properly, despite me using CODE tags, so I apologized for that as well...)Leave a comment:
Leave a comment: