MeterN and Raspberry Pi with a pulse power meter

tassheloff
Posts: 19
Joined: Tue Apr 22, 2014 6:37 pm

Re: MeterN and Raspberry Pi with a impulse power meter

Post by tassheloff » Tue Aug 26, 2014 10:15 am

I wrote this Client/Server software in java. Hoping be useful.
Of course you have to install java and know how to compile.

Run Server in background.

To call LIVE java -cp /PATH/ pv.PoolClient -c live -um W -cn COUNTNUM
To call CUMULATIVE pooler elect , changing in pooler.php in this way

Code: Select all

if ($argv[1] == 'elect') {
    $metnum  = COUNTNUM;
    $cmd = 'java -cp PATH pv.PoolClient -c period -um Wh -cn $metnum';
}

FILE -> PoolServer.java
/**
  * POOL SERVER for METERN
  * USAGE: run in background pv.poolserver, launch 
  * pv.poolClient or pv.poolClient -c live to retrive power live value 
  * pv.poolClient -c period to retrive values consumed
  * Libraries : 
  * The P4J Project http://pi4j.com/
  * pi4j-core.jar
  * @author Fabio Raudino
  * @version 1.0, 26/04/2014
*/

package pv;

import com.pi4j.io.gpio.*;
import com.pi4j.io.gpio.event.*;
import java.io.*;
import java.net.*;
import java.text.DecimalFormat;

public class PoolServer {

	// create gpio controller instance
	final GpioController gpio = GpioFactory.getInstance();
	GpioPinDigitalInput consumi;
	double 				pCounter = 0.0;
	double 				eCounter = 0.0;
	final boolean 		debug 	= false;
	long 				before,
						now;		
	double 				currPow		= 0.0,
						diff		= 0.0,
						wattxpulse	= 0.5;
	DecimalFormat 		df 		= new DecimalFormat("###");


	public class GPIOListener1 implements GpioPinListenerDigital {
		@Override
		public void handleGpioPinDigitalStateChangeEvent(
				GpioPinDigitalStateChangeEvent event) {
			if (event.getState() == PinState.HIGH) {
				//Every 2 pulses, 1 W
				eCounter += wattxpulse;
				pCounter += wattxpulse;
				now = System.nanoTime();
				diff = (now - before)/1000000000.0; //in seconds
				currPow = pCounter / diff * 3600.0; //Watt per Hours
 			}

		}
	}

	public PoolServer(int pinNo, double wxp) {
		super();
		Pin pin;
		switch (pinNo) {
			case 2:pin = RaspiPin.GPIO_02;break;
			case 3:pin = RaspiPin.GPIO_03;break;
			case 4:pin = RaspiPin.GPIO_04;break;
			case 5:pin = RaspiPin.GPIO_05;break;
			case 6:pin = RaspiPin.GPIO_06;break;
			case 7:pin = RaspiPin.GPIO_07;break;
			case 8:pin = RaspiPin.GPIO_08;break;
			case 9:pin = RaspiPin.GPIO_09;break;
			case 10:pin = RaspiPin.GPIO_10;break;
			case 11:pin = RaspiPin.GPIO_11;break;
			case 12:pin = RaspiPin.GPIO_12;break;
			case 13:pin = RaspiPin.GPIO_13;break;
			case 14:pin = RaspiPin.GPIO_14;break;
			case 15:pin = RaspiPin.GPIO_15;break;
			case 16:pin = RaspiPin.GPIO_16;break;
			case 17:pin = RaspiPin.GPIO_17;break;
			case 18:pin = RaspiPin.GPIO_18;break;
			case 19:pin = RaspiPin.GPIO_19;break;
			case 20:pin = RaspiPin.GPIO_20;break;
			default:pin = RaspiPin.GPIO_01; break;
		}
		wattxpulse = wxp;
		consumi = gpio.provisionDigitalInputPin(pin, 							// PIN NUMBER
												"consumi", 						// PIN FRIENDLY NAME (optional)
												PinPullResistance.PULL_DOWN); 	// PIN RESISTANCE (optional)
		consumi.setShutdownOptions(true);
		before = now = System.nanoTime();
		consumi.addListener(new GPIOListener1());
	}

