Directly connecting to Optical Pulse Counter with RPi?

Thanks Paul,

If I want to sync to my current meter reading, say its 40644 kwH, would I set pulse_id =

{1:40644000,2:0}

My node is configured as:

[[18]]
nodename = pulsecounter
[[[rx]]]
    names = pulsecnt1, pulsecnt2
    scales = 1, 1
    units = Wh, Wh

I’m testing the script right now and it doesn’t always increment the pulse_id value:

1520357220.42 18 40664020 0
1520357277.69 18 40664020 0

I can understand why you might want to do this, but if you must, then consider trying a virtual feed, the data storage in emoncms is in 32bit floats, this equates to around 7 digits of accuracy so the next increment to 40664020 0 will be 40664030 0 and depending on how your processing is set up, you may need to see that whole jump in one update, it maybe that every update that doesn’t reach that increment is ignored/lost, so effectively it might only be registering use that is over 10 Wh in any one interval, that could be a large portion of your usage.

I want to track the actual meter reading as closely as possible (i need to report it monthly manually to earn my solar renewable energy credits for generation).

Is there a better way to do this?

Basically the datatype you are using (phpfina or phptimeseries) cannot offer you the scope and resolution to do what you want. You need to store the change in pulsecount and then add the starting meter reading back in afterwards, either by manually calculating it each month or by setting up a virtual feeds so that you are recording the “change in pulse count” but displaying the “meter tracking” because the virtual feed adds the starting reading to every value when graphed or displayed.

Alternatively you could look at other storage engines, but there may be other consequences, eg the apps module only works with phpfina (without hacking).

TBH, if you need to be submitting “meter readings” then that’s what you should be doing “reading the meter”, I’m pretty familiar with all this stuff to the point it’s pretty predictable, but if I submit a meter reading, I read the meter.

If the meter isn’t electronically “readable” eg registers accessible via modbus or infrared etc, and it’s not easily accessed, maybe you should be looking at a remote camera or cctv so you can remotely take a peek at the meter once an month.

Hi Paul, I’m struggling to find more info on the connections between the optical sensors and the GPIO pins. I’ve made my own surface mount ethernet sockets with jumper wires connected to each punch down. Looking at the RJ45 on the optical sensor it looks like there are connections to Pins 1,2, 5 and 6.

Sorry to be a pain, could you please advise what GPIO you have connected 1,2,5 and 6 to?
I’ve searched through other posts and the archive and can’t seem to find any schematics or guides for this.

Thanks

Mike

There are in fact only 3 active connections to the optical sensor. 2 & 5 are +5V & GND respectively, 6 is the output. It is not in fact a pulse, in that there is no control of the shape of the output using (say) a Schmitt trigger. I am measuring pin 6 at within 3 mV of GND in darkness and 35 mV of VCC in reasonably bright light. The output goes to an acceptable ‘high’ state long before the LED on the rear of the sensor lights up.

As Robert explains there is only really one “interesting” connection per optical sensor, that one wire can be connected to almost any gpio pin as long as you edit the sketch to use that gpio pin.

In my example script there are 2 gpio pins defined as this script happened to be used with 2 optical sensors.

The pins I used were as follows (physical pin numbers used rather than BCM/GPIO numbering for RPI GPIO)

optical sensor RPi
1 (nc)
2 (vcc) Pin 17 (vcc)
3 (nc)
4 (nc)
5 (gnd) Pin 9 (gnd)
6 (output) Pin 13 or 15
7 (nc)
8 (nc)

Note I used 3.3V rather than 5V to power the sensor as the Pi gpio input pins are not 5V tolerant and the sensor is designed to work at both 3.3V and 5V.

I’ve recently found this script and put it to use. I’ve also been on a mission to reduce CPU use and found the script uses 100% CPU. The problem was the way the while loop was working.

The while loop at the end is the main difference.

import RPi.GPIO as GPIO
import time
import socket

# a "pulse" is 1 unit of measurement use emonHub scales and unit to define
# eg if 100 pulses is 1m3, ie 0.01m3 each then emonHub should use scale = 0.01 and unit = m3
# Therefore "pulse_id" becomes an accumulating "total used" and should follow the meter reading

