SCT-013-030 Energy Meter



  • Hi all
    It's late and I finished the sketch for my Energy Meter. I'ts not tested yet, but the part for sct-reading is tested and works.
    In a few days more nanos arrive, then I can test it.

    /**
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * EnergyMeterSCT by Patrick Schaerer
     * This Sketch is a WattMeter used with a SCT-013-030 non invasive PowerMeter
     * see documentation for schematic
     * 
     * Special thanks to Surge, who optimized my code.
     * 
     * updated to mySensors Library 2.0
     */
    
    
    #define MY_RADIO_NRF24
    #define MY_REPEATER_FEATURE
    #define MY_DEBUG
    
    
    #include <SPI.h>
    #include <MySensors.h>  
    #include <EmonLib.h> 
     
    #define ANALOG_INPUT_SENSOR 1  // The digital input you attached your SCT sensor.  (Only 2 and 3 generates interrupt!)
    //#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    #define CHILD_ID 1              // Id of the sensor child
    
    EnergyMonitor emon1;
    
    MyMessage wattMsg(CHILD_ID,V_WATT);
    MyMessage kwhMsg(CHILD_ID,V_KWH);
    MyMessage msgKWH(CHILD_ID,V_VAR1);
    unsigned long SLEEP_TIME = 60000 - 3735; // sleep for 60 seconds (-4 seconds to calculate values)
    
    float wattsumme = 0;
    float kwh = 0;
    float wh = 0;
    int minuten = 0;  //vorher 61
    boolean KWH_received=false;
    
    //Humidity Sensor Code
    #include <DHT.h>  
    #define CHILD_ID_HUM 2
    #define CHILD_ID_TEMP 3
    #define HUMIDITY_SENSOR_DIGITAL_PIN 2
    DHT dht;
    float lastTemp;
    float lastHum;
    boolean metric = true; 
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    //End of Humidity Sensor Code
    
    
    void setup()  
    {  
      //energy clamp code
      //gw.begin(incomingMessage, AUTO, true,0); 
      
      Serial.begin(115200);
      emon1.current(ANALOG_INPUT_SENSOR, 30);             // Current: input pin, calibration.
    
      
      double Irms = emon1.calcIrms(1480);  // initial boot to charge up capacitor (no reading is taken) - testing
      request(CHILD_ID,V_VAR1);
      //end of energy clamp code
    
    //Humidity Sensor Code
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);   
      metric = getConfig().isMetric;
      //End of Humidity Sensor Code 
    }
    
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      // Register this device as power sensor
    sendSketchInfo("Energy Meter SCT013", "2.0");
    present(CHILD_ID, S_POWER);
    present(CHILD_ID_HUM, S_HUM);
    present(CHILD_ID_TEMP, S_TEMP);
    
    }
    void loop()     
    { 
      
      //process();
    
      //KWH reveived check
      if (!KWH_received) request(CHILD_ID,V_VAR1);
      
      // power used each minute
      if (minuten < 60) {
        double Irms = emon1.calcIrms(1480);  // Calculate Irms only
        if (Irms < 0.3) Irms = 0;
        long watt = Irms*240.0; // default was 230 but our local voltage is about 240
        wattsumme = wattsumme+watt;
        minuten++;
        send(wattMsg.set(watt));  // Send watt value to gw
        
        Serial.print(watt);         // Apparent power
        Serial.print("W I= ");
        Serial.println(Irms);          // Irms   
      }
      // end power used each minute
      
      // hours KW reading
      if (minuten >= 60) {
        wh = wh + wattsumme/60;
        kwh = wh/1000;
        send(kwhMsg.set(kwh, 3)); // Send kwh value to gw 
        send(msgKWH.set(kwh, 3)); // Send kwh value to gw
        wattsumme = 0;
        minuten = 0;
      }
    // end of hourly KW reading
        
    // Humidity Sensor Code
     if (minuten == 15 || minuten == 30 || minuten == 45|| minuten == 60) {
        float temperature = dht.getTemperature();
        if (isnan(temperature)) {
          Serial.println("Failed reading temperature from DHT");
        } else if (temperature != lastTemp) {
          lastTemp = temperature;
        if (!metric) {
          temperature = dht.toFahrenheit(temperature);
        }
        send(msgTemp.set(temperature, 1));
        Serial.print("T: ");
        Serial.println(temperature);
        }
      
      float humidity = dht.getHumidity();
      if (isnan(humidity)) {
          Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum) {
          lastHum = humidity;
          send(msgHum.set(humidity, 1));
          Serial.print("H: ");
          Serial.println(humidity);
      }
     }
    
     //End of Humidity Sensor Code
     wait(SLEEP_TIME);
    }
    
    void receive(const MyMessage &message) {
      if (message.type==V_VAR1) {  
        kwh = message.getFloat();
        wh = kwh*1000;
        Serial.print("Received last KWH from gw:");
        Serial.println(kwh);
        //send(kwhMsg.set(kwh, 3)); // Send kwh value to gw 
        KWH_received = true;
      }
    }
        
    
    
    

    The schematics for attaching of the sct-013-030 is shown in the picture.

    IMG_20160103_223443.jpg



  • Ok I tested it and it works fine. Because the reading of low current was not acurate I change readings up to 60W as 0W. I mesure the energy consumption of a room dryer that consumes about 1400W. Mabe SCT-013-005 would be more acurate in low current mesurements.



  • 0_1454182054474_Bildschirmfoto 2016-01-30 um 20.26.32.png

    C1 is 100uF

    R1+2 are 15k



  • Thanks for doing the groundwork in developing this. Before i copy your implementation, has there been any updates/improvements/observations now that you've had it running for almost a month? Cheers



  • I made some changes in the software. There was a mistake in the kwh and I added a DHT-Sensor (see comment in the code).
    It works well. The kwh is reset on each restart. I probably will change that in the future.



  • Hey Mate,

    Had a chance to sit down and build this node. Made a few tweaks which you may be interested in.

    Rewrote the code to sleep for 60 seconds between measurements. This saves approx 80% power ( 22mA down to 4.6mA on my 3.3v pro mini). This also corrects for the drift in the original code which resulted in gaining a second every few mins of measurements (its now only 2ms/min)

    Added battery level monitoring which is reported in volts every hour and require no additional hardware or wiring than the originally posted circuit but requires a new vcc library. The actual votlage is only reported if the battery level has changed since the last reading - to save power) .

    Let me know what you think:
    https://codebender.cc/sketch:276398



  • Hi, great sketch! But i have a question: how to chanhe this sketch to send kwh often then once per hour? Maybe safer will be send kwh like sending wh - every minute?



  • @maciejka : you can change the value on column 98: minuten == 60
    "Minuten" is german for minutes. if you want to report every minute change the value to 1.

    @Surge86 : thank you for your improvements! I will compare our codes and hopefully learn a lot.
    I startet arduino programming in november and keep on learning.

    greets patrick



  • Thanks, i will test it 🙂
    Regards
    Maciej



  • Thanks for sharing this! I am hoping to create an all-in-one extension cord plus this meter. I hope this way I can detect when a pump fails or maybe just how much power is being used.

    I have read that you when using a CT you must be careful to avoid a voltage build up on the CT output. Is that a concern with this current setup? With a battery powered arduino you are not grounded? In my extension cord project I was thinking I could use the ground from the extension cord.

    I am not an electrical engineer so I may be way off here, just trying to be safe.

    I think this setup could be very useful. In the high school greenhouse where I have my sensor network there are so many pumps, heaters, air stones, that need to be monitored and an alert sent if they stop working.

    I may also try this with the sensebender micro.



  • As far as i understand there is a resistor built in the sct013 that prevents this voltage buildup. But i am not an electrician.



  • I optimized my code with the help of Surge.
    I added a KWH reading on a restart of the node.
    Now it's Version 1.3



  • Hello Patrick, thank you for sharing your project. I tested it and it works fine but I want to test how acurate it is with low current measurements. Can you please tell me how to change your code to get results below 60W? I'm just beginning to learn arduino-programming so i don't understand everything..



  • @m1rk0
    In Line 95 is the following expression:
    if (Irms < 0.3) Irms = 0;

    Irms is RMS current. The expression sets all current smaller than 0.3 as 0.
    You can delete this line for smaller values.
    I suggest to use a SCT-013-005 instead of a SCT-013-030.



  • Thank you patrik, i already ordered an sct-013-005, but i need sometimes higher measurements than 5a. With this second sensor i will be able to compare the results.



  • @m1rk0 said:

    Thank you patrik, i already ordered an sct-013-005, but i need sometimes higher measurements than 5a. With this second sensor i will be able to compare the results.

    yeah 5A is within its range. I usually sit between 1A-20A



  • hello, where is the MySensor.h file??


  • Admin

    This is made for an earlier version of the library, things has changed a lot since.

    first off, the library header file is now called MySensors.h (note the added "s" to the name). But also how you use / initialize the mysensors project is very different in 2.x, than in 1.x,

    have a look at this post to get an idea of what you have to change, to upgrade your arduino sketch to work with MySensors 2.x library



  • I alread updated to MySensors 2.0

    This is the update code:

    I also edited the first post.

    /**
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * EnergyMeterSCT by Patrick Schaerer
     * This Sketch is a WattMeter used with a SCT-013-030 non invasive PowerMeter
     * see documentation for schematic
     * 
     * Special thanks to Surge, who optimized my code.
     * 
     * updated to mySensors Library 2.0
     */
    
    
    #define MY_RADIO_NRF24
    #define MY_REPEATER_FEATURE
    #define MY_DEBUG
    
    
    #include <SPI.h>
    #include <MySensors.h>  
    #include <EmonLib.h> 
     
    #define ANALOG_INPUT_SENSOR 1  // The digital input you attached your SCT sensor.  (Only 2 and 3 generates interrupt!)
    //#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway)
    #define CHILD_ID 1              // Id of the sensor child
    
    EnergyMonitor emon1;
    
    MyMessage wattMsg(CHILD_ID,V_WATT);
    MyMessage kwhMsg(CHILD_ID,V_KWH);
    MyMessage msgKWH(CHILD_ID,V_VAR1);
    unsigned long SLEEP_TIME = 60000 - 3735; // sleep for 60 seconds (-4 seconds to calculate values)
    
    float wattsumme = 0;
    float kwh = 0;
    float wh = 0;
    int minuten = 0;  //vorher 61
    boolean KWH_received=false;
    
    //Humidity Sensor Code
    #include <DHT.h>  
    #define CHILD_ID_HUM 2
    #define CHILD_ID_TEMP 3
    #define HUMIDITY_SENSOR_DIGITAL_PIN 2
    DHT dht;
    float lastTemp;
    float lastHum;
    boolean metric = true; 
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    
    //End of Humidity Sensor Code
    
    
    void setup()  
    {  
      //energy clamp code
      //gw.begin(incomingMessage, AUTO, true,0); 
      
      Serial.begin(115200);
      emon1.current(ANALOG_INPUT_SENSOR, 30);             // Current: input pin, calibration.
    
      
      double Irms = emon1.calcIrms(1480);  // initial boot to charge up capacitor (no reading is taken) - testing
      request(CHILD_ID,V_VAR1);
      //end of energy clamp code
    
    //Humidity Sensor Code
      dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);   
      metric = getConfig().isMetric;
      //End of Humidity Sensor Code 
    }
    
    void presentation() {
      // Send the sketch version information to the gateway and Controller
      // Register this device as power sensor
    sendSketchInfo("Energy Meter SCT013", "2.0");
    present(CHILD_ID, S_POWER);
    present(CHILD_ID_HUM, S_HUM);
    present(CHILD_ID_TEMP, S_TEMP);
    
    }
    void loop()     
    { 
      
      //process();
    
      //KWH reveived check
      if (!KWH_received) request(CHILD_ID,V_VAR1);
      
      // power used each minute
      if (minuten < 60) {
        double Irms = emon1.calcIrms(1480);  // Calculate Irms only
        if (Irms < 0.3) Irms = 0;
        long watt = Irms*240.0; // default was 230 but our local voltage is about 240
        wattsumme = wattsumme+watt;
        minuten++;
        send(wattMsg.set(watt));  // Send watt value to gw
        
        Serial.print(watt);         // Apparent power
        Serial.print("W I= ");
        Serial.println(Irms);          // Irms   
      }
      // end power used each minute
      
      // hours KW reading
      if (minuten >= 60) {
        wh = wh + wattsumme/60;
        kwh = wh/1000;
        send(kwhMsg.set(kwh, 3)); // Send kwh value to gw 
        send(msgKWH.set(kwh, 3)); // Send kwh value to gw
        wattsumme = 0;
        minuten = 0;
      }
    // end of hourly KW reading
        
    // Humidity Sensor Code
     if (minuten == 15 || minuten == 30 || minuten == 45|| minuten == 60) {
        float temperature = dht.getTemperature();
        if (isnan(temperature)) {
          Serial.println("Failed reading temperature from DHT");
        } else if (temperature != lastTemp) {
          lastTemp = temperature;
        if (!metric) {
          temperature = dht.toFahrenheit(temperature);
        }
        send(msgTemp.set(temperature, 1));
        Serial.print("T: ");
        Serial.println(temperature);
        }
      
      float humidity = dht.getHumidity();
      if (isnan(humidity)) {
          Serial.println("Failed reading humidity from DHT");
      } else if (humidity != lastHum) {
          lastHum = humidity;
          send(msgHum.set(humidity, 1));
          Serial.print("H: ");
          Serial.println(humidity);
      }
     }
    
     //End of Humidity Sensor Code
     wait(SLEEP_TIME);
    }
    
    void receive(const MyMessage &message) {
      if (message.type==V_VAR1) {  
        kwh = message.getFloat();
        wh = kwh*1000;
        Serial.print("Received last KWH from gw:");
        Serial.println(kwh);
        //send(kwhMsg.set(kwh, 3)); // Send kwh value to gw 
        KWH_received = true;
      }
    }
        
    
    


  • @patrick-schaerer said:

    I alread updated to MySensors 2.0

    I just got my sct-013-000 non-burden version and will try it as soon as atmega+nrf packs arrive. Thanks for code update. 👍
    Meanwhile what is "msgKWH" for? What is different than "kwhMsg"? Which controller do you use?



  • Hello, now with the new code I get this error:

    Arduino: 1.6.9 (Windows 10), Board: "Arduino/Genuino Uno"

    WARNING: Spurious .mystools folder in 'MySensors' library
    C:\Users\LENOVO\Desktop\arduino_code\Voltage_sensor_5\Voltage_sensor_5.ino:58:19: fatal error: DHT.h: No such file or directory

    #include <DHT.h>

                   ^
    

    compilation terminated.

    exit status 1
    Error compiling for board Arduino/Genuino Uno.

    This report would have more information with
    "Show verbose output during compilation"
    option enabled in File -> Preferences.



  • @john7845
    Error is related to missing library of DHT. If you will use DHT temperature/humidity sensor in your circuit, you should add DHT library to your Sketchbook/libraries folder. If you don't use that sensor, clear or comment out dht related codes in sketch.



  • Hello,

    I use this code just to see if the current sensor works, but I get 0.0 on the serial! What am I doing wrong?

    /*
    ReadAnalogVoltage
    Reads an analog input on pin 0, converts it to voltage, and prints the result to the serial monitor.
    Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
    Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

    This example code is in the public domain.
    */

    // the setup routine runs once when you press reset:
    void setup()
    {
    // initialize serial communication at 9600 bits per second:
    Serial.begin(9600);
    }

    // the loop routine runs over and over again forever:
    void loop()
    {
    // read the input on analog pin 0:
    int sensorValue = analogRead(A0);
    // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
    float voltage = sensorValue * (1.0 / 1023.0);
    // print out the value you read:
    Serial.println(voltage);
    }



  • Someone??


  • Mod

    @john7845 Try printing the value of sensorValue:

    Serial.println(sensorValue);
    


  • Again, I take zeros.



  • Sorry for nuub question but can you use a pro mini 3.3 för this?
    Or do i need a nano or pro mini 5v?



  • @meanmrgreen
    Sure you can use 3.3v for this. If you are using sct-013-000 version, adjust your burden according to

    Burden Resistor (ohms) = (AREF * CT TURNS) / (2√2 * max primary current)
    

    where Aref =3.3 (or at worst case, it's lower than 3.3V- if battery powered)
    Also don't forget to change calibration which is

    Current Calibration Constant = CT TURNS / burden resistor
    


  • One thing to keep in mind with this configuration: you're not actually measuring true power. Rather by not using a voltage reference, you're calculating apparent power, which is measured in VA (Volt Amps) vice Watts.

    For resistive loads, apparent power and real power are the same, or very nearly so. But with reactive loads, e.g. motors, computer power supplies, compact flourescent or LED lamps, etc. they will differ considerably.



  • Hi @patrick-schaerer ,
    I got my setup running and was trying your code.

    I was testing this code on my AC unit which has 1600W max consumption. When I first ran it always reported a value of around 270W even when the AC unit was off from mains and in running condition it reported around 750W with compressor on and around 250W with compressor off.
    I adjusted the value on line

    emon1.current(ANALOG_INPUT_SENSOR, 30);             // Current: input pin, calibration
    

    Tried values from 10 to 111(default as per emon lib) to calibrate it to report 0 in off condition. finally at 10 it reported zero but now when the AC is on it reports 270W max.

    Could you please help me figure out where the problem could be. Thanks



  • Thank for sharing the code and schematics, I cannot get it to run however, I always get 0 value whatever I do. Anyone has a suggestion about how to test this sensor the easiest way?

    I have sct 013 030 sensor, and I connected it using the schematics provided here, I tried even the most basic examples I could find using EmonLib, I tried some basic examples using analog read and what not, but nothing seemed to work properly, I would always get either 0 or some fixed value.
    I am connecting "first" and "last" conneciton on 3.5mm jack, but I also tried all combinations, and nothing seems to make a diffference.
    I am using two resistors of 20Kohm as splitters, I am getting 2.43v between both side of them (using nano on 5V).
    I am wrapping the module around the cable of the water cooker for example, which is 1.5KW, but values never change at all. It is either 0 or some max value (46A f.eks.) either with or without the load.
    I was trying both nano and pro mini, same thing happens. Checked the circuit and connection between components several times.
    This is the simplest code I found on the internet (not even mysensorized)

    void setup() {
    	
    	Serial.begin(9600);
    	analogReference(INTERNAL);
    	//analogReference(INTERNAL1V1); //solo Arduino Mega
    }
    
    void loop() {
    	
    	float Irms=get_corriente(); //Corriente eficaz (A)
    	float P=Irms*220.0; // P=IV (Watts)
    
    	Serial.print("Irms: ");
    	Serial.print(Irms,3);
    	Serial.print("A, Potencia: ");
    	Serial.print(P,3);
    	Serial.println("W");
    	//delay(100);
    }
    
    float get_corriente()
    {
    	float voltajeSensor;
    	float corriente=0;
    	float Sumatoria=0;
    	long tiempo=millis();
    	int N=0;
    	while(millis()-tiempo<500)//DuraciĂłn 0.5 segundos(Aprox. 30 ciclos de 60Hz)
    	{
    		voltajeSensor = analogRead(A0) * (1.1 / 1023.0);////voltaje del sensor
    		corriente=voltajeSensor*30.0; //corriente=VoltajeSensor*(30A/1V)
    		Sumatoria=Sumatoria+sq(corriente);//Sumatoria de Cuadrados
    		N=N+1;
    		delay(1);
    	}
    	Sumatoria=Sumatoria*2;//Para compensar los cuadrados de los semiciclos negativos.
    	corriente=sqrt((Sumatoria)/N); //ecuaciĂłn del RMS
    	return(corriente);
    }
    

    Could it be that here in Norway we use two "phases" in the house? (or I could be wrong here either).

    What is the most easy "idiot" proof way of testing this and getting some values? What could I be doing wrong?
    Should I just order another sensor, can this "simple" sensor even be wrong?

    Any clues, anyone?



  • I never got this going, have to play around with it again, but one thing I did do wrong was put the clip around both wires, instead of just the positive. I.e. putting it around + and - will give 0.



  • Ok so it will not work around both wires?
    You can not clamp it around extension cable and measure "something"?

    I basically just want to detect if stove is on or off, i was hoping to see at least a blip or anything really, can leave without actual numbers..



  • After some research I realized that this cannot work with two wires as they cancel each other.
    After some googling I have found this https://moderndevice.com/product/a1324-hall-effect-sensor/ in description they mention that it can do what I want, to detect if appliance is on or off even if two wires are in close proximity. They mention that you could detect 100W, although I am planning to monitor if stove is on or off, which is I assume more then 100w.
    They also have more precise "boosted" version that is more precise https://moderndevice.com/product/current-sensor/ but I think I do not need it for now.


 

280
Online

7.6k
Users

8.5k
Topics

91.3k
Posts