Individual socket monitoring with integration to EmonCMS/EmonTX?

I have some rather large appliances (deep freeze, bar fridges and servers) I would like to monitor but they all exist on the same circuit. Some are even on the same socket.

Is their anything I can buy that integrates into EmonTX or EmonCMS?

Maybe a PDU with power stats?

Cheers

(Australian plug)

Are they hard wired to the socket or do they have power leads?

Just standard power leads into a GPO

What’s a GPO?

How many appliances and are they all located by the same socket or all over the place?

General Purpose Outlet, standard 3-pin, 10A power outlet found in most houses in Australia.
Although as per https://whirlpool.net.au/wiki/gpo, they are now simply called “Socket Outlets”

General purpose outlet

(The plug on the wall)

Various ‘smart plugs’ can do sub-metering. If you look for one that is compatible with OpenHAB (which is bundled with emonPi or can be deployed separately) and get that setup then you can easily push that data to emoncms.

That’s what BS7671 (otherwise known as “The IEE Regs.”) calls them in the UK.

1 Like

If you can find Watts Up? Pro ES (or Pro .net) power meters that mate with your GPO (try ebay), it’s not hard to extract real-time data via the USB port using a Raspberry Pi. I’ve got working Python code that does this and sends to data stream to emoncms.org. I’m happy to share the code if anyone’s interested.

@sroof my Python has never been very good so I would be interested in seeing your code for the Pi.

Hopefully this will make sense!

#!/usr/bin/env python

#Program to read data from WattsUp power meter through USB port.  
#Written by Steve Roof, September 2016
#This version sets Watts Up meter to external logging then does a continuous loop writing data to file
#and sends data to emoncms web site

import sys
import string
import serial
import time
import requests
from datetime import datetime, date

#Define the serial port the WattsUp is connected to
WattsUp = serial.Serial('/dev/ttyUSB0', baudrate=115200)

#define output file
data_file_name = '/home/pi/wattsup/GreyWaterSumpPump1.txt'

#initialize some variables
current_day = date.today()
firstpass = True
daily_total_kWh = prev_kWh_tot = kWh_tot = prev_meter_kWh_tot = elapsed_hours = elapsed_minutes = 0.0

#kWh_tot is running total since wattsup program started, not total value report by meter

#Set Watts Up meter to external logging mode.  Triple quotes are needed to escape the # char 
#last digit before semi-colon in trigger sets logging interval in seconds
trigger1 = '''#L,W,3,E,2,60;'''
WattsUp.write(trigger1)
time.sleep(4)

#Create output file (append to it if it already exists)
with open(data_file_name, 'a') as file:
    file.write('\n')
    file.write(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S') + ', +++++++ Program Started +++++++'))
    file.write('\n')
    file.write(trigger1)  #record trigger in file
    file.write('\n')
    file.write('Date Time,d,-,18,W,V,A,WH,Cost,WH/Mo,Cost/Mo,Wmax,Vmax,Amax,Wmin,Vmin,Amin,PF,DC,PC,Hz,VA')
    file.write('\n')

    #Read output line from the WattsUp and discard - 1st line is often incomplete
    WattsUp_data = WattsUp.readline()

    start_time = time.time()
while True:
    try:
        #Read output from the WattsUp
        WattsUp_data = WattsUp.readline()
        
        #write raw results to output file
        with open(data_file_name, 'a') as file:
            if firstpass:
                file.write('Line below is first pass - it was not processed: ')
                file.write('\n')
            file.write(str((datetime.now().strftime('%Y-%m-%d %H:%M:%S'))))
            file.write(', ')
            file.write(WattsUp_data)
        
        #Clean up data stream and extract relevant values using split
        WattsUp_data = WattsUp_data.strip() #strips any non-printing characters including line feeds '\n'
        if WattsUp_data[1:7] <> 'd,-,18': #tests to determine if input is proper data string  (proper strings start with #d,-,18
            with open(data_file_name, 'a') as file:
                file.write(str((datetime.now().strftime('%Y-%m-%d %H:%M:%S'))))
                file.write(', +++++ Malformed Input Line Above Skipped +++++')
                file.write('\n')
                firstpass = False  #needed if data line from 1st pass is malformed, since reset of firstpass below will be skipped
                continue #"continue" causes program to skip code lines below and immediately return to beginning of While loop
        else:
            Watts = (float(WattsUp_data.split(',')[3])/10)  #Splits out watt value, converts to float, then divides by 10
            meter_kWh_tot = (float(WattsUp_data.split(',')[6])/10000)  #Splits out watt-hour value, converts to float, then divides by 10000


        #This prevents the daily_total values from accumulating bad data on first pass through While loop
        if not firstpass: 
            #calculate change in kWh_tot in interval
            interval_kWh_tot = meter_kWh_tot - prev_meter_kWh_tot
            if interval_kWh_tot < 0:  # Occurs when WH rolls over at approx 260,000
                interval_kWh_tot = 0  # Replace any negative interval value with zero
            daily_total_kWh = daily_total_kWh + interval_kWh_tot
            #kWh_tot is running total since wattsup program started, not total value report by meter
            kWh_tot = kWh_tot + interval_kWh_tot 
            elapsed_seconds = time.time() - start_time
            m, s = divmod(elapsed_seconds, 60) #see http://stackoverflow.com/questions/775049/python-time-seconds-to-hms
            h, m = divmod(m, 60)
            elapsed_hours = str(int(h))
            elapsed_minutes = str(int(m))

        #Format data to send to emoncms.org.	
        datapack = "GreyWaterSumpPump1_Watts:" + str(round(Watts,6)) + \
            ",GreyWaterSumpPump1_kWh_tot:" + str(round(kWh_tot,6)) + \
            ",GreyWaterSumpPump1_daily_total_kWh:" + str(round(daily_total_kWh,6)) + \
            ",GreyWaterSumpPump1_elapsed_hours:" + str(elapsed_hours) + \
            ",GreyWaterSumpPump1_elapsed_minutes:" + str(elapsed_minutes)

#    	print 'datapack = ' + datapack
        
        #determine epochtime
        epochtime = str(int((datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()))
        
        #insert the api key at the beginning and append the data:
        #This version sends to node 4 at emons!
        oem_payload = "time=" + epochtime + "&node=4&apikey=XXXXXXXXXXXXXXXXXXXX&json=" + datapack
        #print 'oem_payload = ' + oem_payload
        
        #combine the url with the payload into "fullurl":
        fullurl = 'http://emoncms.org/input/post.json?' + oem_payload
        #print 'fullurl: ' + fullurl
        
        #Now send the message to emomcms.org if it's not the first pass
        if not firstpass:
            r = requests.post(fullurl)

        #Test if current time has passed midnight and if true, reset "daily_total_" values and "today" value
        if date.today() > current_day:
            daily_total_kWh = 0.0
            current_day = date.today()

        #Set all current values to prev_ values for next pass
        firstpass = False
        prev_meter_kWh_tot = meter_kWh_tot
        
    except:
        error_msg = sys.exc_info()
        with open(data_file_name, 'a') as file:
            file.write(str((datetime.now().strftime('%Y-%m-%d %H:%M:%S'))))
            file.write(', ')
            file.write(str(error_msg))
            file.write('\n')
1 Like