	void shutdown() {
		gpio.shutdown();
	} 

	String ePowerValue() {
		double power=currPow;
		pCounter = 0;
		before = now;
		return df.format(power);		
		
	}

	String eEnergyValue() {		
		double energy=eCounter;
		eCounter = 0;
		return 	df.format(energy);
	}

	String executeCommand(String command){
		if (command.equalsIgnoreCase("live")) {
			return ePowerValue();
		} else if (command.equalsIgnoreCase("period")) {
			return eEnergyValue();
		} else {
			return "Not Implemented";
		}
	}
	
	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] argv) throws IOException {
		Socket connectionSocket = null;
		boolean forever = true;
		DataOutputStream outToClient;
		String returnString = "";
		int portNo = 6789;
		int pinNo = 1;
		double wxp=0.5;
		for (int i = 0; i < argv.length; i=i+2) {
			if (argv[i].equalsIgnoreCase("-h")){
				System.out.println(
						"USAGE:\n" +
						"poolServer -port|-p xxx\n" +
						"-gpiopin|-g xx\n" +
						"-pulsevalue|-pv xx.xx\n"+
						"-h show this help\n" +
						"(default port 6789, pin 1, pulsevalue=0.5)\n");
				System.exit(0);
			}else if ((argv[i].equalsIgnoreCase("-pulsevalue"))||(argv[i].equalsIgnoreCase("-pv"))){
				wxp = Double.parseDouble(argv[i+1]);
			}else if ((argv[i].equalsIgnoreCase("-port"))||(argv[i].equalsIgnoreCase("-p"))){
				portNo = Integer.parseInt(argv[i+1]);
			}else if ((argv[i].equalsIgnoreCase("-gpiopin"))||(argv[i].equalsIgnoreCase("-g"))){
				pinNo = Integer.parseInt(argv[i+1]);
			}
		}		 
		ServerSocket socket = new ServerSocket(portNo);
		PoolServer sample = new PoolServer(pinNo,wxp);
		do {
			connectionSocket = socket.accept();
			BufferedReader inFromClient = new BufferedReader(
					new InputStreamReader(connectionSocket.getInputStream()));
			returnString = sample.executeCommand(inFromClient.readLine());
			outToClient = new DataOutputStream(
					connectionSocket.getOutputStream());
			outToClient.writeBytes(returnString);
			outToClient.flush();
			connectionSocket.close();

		} while (forever == true);
		sample.shutdown();
		socket.close();
	}
}

FILE -> PoolClient.java
/**
  * POOL CLIENT for METERN
  * USAGE: launch 
  * pv.poolClient or pv.poolClient -c live to retrive power live value 
  * pv.poolClient -c period to retrive values consumed
  * Libraries : 
  * The P4J Project http://pi4j.com/pi4j-core.jar
  * 
  * @author Fabio Raudino
  * @version 1.0, 26/04/2014
*/

package pv;

import java.io.*; 
import java.net.*;

public class PoolClient {
	static final boolean debug=true;
	public static void main(String argv[]) throws Exception  {
		int portNo = 6789;
		String countNo = "1";
		String unit = "W";
		String command = "live";
		for (int i = 0; i < argv.length; i=i+2) {
			if (argv[i].equalsIgnoreCase("-h")){
				System.out.println(
						"USAGE:\n " +
						"poolClient -command|-c live|period (default live)\n" +
						"-port|-p xxx (connection port default 6789)\n" +
						"-counter|-cn x  (counter no default 1)\n" +
						"-um xxx  (Units default W)\n"  +
						"-h show this help\n"+
						"(default command live, port 6789, counter no 1, units W) ");
				System.exit(0);
			}else if ((argv[i].equalsIgnoreCase("-port"))||(argv[i].equalsIgnoreCase("-p"))){
				portNo = Integer.parseInt(argv[i+1]);
			}else if ((argv[i].equalsIgnoreCase("-command"))||(argv[i].equalsIgnoreCase("-c"))){
				command = argv[i+1];
			}else if ((argv[i].equalsIgnoreCase("-counter"))||(argv[i].equalsIgnoreCase("-cn"))){
				countNo = argv[i+1];
			}else if (argv[i].equalsIgnoreCase("-um")){
				unit = argv[i+1];
			}
		}		 
		Socket clientSocket = new Socket("localhost", portNo);
		DataOutputStream outToServer= new DataOutputStream(clientSocket.getOutputStream());
		BufferedReader inFromServer= new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
		outToServer.writeBytes(command + '\n');   
		outToServer.flush();
		System.out.println(countNo+"("+inFromServer.readLine()+"*"+unit+")");
		System.out.flush();
		clientSocket.close();
	 }
}

