Page 1 of 1

Reading meter using PHP

Posted: Mon Nov 26, 2012 7:56 pm
by rcarsey
Since I do a lot of PHP programming, it seemed only natural to use PHP to query the meter for data.

Below is a snipit of code which you can use to get the data from the meter... of course your PHP must have the extensions for snmp and tcp -- which i think come standard.

Code: Select all

<?php

function get_meter_data($meter_number, $remote_address, $remote_port) {
	//$meter_number is the meters serial number. leading 0s not required.
	//$remote_address is the IP address of the ethernet-RS485 converter
	//$remote_port is the TCP port number the converter is listening to (50000 in my case)

	//We do not check the checksum - I'm lazy.  Probably should. Running for 8 months, querying
	//once per minute..I've encountered one or two bad results from the meter.


	/*  Connect and get response */
	// fix up the meter number with the correct amount of leading zeros
	$meter_number = str_pad($meter_number, 12, "0", STR_PAD_LEFT);
	//create a new socket and make sure it worked
	$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
	if ($socket === false)
		echo "socket_create() failed: reason: ".socket_strerror(socket_last_error())."\n";
	// connect to the meter and check to make sure we connected
	$res = socket_connect($socket, $remote_address, $remote_port);
	if ($res === false)
        {
                echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
                echo "Aborting";
                exit;
        }

	//send query string to the meter.  e.g.  /?000000000123!  then a CRLF
	socket_write($socket, "/?" . $meter_number . "!\r\n");
	//Receive a response of 255 bytes.  Wait till we have all of them!
	$res = socket_recv($socket, $response, 255, MSG_WAITALL);
	if ($res === false)
        	echo "socket_recv() failed; reason: " . socket_strerror(socket_last_error($socket)) . "\n";

	// no idea what this is about. EKM Meter software sends it, so we will too. Then close the connection.
	$message = "\x0a\x03\x32\x3d";
	socket_write($socket, $message);
	socket_close($socket);

	// Now the fun stuff.  parsing through the 255 byte response
	$meter_number = substr($response,4,12);
	$meter_model = substr($response,1,2); //non-ASCII
	$meter_firmware = substr($response,3,1); //non-ASCII
	$KWh_total = substr($response, 16, 8) / 10;
	$L1_KWh = substr($response, 24, 8) / 10;
	$L2_KWh = substr($response, 32, 8) / 10;
	$L3_KWh = substr($response, 40, 8) / 10;
	$L4_KWh = substr($response, 48, 8) / 10;
	$ReverseKWh_total = substr($response, 56, 8) / 10;
	$L1_ReverseKWh = substr($response, 64, 8) / 10;
	$L2_ReverseKWh = substr($response, 72, 8) / 10;
	$L3_ReverseKWh = substr($response, 80, 8) / 10;
	$L4_ReverseKWh = substr($response, 88, 8) / 10;
	$L1_volt = substr($response,96, 4) / 10 ;
	$L2_volt = substr($response,100, 4) / 10;
	$L3_volt = substr($response,104, 4) / 10 ;
	$L1_amp = substr($response,108, 5) / 10;
	$L2_amp = substr($response,113, 5) / 10;
	$L3_amp = substr($response,118, 5) / 10;
	$L1_watt = substr($response,123, 7) / 1;
	$L2_watt = substr($response,130, 7) / 1;
	$L3_watt = substr($response,137, 7) / 1;
	$watt_total = substr($response,144, 7) / 1;
	$L1_pf = substr($response,151, 4);
	$L2_pf = substr($response,155, 4);
	$L3_pf = substr($response,159, 4);
	$max_demand = substr($response, 163,7) / 1;
	$demand_period = substr($response, 170,1); //not sure of units
	$meter_date = "20" . substr($response, 172,2) . "-" .  substr($response, 174,2) . "-" .  substr($response, 176,2) . " " .  substr($response, 180,2)  . ":" .  substr($response, 182,2) .":" .  substr($response, 184,2);
	$CT_rating = substr($response, 86,4);
	$pulse1_count = substr($response, 163,8) / 1;
	$pulse2_count =  substr($response, 171,8) / 1;
	$pulse3_count =  substr($response, 179,8) / 1;
	$pulse1_ratio =  substr($response, 187,4) / 1;
	$pulse2_ratio =  substr($response, 191,4) / 1;
	$pulse3_ratio =  substr($response, 195,4) / 1;
	$pulse_HL =  substr($response, 202,3) ;

	// do whatever you want with the data.
	print "Meter Number: " . $meter_number . "\r\n";
	print "KWh Total: " . $KWh_total. "\r\n";
	print "Reverse KWh Total: " . $ReverseKWh_total. "\r\n";
	print "L1 V: " .$L1_volt. "\r\n";
	print "L2 V: " . $L2_volt. "\r\n";
	print "L3 V: " . $L3_volt. "\r\n";
	print "L1 A: " . $L1_amp. "\r\n";
	print "L2 A: " . $L2_amp. "\r\n";
	print "L3 A: " . $L3_amp. "\r\n";
	print "L1 W: " . $L1_watt. "\r\n";
	print "L2 W: " . $L2_watt. "\r\n";
	print "L3 W: " . $L3_watt. "\r\n";
	print "Watt Total: " . $watt_total. "\r\n";
	print "L1 Pf: " . $L1_pf. "\r\n";
	print "L2 Pf: " . $L2_pf. "\r\n";
	print "L3 Pf: " . $L3_pf. "\r\n";
	print "Max Demand: " . $max_demand. "\r\n";
	print "Meter Date: " . $meter_date. "\r\n";


} //end of function

