Request for help with Plugin to measure mains AC current

Moderators: grovkillen, Stuntteam, TD-er

Post Reply
Message
Author
AndrewJ
Normal user
Posts: 229
Joined: 14 Feb 2017, 12:38

Request for help with Plugin to measure mains AC current

#1 Post by AndrewJ » 04 Apr 2017, 20:29

I'm hoping someone with more experience of plugins than me will kindly offer some advice about a plugin I'm developing. At the moment, it works (sort of) but doesn't display its readings on the Devices page.

My plugin is based on the existing Analog ADC Plugin (P002), and also uses interrupt code and calculations from a Henry's Bench arduino sketch. My present code is functioning ok, reading the waveform of the mains AC through a current-transformer sensor module (I'm using a TA12-100). The interrupt routine identifies the peaks in the alternating current, then the main code of the plugin converts this peak data to a RMS (root mean square) value for current, and finally sends the result via MQTT to openHAB2. It also correctly displays the values in the Log. I've begun to set up some parameters which can be entered/changed at runtime in the device configuration page, then saved, such as the ratio of the current transformer, mains voltage, etc. Potentially this could allow the plugin to be used with other sensor devices. So far so good!

The problem I have is this. Whereas all other plugins display the value of their measurements in the Devices screen, at present this isn't happenIng with my plugin :( . I must be missing something. Can anyone help me with some advice about where I'm going wrong, please?

Here is my code, with thanks and acknowledgements to the authors of Plugin 002 and Henry's Bench ....

Code: Select all

//#######################################################################################################
//#################################### Plugin 202: AC current C.T. sensor ###############
//#######################################################################################################

#define PLUGIN_202
#define PLUGIN_ID_202         202
#define PLUGIN_NAME_202       "Analog AC current sensor"
#define PLUGIN_VALUENAME1_202 "nVPP"
#define PLUGIN_VALUENAME2_202 "ACcurrentRMS"
#define PLUGIN_VALUENAME3_202 "ACwatts"

// float Plugin_202_nVPP[TASKS_MAX];                 // Signal voltage measured across C.T. resistor, converted to float.
float Plugin_202_nVPP;
//float Plugin_202_nCurrThruResistorPP[TASKS_MAX];  // peak to peak current through resistor.
//float Plugin_202_nCurrThruResistorPP;
//float Plugin_202_nCurrThruResistorRMS[TASKS_MAX]; // RMS current through Resistor

//float Plugin_202_nCurrentThruWire[TASKS_MAX];     // Actual RMS current in Wire
float Plugin_202_nCurrentThruWire;
//float Plugin_202_watts[TASKS_MAX];                // watts (VA) assuming constant mains voltage and resistive load.
float Plugin_202_watts;