jeanmarc
Posts: 1832
Joined: Thu Aug 29, 2013 7:16 am

Re: MeterN and Raspberry Pi with a impulse power meter

Post by jeanmarc » Tue Aug 26, 2014 10:28 am

Thanks for the feedback 8-)

acfnews
Posts: 35
Joined: Mon Jan 05, 2015 6:58 pm

Re: MeterN and Raspberry Pi with a impulse power meter

Post by acfnews » Wed Jan 07, 2015 12:46 am

Hi All

Based on the following code : https://github.com/sanderjo/GPIO-counter, i am working on adapting this code to work with metern.

I am not sure about the exact results which metern is expecting.
Should the normal STDOUT of the script be like :

pi@raspberrypi /usr/share/nginx/www/metern/scripts $ sudo /usr/share/nginx/www/metern/scripts/gpio-counter.py 23 /mnt/data_tmpfs
1(137*W)
1(138*W)
1(139*W)
1(140*W)
1(141*W)
1(142*W)
1(143*W)

?

Many thanks,

ron

jeanmarc
Posts: 1832
Joined: Thu Aug 29, 2013 7:16 am

Re: MeterN and Raspberry Pi with a impulse power meter

Post by jeanmarc » Wed Jan 07, 2015 8:34 am

Hi,
Thanks for your work. The format should be a single line output like 1(137*W)

acfnews
Posts: 35
Joined: Mon Jan 05, 2015 6:58 pm

Re: MeterN and Raspberry Pi with a impulse power meter

Post by acfnews » Fri Jan 09, 2015 8:55 pm

Hi Jean-Marc et all,

Since a few weeks i'm playing with 123solar + metern.
123solar is working fine with a RS485 interface, and my solar data is processed correctly.