nodeid = 18
valueid = 1
bounce = 1
interval = 5
lastsend = 0
host = "localhost" #emonbase1"
port = 50012
pulse_pin1 = 21
pulse_pin2 = 15

pulse_id = {1:0,2:0}

def eventHandler1(channel):
    processpulse(1,GPIO.input(channel))
def eventHandler2(channel):
    processpulse(2,GPIO.input(channel))


#    print("event")

def processpulse(channel,status):
    global pulse_id
    global frame
    global lastsend
    if status: #GPIO.input(channel):
        pulse_id[channel] += 1
        print("Channel "+ str(channel) + "  on : " + str(pulse_id[channel]))
    else:
        print("Channel "+ str(channel) + " off : " + str(pulse_id[channel]))

    t = time.time()
    f = ' '.join((str(t), str(nodeid), str(pulse_id[1]), str(pulse_id[2])))
    if t > (lastsend + interval):
        lastsend = t
        print f
        send(f)


def send(f):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    f = f + '\r\n'
    s.send(f)
    s.close()


if rpi:
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(pulse_pin1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.add_event_detect(pulse_pin1, GPIO.BOTH, callback=eventHandler1, bouncetime=bounce)
    GPIO.setup(pulse_pin2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.add_event_detect(pulse_pin2, GPIO.BOTH, callback=eventHandler2, bouncetime=bounce)


try: # CTRL+C to break - requires graceful exit
    while True:
        time.sleep(5) # the value doesn't matter.
except KeyboardInterrupt:
    GPIO.cleanup() # clean up GPIO on CTRL+C exit
    exit()

GPIO.cleanup() # just in case

time.sleep() could be a millisecond, one second, 5000 seconds, makes no difference, as long as the program is running the interrupts will happen and callbacks are initiated immediately.
I hope that helps.

1 Like

Hi guys

Is there a summary of this?

I’m using the Lechacal boards on top of my RPi’s. They don’t know/understand the pulse sensor (and don’t have input points, they are however only using pins 1-10, thus there are open pins, so can hard wire the RG45 pins used to open GPIO pins + modify the above script to use the then selected pin,
(is this script going to flat line my CPU… cause problems for emonPi)?

(thinking I might connect a camera also, and take a photo once a day which can be used down the line as a sanity check against values stored/recorded by the pulse sensor.

optical sensor RPi
1 (nc)
2 (vcc) Pin 17 (vcc)
3 (nc)
4 (nc)
5 (gnd) Pin 9 (gnd)
6 (output) Pin 13 or 15
7 (nc)
8 (nc)

is there a how too, considering this seems to be a long running thread by now ?
seen some comments re the auto start of the script, and rc.local being phased out, so whats the preferred method.

G

My personal motivation for making a how-to is to get an item in the OEM shop alongside.
It’s somewhere around the top of the OEM related to-do list I have… to design an RJ45 pi hat for the optical sensors.

I think it’s now systemd? I used a guide online without much trouble.

Perhaps chop the optical lead and make up something like this for a simple plug into the Pi:

image
That image is actually a little misleading, the crimpy things go into the housing the other way around.

I’m pretty sure it helps to have a small ceramic cap on the signal line to GND for countering noise or flickering ambient light.

1 Like

Hi Dan,

thanks.

I’l rather plug the Optical sensor into a RG45 female plug, and then run out of there lines that i will plug into the RPI’s board, that way the optical sensor is untouched, should I change my mind later and get a OEM board and want to then plug it into a RG45 female connector.

G

1 Like

Sorry to revive an old thread. I am trying to use an optical sensor via RJ45 breakout socket. Headers soldered and jumpers connected to the Rpi as above. Some activity from monitor.py but no luck with the actual sensing. LED doesn’t light either, I’ve used a 3.3v pin as advice above, should I use 5v?

Now thinking about constructive vandalism, removing RJ45 plug and soldering directly. However, if I do this, any clues guidance about the cable colour codes inside?

I need just what’s in this thread, rather than the whole of emon, hence my rather direct approach. Thanks in advance.

If you’re looking for details of what’s inside to Optical Pulse sensor, there’s a link in post no.2.

Thanks! Will look.

I have a working set up now. Removing the RJ45 and soldering jumpers directly worked. I find that I benefit for looking at different programming approaches to a single problem, so here’s my simple flash collector → influxdb + thence to grafana.

#!/usr/bin/env python

# (c) hugh barnard 2022 Based on emon work and the need for something 'simpler' 
# hughbarnard.org and @hughbarnard

# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
# See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program.  If not, see <http://www.gnu.org/licenses/>.

from gpiozero import LightSensor
import time
import datetime
from influxdb import InfluxDBClient

import configparser

# unused currently
import schedule

# read configuration file
config = configparser.ConfigParser()
config.read('config/config.ini')
total_watts = 0


#influx_client = InfluxDBClient('10.0.0.100', '8086', 'user', 'password', 'temp') this is 'old' influxdb
influx_client = InfluxDBClient(config['server']['ip_address'], config['server']['port'], '', '', config['server']['database'])
sensor = LightSensor(config['gpiozero']['bcm_sensor_pin'], queue_len=int(config['gpiozero']['queue_length']), threshold=config['gpiozero']['threshold'])

# config['data']['cost'] is the cost of 1 watt = 1 impression (flash)
# need to upgrade to influxdb line protocol and send batches later on

def write_influxdb(config,client,value,total_watts):
    json_body = [
       {
        "measurement": config['data']['measurement'],
        "tags": {
            "sensor": config['data']['sensor'],
            "house": config['data']['house']
        },
        "fields": {
            "watt": value,
            "cost": config['data']['cost']
        }
       }
    ]
    total_watts += 1
    # print("writing influx, total_watts are " + str(total_watts))
    client.write_points(json_body)
    return total_watts


#Catch when script is interrupted, cleanup correctly
try:
    # Main loop
    while True:
        sensor.wait_for_light()
        total_watts = write_influxdb(config,influx_client,1,total_watts)
        sensor.wait_for_dark()

except KeyboardInterrupt:
    pass
finally:
    quit()
1 Like

Just install emonhub.

That is rather a neat way to do it, using LightSensor.

Here’s one way to use line protocol - via the Requests module - from a Python script:

# measurement names and values
        meas = {
            'LEG1':LEG1,
            'LEG2':LEG2,
            'GENW':GENW,
            'PVWH':PVWH,
            'CONS':CONS,
            'TOTL':TOTL,
            'TECO':TECO,
            'IMPT':IMPT,
            'EXPT':EXPT,
            'NETT':NETT,
            'VOLT':VOLT,
            'L1PF':L1PF,
            'L2PF':L2PF,
            'PVPF':PVPF,
            'DRCT':DRCT,
            'IMPW':IMPW,
            'EXPW':EXPW
        }

        tmpData = []
        for key, val in meas.items():
            tmpData.append('{} value={} {}'.format(key, val, int(time.time())))
            Data = '\n'.join(tmpData)

        requests.post('http://192.168.1.61:8086/write?db=energy&precision=s', data=Data, timeout=1)

Used with InfluxDB v1.8 and no security, as it’s on a LAN that’s not connected to the internet.
If you’d like a copy of the script, I’m happy to share.

Thanks, I have most of one from an earlier project, that I borrowed from this:

I’m mainly doing something for a friend’s storage heater problems, we don’t need a full monitoring setup/CMS etc.

Here’s the config.ini

[general]
language = en

[gpiozero]
bcm_sensor_pin = 27
sleep = 0.1
queue_length = 1
threshold = 0.1
[server]
ip_address = 10.0.0.100
port = 8086
database = temp
#user = root
#password = none

[data]
measurement = watts
sensor = 2
house = house_address
# cost in pence of one impression = 1 watt
cost = 0.0345

[schedule]
# not used at present

Also, I’ve had some trouble with the cost, that seemed to default as a string, so:
cost = float(config['data']['cost'])
before constructing the json, solves it.