/*
// Parameters (variables so they can eventually be changed via web interface)

 int plugin_202_CT_ratio[TASKS_MAX];  // turns ratio of Current Transformer
 int plugin_202_Resistor_ohms[TASKS_MAX]; // burden resistor value 200
 int plugin_202_mains_volts[TASKS_MAX]; // assumed to be constant voltage 241
 float plugin_202_current_zero_error[TASKS_MAX]; // 93.0 zero correction in mA (from independent measurement)
*/
boolean Plugin_202(byte function, struct EventStruct *event, String& string)
{
  boolean success = false;

  switch (function)
  {

    case PLUGIN_DEVICE_ADD:
      {
        Device[++deviceCount].Number = PLUGIN_ID_202;
        Device[deviceCount].Type = DEVICE_TYPE_ANALOG;
        Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM_BARO;
        Device[deviceCount].Ports = 0;
        Device[deviceCount].PullUpOption = false;
        Device[deviceCount].InverseLogicOption = false;
        Device[deviceCount].FormulaOption = true;
        Device[deviceCount].ValueCount = 3;
        Device[deviceCount].SendDataOption = true;
        Device[deviceCount].TimerOption = true;
        Device[deviceCount].GlobalSyncOption = true;
        break;
      }

    case PLUGIN_GET_DEVICENAME:
      {
        string = F(PLUGIN_NAME_202);
        break;
      }

    case PLUGIN_GET_DEVICEVALUENAMES:
      {
        strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_202));
        strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_202));
        strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_202));
        
        break;
      }

    case PLUGIN_WEBFORM_LOAD:
      {
        char tmpString[256]; // was 128 - too small?

        sprintf_P(tmpString, PSTR("<TR><TD>CT ratio:<TD><input type='text' name='plugin_202_CT_ratio' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
        string += tmpString;

        sprintf_P(tmpString, PSTR("<TR><TD>Resistor ohms :<TD><input type='text' name='plugin_202_Resistor_ohms' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]);
        string += tmpString;

        sprintf_P(tmpString, PSTR("<TR><TD>Mains volts :<TD><input type='text' name='plugin_202_mains_volts' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]);
        string += tmpString;

        sprintf_P(tmpString, PSTR("<TR><TD>Current Zero Error (mA) :<TD><input type='text' name='plugin_202_current_zero_error' value='%u'>"), Settings.TaskDevicePluginConfig[event->TaskIndex][3]);
        string += tmpString;
                
        success = true;
        break;        
      }

    case PLUGIN_WEBFORM_SAVE:
      {

        String plugin1 = WebServer.arg("plugin_202_CT_ratio");
        Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt();

        String plugin2 = WebServer.arg("plugin_202_Resistor_ohms");
        Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt();

        String plugin3 = WebServer.arg("plugin_202_mains_volts");
        Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt();

        String plugin4 = WebServer.arg("plugin_202_current_zero_error");
        Settings.TaskDevicePluginConfig[event->TaskIndex][3] = plugin4.toInt();
        
        success = true;
        break;   
        
      }


    case PLUGIN_WEBFORM_SHOW_VALUES:
      {
/*
        string += ExtraTaskSettings.TaskDeviceValueNames[0];
        string += F(":");
        string += plugin_202_CT_ratio[event->TaskIndex];
//        string += F("<BR>");

        string += ExtraTaskSettings.TaskDeviceValueNames[1];
        string += F(":");
        string += plugin_202_Resistor_ohms[event->TaskIndex];
//        string += F("<BR>");

        string += ExtraTaskSettings.TaskDeviceValueNames[2];
        string += F(":");
        string += plugin_202_mains_volts[event->TaskIndex];
//        string += F("<BR>");

        string += ExtraTaskSettings.TaskDeviceValueNames[3];
        string += F(":");
        string += plugin_202_current_zero_error[event->TaskIndex];
        string += F("<BR>");
*/                
        success = true;
        break;  
      }

       
      
    case PLUGIN_READ:
      {
        Plugin_202_nVPP = (float)Plugin_202_getVPP(); // Calls method below to sample AC waveform and pick up digital signal of peak to peak voltage

           // Convert the digital data to a voltage

            Plugin_202_nVPP *= 3.3;     // NodeMCU works at 3.3v
            Plugin_202_nVPP *= 1.1032;  // empirical range correction 
            Plugin_202_nVPP /= 1024.0;  // 1024 analog values in range.
           
        
        Plugin_202_nCurrentThruWire = (Plugin_202_nVPP / 200.0) * 1000.0;      // 200 = R, 1000 = conversion to mA
        Plugin_202_nCurrentThruWire *= 0.707; // factor for sinewave to convert to RMS

        Plugin_202_nCurrentThruWire *= 1000.0;   // 1000 is CT ratio, current in mA
        Plugin_202_nCurrentThruWire -= 93.0;  // 93.0 is zero error
         if (Plugin_202_nCurrentThruWire < 0.0 ) {
            Plugin_202_nCurrentThruWire = 0.0;          
        }

//        Plugin_202_watts = 241.0 * Plugin_202_nCurrentThruWire / 1000.0; // 241 = Plugin_202_mains_volts
          // calculate watts (V*A), assumes constant mains voltage and 100% PF (pure resistive load)
          Plugin_202_watts = Plugin_202_nCurrentThruWire * Settings.TaskDevicePluginConfig[event->TaskIndex][2]; // multiply by mains volts
          Plugin_202_watts /= 1000.0; // convert mW to Watts
                
        UserVar[event->BaseVarIndex] = (float) Plugin_202_nVPP; // peak to peak signal volts
        UserVar[event->BaseVarIndex+1] = Plugin_202_nCurrentThruWire; // RMS AC current in mA 
        UserVar[event->BaseVarIndex+2] = Plugin_202_watts; // Watts   
        
        String log = F(" BaseVar  : ");
        log += UserVar[event->BaseVarIndex];
        log += F(" BaseVar+1 : ");
        log += UserVar[event->BaseVarIndex+1];
        log += F(" BaseVar+2  : ");
        log += UserVar[event->BaseVarIndex+2];
        addLog(LOG_LEVEL_INFO,log);

                   
        success = true;
        break;
      }
  }
  return success;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//////////////// Function to read peak to peak signal volts from CT sensor unit  //////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

        float Plugin_202_getVPP() {       // was float
//         int result;                   // was float
          int readValue;             // instantaneous volt value read from the sensor
          int maxValue = 0;          // store max voltvalue here
          uint32_t start_time = millis();
          
          while((millis()-start_time) < 100) //sample for 100 milliSec, each cycle of mains is 1/50th sec = 20 millisec
            {
              readValue = analogRead(A0); // read digital signal representing instantaneous volt value from sensor (0-254)
              // see if we have a new maxValue
               if (readValue > maxValue) 
              {
                 // record the maximum sensor value
                maxValue = readValue;
              }
            }
/*
            // Convert the digital data to a voltage
            result = (maxValue * 3.3 * 1.1032)/1024.0;  // NodeMCU works at 3.3v
   //                                         1.1032 = empirical range correction 
   //                                         factor to match meter.
   //                                         1024 analog values in range.
*/
    //        result = maxValue;  // temporary for debug!   
         return maxValue;
        }



.. and here is a screenshot of my Devices page (with no values from this plugin) ...
Devices.PNG
Devices.PNG (19.99 KiB) Viewed 6875 times
... and my device configuration screen for the plugin...
Device_config.PNG
Device_config.PNG (43.48 KiB) Viewed 6875 times
All help and advice welcome! Thanks in advance!.
AndrewJ

User avatar
costo
Normal user
Posts: 500
Joined: 21 Nov 2015, 15:03
Location: NL, zw-NB

Re: Request for help with Plugin to measure mains AC current

#2 Post by costo » 05 Apr 2017, 15:26

Hi andrewj, I really like the effort you do to make a plugin for measuring 50/60 Hz AC current.

I cannot help you with the code.

You say that after multipliing your highest current value with 0.707 it is the RMS value.
That is not true. You get the average value after correcting the max value of a sine wave by 0.707.
For a near perfect resistive load, like a heating element or a old school light bulb, that will be ok and when multiplied with the average voltage (230) you will get a accurate power value.
You get in trouble when calculating power for inductive orcapacitive loads becouse Cos.Phi is not equal to 1.

Calculating RMS (Root Means Square) takes some more mathematics. You need to take a lot of readings during one cycle ,20 millseconds at 50 Hz, Square each single value add all the values together and take the square root of the total. That will be , by defenition, the RMS value.

edit: wrong definition read:
Square each single value, add all the squared values together, divide this total by the number of samples and take the square root of that value.

AndrewJ
Normal user
Posts: 229
Joined: 14 Feb 2017, 12:38

Re: Request for help with Plugin to measure mains AC current

#3 Post by AndrewJ » 06 Apr 2017, 23:26

Hi all,
Thanks Costo for the information about RMS, that is useful, but I wonder if the ESP8266 would handle all the calculations of squares etc. (I don't mind too much if the readings are not perfectly accurate, as I'm mainly interested in the trends of the data.)

I've made some progress since my first post, and partly solved the problem. Looking at my plugin afresh, I realised that the majority of the PLUGIN_WEBFORM_SHOW_VALUES section was commented out. I now remember doing this to isolate the source of some compile errors earlier in the life of the plugin, but I had never gone back and uncommented this part :oops:

When I uncommented it, I immediately got errors. After some head-scratching, I realised that I had lines such as

Code: Select all

 string += plugin_202_CT_ratio[event->TaskIndex] 
. These referred to my configurable parameters, not to measured variable values.

So I changed the section to this...

Code: Select all

    case PLUGIN_WEBFORM_SHOW_VALUES:
      // This section displays most recent measured values in the "Devices" table of the web interface....
      
      {
        string += ExtraTaskSettings.TaskDeviceValueNames[0];
        string += F(":");
        string += UserVar[event->BaseVarIndex];
        string += F("<BR>");

        string += ExtraTaskSettings.TaskDeviceValueNames[1];
        string += F(":");
        string += UserVar[event->BaseVarIndex+1];
        string += F("<BR>");

        string += ExtraTaskSettings.TaskDeviceValueNames[2];
        string += F(":");
        string += UserVar[event->BaseVarIndex+2];
        string += F("<BR>");
/*
        string += ExtraTaskSettings.TaskDeviceValueNames[3];
        string += F(":");
        string += plugin_202_current_zero_error[event->TaskIndex];
        string += F("<BR>");
*/                
        success = true;
        break;  
      }
.....and it now compiles and displays the values in the Devices table page. :D
Devices_corrected.PNG
Devices_corrected.PNG (25.23 KiB) Viewed 6798 times

BUT (there's always a "but" isn't there?) the green colour around the values is missing... :(

I've been looking in the web interface code to try to spot how this is controlled, but without success so far. Could someone kindly give me some advice?
Thanks in advance,
Andew

papperone
Normal user
Posts: 497
Joined: 04 Oct 2016, 23:16

Re: Request for help with Plugin to measure mains AC current

#4 Post by papperone » 08 Apr 2017, 09:22

Honestly I gave up trying to have a proper AC current/power monitor with ESPEasy...
Nothing was working reliable so I got the EMONEMC firmware rewrote most of it to adapt to ESP8266 using a better DAC (ADS1115 16 bit, not fast but does it job) and I've a very accurate Vrms Irms reading for my home.
I installed it currently near the main meter, it send reading every 30sec to my MQTT broker and then I log all to an SQL database. It's still under "beta version" as I'm fine tuning the algorithm but much more advanced of what I was trying to achieve with ESPEasy!
My TINDIE Store where you can find all ESP8266 boards I manufacture --> https://www.tindie.com/stores/GiovanniCas/
My Wiki Project page with self-made PCB/devices --> https://www.letscontrolit.com/wiki/inde ... :Papperone

AndrewJ
Normal user
Posts: 229
Joined: 14 Feb 2017, 12:38

Re: Request for help with Plugin to measure mains AC current

#5 Post by AndrewJ » 08 Apr 2017, 12:39

Thanks papperone, I may end up going the same way as you or similar, but I'll keep trying a bit longer with the ESP8266 and ESPeasy plugin. It is working fairly well for me with the latest version of my plugin. There are just 2 remaining issues:
1. The readings agree with my plug-type meter at the mid range, but not across the whole range, so I need to resolve that,
2. (cosmetic) the values now showing in the Devices table are not highlighted green. Definitely not a show-stopper, but for my own learning I'd like to find out why.

Good luck with your beta code, and please share when you feel ready.
AndrewJ

krikk
Normal user
Posts: 118
Joined: 28 Feb 2017, 07:57
Location: Austria
Contact:

Re: Request for help with Plugin to measure mains AC current

#6 Post by krikk » 08 Apr 2017, 14:26

can only recommend to read all the info over there at openenergymonitor, the info on there page, was the reason i bought their solution instead of building it by myself... :)

Shardan
Normal user
Posts: 1156
Joined: 03 Sep 2016, 23:27
Location: Bielefeld / Germany

Re: Request for help with Plugin to measure mains AC current

#7 Post by Shardan » 08 Apr 2017, 16:17

Hello all,

i've made two different solutions for me:

For power consumption i use a counter module.
They can be mounted in the distribution box and the pulse output can safely be connected to an ESP or other devices.
Security comes first, i tend to avoid selfmade circuitry with mains power.

For just measuring current i'm making up a prove of concept atm.
I have some PDU boxes, just 7 outlets in the back and switches in the front.
For measuring current i plan to use small current transformers like this:
Current-Transformer.jpg
Current-Transformer.jpg (16 KiB) Viewed 6739 times
The advantage: It's completely galvanic isolated.
I've already made a circuit for this, allowing switching of the outlets and measuring current
but it is not tested yet due to lack of time.
PowerManager-PCB.jpg
PowerManager-PCB.jpg (270.05 KiB) Viewed 6739 times
It uses 2 x ADS1115. Disatvantage is that it just measures current, not active / reactive current or such.
If anyone is interested i can publish the schematics, but be aware it is not tested yet.

Regards
Shardan
Regards
Shardan

AndrewJ
Normal user
Posts: 229
Joined: 14 Feb 2017, 12:38

Re: Request for help with Plugin to measure mains AC current

#8 Post by AndrewJ » 08 Apr 2017, 22:06

Thanks for responses. The sensor module I am using also has a current transformer TA12-100, which provides complete isolation from mains (line) voltage. This was the big attraction.
I am using this ESP8266/ESPeasy module to measure AC current consumption (and thus estimate power) for individual appliances (currently my oil-fired central heating boiler system, pump and fan). Separately I have another ESP8266 next to my distribution box which is running a pulse counting sketch (not yet ESPeasy!) which is reliably reporting total power consumption of my house by reading the LED flashes on my main electric meter.

Coming back to my original, or rather second, question - please could somebody explain how the normal green background around the measured values (in the Devices table) is generated? I'd really like to get that right for completeness, and also for my own learning about how the plugins and the framework together should function.

Thanks in advance
AndrewJ

Post Reply

Who is online

Users browsing this forum: Google [Bot] and 37 guests