Next to that, i am trying to get a S0 interface working for monitoring my own consumption. The S0 meter is connected directly to the GPIO #23 on my RPI.
I use 1 single script at this moment to reads the values, create output (based on https://github.com/sanderjo/GPIO-counter).
The script i use, is started with 'sudo' to provide access to the GPIO values/device files for the moment.
The script has no output during runtime, but places it's data in a temp file.

Now i have some questions, which i cannot clarify from the example scripts :

- should the 'daemon' script used in the 'main pooling' part provide any ouptut, or should it only write to a temp file (on tmpfs)
- should this daemon run 'forever' until the metern is stopped, or only 5 minutes ?
- should it suffice that this temp file has all the data : Electricity, Gas and Water ?
- should the layout be like below, or more like the original P1 standard ?

Current output:
1(12407*W)

Or should it look like:
1-23:1.8.0(12407*W)
!



My current code :

Code: Select all

#!/usr/bin/python

import RPi.GPIO as GPIO
import datetime
import sys
import signal
import psutil

############################################################################################################
############################################################################################################

def printusage(progname):
        print progname + ' <gpio-pin-number> <filename> <file available after reboot>'
        print 'Example usage: ' 
	print progname + ' 23 /path/to/mylogfile /path/fo/otherfile'
	sys.exit(-1)

def signal_handler(signal, frame):
	GPIO.cleanup()
	keepvalue(keepfile,counter)
        sys.exit(0)

def readvalue(myworkfile):
	try:
		f = open(myworkfile, 'ab+')		# open for reading. If it does not exist, create it
		value = int(f.readline().rstrip())	# read the first line; it should be an integer value
	except:
		value = 0
	f.close()
	return value

def writevalue(myworkfile,value):
	f = open(myworkfile, 'w')

        #according to standard, and other forums complete syntax
	#f.write(('1-'+ str(mygpiopin)+ ':'+  '1.8.0('+ str(counter)+ '*W)'+ '\n'+ '!'))

        #but metern requires 1(12345.123*W)
	f.write(('1('+ str(counter)+ '*W)'+ '\n'))

	#f.write((str(value)+ '\n'))
	#f.write((str(datetime.datetime.now())+ '\n'))
	f.close()	

def keepvalue(myworkfile,value):
	f = open(myworkfile, 'w')

        #deze waarde moet naar de file welke na reboot blijft bestaan, en tijdens 1e opstart wordt uitgelezen
	f.write((str(value)+ '\n'))
	f.write((str(datetime.datetime.now())+ '\n'))
	f.close()	

############################################################################################################
############################################################################################################

######### Initialization

#### get input parameters:

try:
	mygpiopin = int(sys.argv[1])
	logfile = sys.argv[2]
	keepfile = sys.argv[3]
        errorfile = sys.argv[2]+'.err'
except:
	printusage(sys.argv[0])


#### check for duplicate process
PROCNAME='gpio-counter.py'
procnum=0

for proc in psutil.process_iter():
    if proc.name == PROCNAME:
        if procnum >= 1:
	    keepvalue(errorfile,'ERROR')
            sys.exit(0)
        procnum=+1


#### setup

GPIO.setmode(GPIO.BCM)
GPIO.setup(mygpiopin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)

signal.signal(signal.SIGINT, signal_handler)	# SIGINT = interrupt by CTRL-C

counter=readvalue(keepfile) 

########## Main Loop 

while True:
	# wait for pin going up
	GPIO.wait_for_edge(mygpiopin, GPIO.RISING)

	counter=counter+1

	writevalue(logfile,counter)
	#print '1('+ str(counter)+ '*W)'

	# and wait for pin going down
	GPIO.wait_for_edge(mygpiopin, GPIO.FALLING)

############################################################################################################
############################################################################################################


jeanmarc
Posts: 1832
Joined: Thu Aug 29, 2013 7:16 am

Re: MeterN and Raspberry Pi with a impulse power meter

Post by jeanmarc » Fri Jan 09, 2015 9:30 pm

Hi,

- should the 'daemon' script used in the 'main pooling' part provide any ouptut, or should it only write to a temp file (on tmpfs)
The main output is to retieve a quantity (Wh). The daemon i use if for live value (power)

- should this daemon run 'forever' until the metern is stopped, or only 5 minutes ?
It live for a 5 min periode, it is stopped to retrieve quantity value

- should it suffice that this temp file has all the data : Electricity, Gas and Water ?
Yes i do that, i use a simple "grep" to get the value

- should the layout be like below, or more like the original P1 standard ?
You may use the layout you wish

Your output is correct but you run it in a terminal as root, beware the tmpfs is different from the 'http' user !

Please, read carefully the README in poolmeters example. I've spend hours to get a correct metering, good luck ;)

acfnews
Posts: 35
Joined: Mon Jan 05, 2015 6:58 pm

Re: MeterN and Raspberry Pi with a impulse power meter

Post by acfnews » Sun Jan 11, 2015 10:41 pm

Hi All,

I have (for this moment at least), the gpio_counter running as a seperate 'daemon', and the output of this 'daemon' is readable by metern.

This works quite good, but i need to work on accidental reboots. This has al to do with the tempfs filesystem.
Currently the latest value is only written to normal filesystem when SIGINT (kill -2) is presented to the script.
Maybe write it each hour to normal filesystem, or something like that ?


Grtz,


ron

gdrak0
Posts: 8
Joined: Thu Jan 21, 2016 9:41 pm

Re: MeterN and Raspberry Pi with a impulse power meter

Post by gdrak0 » Wed Jan 27, 2016 2:00 pm

Hi
I try to use the py script you have above but without success..
if I run the original script from sanderjo see normally pulses..

root@raspberrypi:~/GPIO-counter# python gpio-counter.py 23 /var/log/gpio23-counter.log debug
Verbose is On
GPIO is 23
Logfile is /var/log/gpio23-counter.log
Current value is 321
New value is 322
New value is 323
New value is 324
New value is 325
New value is 326
New value is 327

And with yours I have this in log file ..
1(66*W)
and nothing in metern app
Is there something more I should know or escapes me ??
Thank you in advance

acfnews
Posts: 35
Joined: Mon Jan 05, 2015 6:58 pm

Re: MeterN and Raspberry Pi with a impulse power meter

Post by acfnews » Sat Jan 30, 2016 2:11 pm

Hi Gdrak0,

Not sure if you have the latest script, but there are some things to consider :
- 2 output files , one for preservation after a reboot, the other on a tempfs filesystem to prevent CF wear,
- input reading in metern

In my metern config i have 1 sensor configured, which is simply reading the file from above (on the tempfs), with these settings :

Code: Select all

pi@raspberrypi /usr/share/nginx/www/metern/config $ more config_met1.php 
<?php
if(!defined('checkaccess')){die('Direct access not permitted');}

// ### CONFIG FOR METER #1
    
$METNAME1='Elect';
$TYPE1='Elect';
$PROD1=2;
$PHASE1=1;
$SKIPMONITORING1=false;
$ID1='1';
$COMMAND1='more /mnt/data_tmpfs/metern | grep W';
$UNIT1='Wh';
$PRECI1=0;
$PASSO1=1000000;    
$COLOR1='AA4643';
$PRICE1=0.218;
$LID1='1';
$LIVEPOOL1=0;
$LIVECOMMAND1='';    
$LIVEUNIT1='W';
$EMAIL1='youremail-here';
$REPORT1='monthly';
$PUSHO1=false;
$POUKEY1='yourkey';
$WARNCONSOD1=15000;
?>
pi@raspberrypi /usr/share/nginx/www/metern/config $ 




my current script, just to be sure :

Code: Select all

#!/usr/bin/python

import RPi.GPIO as GPIO
import datetime
import sys
import signal
import psutil



def printusage(progname):
	print progname + ' <gpio-pin-number> <filename> <file available after reboot>'
	print 'Example usage: ' 
	print progname + ' 23 /path/to/mylogfile /path/fo/otherfile'
	sys.exit(-1)

def signal_handler(signal, frame):
	GPIO.cleanup()
	keepvalue(keepfile,counter)
	sys.exit(0)

def readvalue(myworkfile):
	try:
		f = open(myworkfile, 'ab+')
		value = int(f.readline().rstrip())
	except:
		value = 0
	f.close()
	return value

def writevalue(myworkfile,value):
	f = open(myworkfile, 'w')
	#1(12555*W)
	f.write(('1('+ str(counter)+ '*Wh)'+ '\n'))
	f.close()	

def keepvalue(myworkfile,value):
	f = open(myworkfile, 'w')
	f.write((str(value)+ '\n'))
	f.write((str(datetime.datetime.now())+ '\n'))
	f.close()	



######### Initialization

#### get input parameters:

try:
	mygpiopin = int(sys.argv[1])
	logfile = sys.argv[2]
	keepfile = sys.argv[3]
	errorfile = sys.argv[2]+'.err'
except:
	printusage(sys.argv[0])


#### check for duplicate process
PROCNAME='gpio-counter.py'
procnum=0

for proc in psutil.process_iter():
	if proc.name == PROCNAME:
		if procnum >= 1:
			keepvalue(errorfile,'ERROR, process already running,exiting...')
			sys.exit(0)
		procnum+=1


#### setup

GPIO.setmode(GPIO.BCM)
GPIO.setup(mygpiopin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)

signal.signal(signal.SIGINT, signal_handler)

writevar=0
counter=readvalue(keepfile)

########## Main Loop

while True:
	# wait for pin going up
	GPIO.wait_for_edge(mygpiopin, GPIO.RISING)

	counter+=1
	writevar+=1

	writevalue(logfile,counter)

	if writevar >= 10:
		keepvalue(keepfile,counter)
		writevar=0

	# and wait for pin going down
	GPIO.wait_for_edge(mygpiopin, GPIO.FALLING)
	

gdrak0
Posts: 8
Joined: Thu Jan 21, 2016 9:41 pm

Re: MeterN and Raspberry Pi with a impulse power meter

Post by gdrak0 » Wed Feb 17, 2016 12:33 pm

Hi pd1acf

Thank you for your help it's work perfect..
But now my problem is how i can adjust the metern to know that 4000 impulse is 1 kWh ?
Thank you George

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest