Emonhub Pulse Interfacer

Continuing the discussion from Pulse monitoring on a Pi:

The recent thread (New Home and PV energy Monitoring system) reminded me about direct pulse monitoring using a pulse sensor and a Pi. Digging around I found I’d asked much the same question a while back. However, being older and wiser, I now wonder if there could be a generic emonhub interfacer to read the pulses directly.

The script in this thread (Directly connecting to Optical Pulse Counter with RPi? - #61 by danbates), original script by @pb66 that @danbates modified the loop with call backs, seems like a good place to start. I’m no Python expert (@bwduncan) but I wonder if this could be used for a generic pulse interfacer for emonhub?

It would make a very cheap and simple means of reading the use at the meter.

1 Like

Also, I have a script which converts the time between pulses into a Wattage. I don’t know how accurate it is and it’s unlikely to be so, but it is cheap. I ran the script with extra Priority which helped with accuracy.

If an interfacer’s being made, happy to share the script. Converting time to wattage with the known imp/Wh value is all it does.

I didn’t add the callbacks btw, I only changed the while loop at the end so it didn’t use 100% CPU.

Optical Pulse Sensors are great for the price.

1 Like

I’m hoping someone will offer :grinning:. Happy to test it but my Python is not that good…

@borpin

And the thing about meter pulses is – they are dead accurate. We even pay our energy bills and receive our FIT payments based on meters.

Meter pulses do not record export tho’.

An Optical Pulse Sensor costs £19. Add another £18 for a Pi ZERO with wireless and an official Raspberry PSU and add a couple of quid for a GPIO header, jump leads & a female RJ45 connector and so for £40 you’d have quite a capability with the benefit of emon software to visualise/dashboard as you so choose.

I haven’t tried it – a winter evening project – what do you think?

RS-online have this female RJ45 connector for £1 – might even be possible to solder the relevant pins directly to the Pi ZERO?

0900766b815bdd23.pdf (309.4 KB)

Just a thought.

@borpin My python skills are weak :slight_smile:

@johnbanks I knocked together a PCB design with two similar rj45’s on board, for mounting on a rPi. I could dig it out after this summer project work. I wanted to get an rfm69 footprint on there too. Make it an evolved rfm2pi gateway as it were.

Elster can configure the pulse out of a meter at the factory for import or export.

For the main meter, we need both. Maybe a 100 ms flash for import and 100 ms dark for export? :rofl:

I doubt if the Meter owner would co-operate.

@Robert.Wall
Knowing export at the Grid meter is important info and pulse flashes will not provide that info.
But, at the meter recording PV generation, it is an irrelevant limitation. Pulse flashes will provide all the info.

Thing to do is swap L1 and L2 for a quick check when the sun’s out. :sweat_smile:

I better get on with work :zipper_mouth_face:

@bwduncan - could I impose on your generosity and have a look at this for me please?

OK I think I understand a bit more now. I presume when we’re talking abut a “pulse” we mean a rising edge, some minimum time before an immediate falling edge. I.e. you don’t want to count twice?

I also presume this is a barely-connected RPi (zero), so I wouldn’t rely on its time being correct.

If that’s the case then I would do something like the code at the end. I can’t test this, though, obviously!

It’s unfortunate that the emonhub socket interfacer expects a new TCP connection for each data packet. I’m not sure how quickly these pulse can go, but setting up and destroying TCP connections is fairly costly, especially on a high-latency network. Whether that causes problems in practice is hard to say.

A similar question applies to the debounce time, if we expect pulses more often than one every 1ms.

import socket
import time
import signal
from collections import defaultdict
import RPi.GPIO as GPIO

# 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

# Configuration
nodeid = 18
bounce = 1  # ms
interval = 5  # s
host = "localhost" #emonbase1"
port = 50012
pulse_pins = [21, 15]

# Global state
last_send = 0
pulse_id = defaultdict(int)

def process_pulse(channel):
    global lastsend
    pulse_id[channel] += 1
    print("Channel", channel, "pulse:", pulse_id[channel])

    t = time.time()
    if t > lastsend + interval:
        frame = '{t} {nodeid}'.format(t=t, nodeid=nodeid)
        for pin in pulse_pins:
            frame += ' {}'.format(pulse_id[pin])
        lastsend = t
        print(frame)
        send(frame)


def send(frame):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((host, port))
        frame = frame + '\r\n'
        s.send(frame.encode())


def main():
    GPIO.setmode(GPIO.BOARD)
    for pin in pulse_pins:
        GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
        GPIO.add_event_detect(pin, GPIO.FALLING, callback=process_pulse, bouncetime=bounce)

    # Sleep forever until interrupted by a signal, then exit. GPIO.cleanup is called automatically.
    signal.pause()

if __name__ == '__main__':
    main()

Almost :grinning:

What I am thinking is like the serial interfacer in emonhub, but instead of reading the serial interface, it detects the pulses, then just passes that on as an incrementing number to the rest of emonhub.

The socket part would be handled (if necessary, by the socket interfacer.

Ah OK that’s simpler. The EmonHubInterfacer class calls read() infinitely fast, but the counters are updated by an interrupt, so read() just has to generate a frame from the stored data whenever it is called. This is different from the serial interfacer which will block until new data arrives, then generate a frame out of it.

I think we might have to worry about not sending data up the queue too fast. I don’t know.

If the pulses are being counted directly, what is left for the socket interfacer to do?

Bruce

I think so… :grinning: I was thinking the read() is when the pulse happens.

Nothing in this case, we just need to return the frame of data. The socket interfacer was a way to get it to emonhub in the absence of a native pulse interfacer. I was not sure how to deal with the callbacks as part of the read(). None of the other interfacers seemed to use them so I had no example to work from.

Pulses are not that rapid.

read() is called from within the EmonHubInterfacer.run method loop, it’s not meant to be called by us. That method has a time.sleep(0.1) which will stop us from hoovering up all the CPU, but we’ll still be doing a lot of work for nothing. I’m not sure what the authors of emonhub intended to happen in this scenario!

Try this?

Great.

I’m having trouble initiating it though.

It needs an entry in the __init__.py file I think but even with that I am getting

2020-06-10 21:36:26,414 INFO     MainThread Creating EmonHubPulseCounterInterfacer 'pulse'
2020-06-10 21:36:26,417 ERROR    MainThread Unable to create 'pulse' interfacer: module 'emonhub_interfacer' has no attribute 'EmonHubPulseCounterInterfacer'

Oops, good point. I’ve pushed a commit to fix that.

As you say that doesn’t explain why it’s not working, though. Is the python3-rpi.gpio package installed?

No it isn’t getting that far. Somehow it is not finding the interfacer. @TrystanLea can you help?

One point though, I think the pulse pins should be passed as an init setting rather than runtime. Not really clear what the difference is though!

Yeah I don’t understand the difference either. It’s somewhat confusing!

It must be finding python3-rpi.gpio because everything in __init__.py/__all__ is loaded right at start through from interfacers import *. If it has the right name I can’t think why it wouldn’t be found. Are you sure it’s executing the code you checked out and not the system install?

@bwduncan - schoolboy error - I had it installed twice. Getting there.

It doesn’t like the pulse_pins option… I think you may have used the wrong settings object? I think this should be an init setting rather than runtime.

I needed to hardcode the pin to get it to work.

        GPIO.setmode(GPIO.BOARD)
        GPIO.setup(15, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
        GPIO.add_event_detect(15, GPIO.FALLING, callback=self.process_pulse, bouncetime=1)

emonhub.conf (I did try the pulse_pins setting)

[[pulse2]]
    Type = EmonHubPulseCounterInterfacer
    [[[init_settings]]]
    [[[runtimesettings]]]
        pubchannels = ToEmonCMS,

However* although it says it couldn’t create it, it seems it is running as I am seeing pulses!

2020-06-10 23:18:40,995 INFO     MainThread EmonHub emonHub emon-pi variant v3-beta
2020-06-10 23:18:40,998 INFO     MainThread Opening hub...
2020-06-10 23:18:41,002 INFO     MainThread Logging level set to DEBUG
2020-06-10 23:18:41,006 INFO     MainThread Creating EmonHubPulseCounterInterfacer 'pulse2'
2020-06-10 23:18:41,014 DEBUG    MainThread Setting pulse2 pause: off
2020-06-10 23:18:41,017 ERROR    MainThread Unable to create 'pulse2' interfacer: 'int' object has no attribute 'isdigit'
2020-06-10 23:18:41,030 INFO     MainThread Creating EmonHubEmoncmsHTTPInterfacer 'emoncmsorg'
2020-06-10 23:18:41,035 DEBUG    MainThread Setting emoncmsorg subchannels: ['ToEmonCMS']
2020-06-10 23:18:41,037 INFO     MainThread Setting emoncmsorg apikey: set
2020-06-10 23:18:41,047 INFO     MainThread Setting emoncmsorg url: http://192.168.7.243/
2020-06-10 23:18:41,049 INFO     MainThread Setting emoncmsorg senddata: 1
2020-06-10 23:18:41,053 INFO     MainThread Setting emoncmsorg sendstatus: 1
2020-06-10 23:18:44,135 DEBUG    Dummy-3    Process pulse
2020-06-10 23:18:44,139 DEBUG    Dummy-3    Channel 15 pulse: 1
2020-06-10 23:18:48,818 DEBUG    Dummy-3    Process pulse
2020-06-10 23:18:48,822 DEBUG    Dummy-3    Channel 15 pulse: 2
2020-06-10 23:18:53,486 DEBUG    Dummy-3    Process pulse
2020-06-10 23:18:53,489 DEBUG    Dummy-3    Channel 15 pulse: 3
2020-06-10 23:18:58,173 DEBUG    Dummy-3    Process pulse
2020-06-10 23:18:58,176 DEBUG    Dummy-3    Channel 15 pulse: 4

On restart now getting

Unable to create 'pulse2' interfacer: Conflicting edge detection already enabled for this GPIO channel

But again it seems to sort itself out as I see the processing messages.

That is me for tonight. Thanks for your help.

I misread the source of the GPIO module. I have added a cleanup call which will fix that latter error. I’ll move the settings to init settings.

If it says it failed but it’s actually running maybe that means it’s throwing an exception in its initialiser. Unfortunately emonhub is swallowing the stacktrace, or the whole exception. I’ll have a closer think.

If it’s this: 2020-06-10 23:18:41,017 ERROR MainThread Unable to create 'pulse2' interfacer: 'int' object has no attribute 'isdigit' then I have no idea where to start. Maybe I’ll improve the exception logging and we can find out.

Night!