/* MAIN  */

get_meter_data(11123,"10.5.2.17",50000);

?>

Re: Reading meter using PHP

Posted: Wed Nov 28, 2012 4:29 pm
by Jameson
Hey this is VERY cool ;) Thank you so much for sharing! We love this type of collaboration.

Can you give us a hand on how to set it up? We have tried to host the code on our web server: http://documents.ekmmetering.com/EKM-php-reader.php

When you go to this URL you get:
Parse error: syntax error, unexpected T_STRING in /home/dbrouwer/public_html/documents/EKM-php-reader.php on line 4
We took the text of your code (changed the IP address and port to on of ours here) and put it in a .php file. We then posted this to our web server. Obviously we seem to be missing something about how this is supposed to work.

Thanks for any insights you have.

Regards,

Re: Reading meter using PHP

Posted: Mon Dec 31, 2012 3:05 pm
by LBJ
Thanks rcarsey, this is great, especially all of that parsing! Jameson, that sounds like it could be a fairly simple error - if you can post the code (or send privately) I can try to help debug.

Note also to anyone using this code, the tcp rcarsey's referring to is the sockets (php_sockets.dll or .so) extension.

Re: Reading meter using PHP

Posted: Mon Dec 31, 2012 3:33 pm
by Jameson
LBJ,

Yes, you are right, this is great. Very nice of rcarsey to put this together.

To be honest I was not certain what I was doing. I just took the code (word for word) that is posted here by rcarsey and pasted it into a file that I named "ekm-php-reader.php". I changed the IP address, port, and meter number from this section: "get_meter_data(11123,"10.5.2.17",50000)". Then I put it in a web folder and tried to open it.

So in short I have the same code that is pasted here (above).

If you do get this working, it would be great if you could send us a link to see it run.

Thanks!

Re: Reading meter using PHP

Posted: Mon Dec 31, 2012 7:06 pm
by LBJ
Hmm... it sounds like maybe there was a text encoding issue involving the text editor you were using? So the copy/paste from the website introduced unwanted characters? I was able to take the code straight from this page with no problems (using Crimson Editor). I'd love to share but unfortunately the code is running on a local server that's not set up for outside access at this time.

I'm still working out a few other issues with the script that are probably server-dependent. We're running the test server on a windows machine, so timeouts need to be accounted for, and parsing of the return string is slightly off (probably due to os-dependent socket handling discrepancies as well). If the OP is still around, I'd be interested to know what their setup is - php version, apache/iis version, etc.