PV router - linky problem

Hi all

My name is David, I live in France.

I installed 6 solar panels, I operate in self-consumption and so I built my own PV router based on “énergie autrement” by Barnabé Chaillot Tout sur l'autoconsommation photovoltaique #5 - YouTube

I am commissioning the system since yesterday, and all is well working from the screen of my PV meter :

PV energy : 600W

Water tank energy : 300W ( water tank 300l – 3000W)

Home consumption is well regulated around 0W (confirmed by direct measure with courant meter)

The problem is from my Linky counter, on the consumption screen I observe 800W!!

When the triac is not operating, the power seen from my screen and linky screen is the same.

I Think there is a perturbation from the triac with Linky

Is there anyboby who already observe such a phenomena?

Thank you for assistance

David

Sorry for the Ctr_V mistake.
And please try to use quite simple enghish as my understanding is sometime limited. :wink:

David

Bienvenue David au OEM

We do not know about M. Chaillot here, I know only the Mk2 PV Router by Robin Emley.

If M. Chaillot’s router is like Robin’s, then I think you are correct - the problem is with the Linky.

It is possible that Linky ignores the energy that is returned to the electricity company by your PV, or maybe worse, it charges you for energy you export to them in addition to the energy you use!

As I understand “smart” meters (like Linky), each one can be programmed differently by the maker according to the instructions of the electricity company that you buy your energy from. It is possible that there is no easy DIY solution to your problem - there might be no solution at all.

Thank you Robert
To simplify my question, without talking of the PV, just when I try to regulate the power with the triac here below, linky see the wrong power, I realy think it is du to bad quality of the triac (harmonic problem)

Do you have experience of using other type of power regulation, such static relay or beter triac?

David

1 Like

How do you know? If you have an ammeter and you are measuring current, you will not read the correct current if your triac is phase-controlled (commande de phase) and your ammeter does not read true rms (valeur moyenne quadratique vrai). Even if your ammeter does read true rms, it might only be correct over a limited range for the shape of the current wave. The reason is, the triac regulates the current by switching on at varying times during each half-cycle of the mains electricity.
https://www.electronics-notes.com/images/triac-switching-waveform.svg
If it switches on early, you get maximum power. If it switches on half-way, you get half power, and if it switches on very late, you get a very low power.

I do not measure the current after the triac but on it supply; so I measure a sinus normaly.
I saw on Robin Emley site that he was using (I think for an older version of his system) a static relay… how is it working?

It does not matter where you measure the current - it is still the same before and after the triac.

The Mk2 PV Router uses “Burst fire” mode. The triac switches on for a number of whole cycles, then remains off for a number of whole cycles. It always switches on at the beginning of each cycle.
Phase control and burst fire are both illustrated on this page:
https://learn.openenergymonitor.org/pv-diversion/mk2/switchdev

Very interresting … I think it can work in my case, maybe less problem of harmonic with this kind of regulation.
I have to read all the very interresting documentation of Robin.
What is the cost of a compete MK2 system?

Thanks

I can add this part (from mk2) to my system:

Opto-isolator is piloted by a 0-5V? and do you know which % of power step I will have with this monting?

Robin is not selling kits at this time. You can see the prices in GBP on his website mk2pvrouter.co.uk The basic kit is £80 plus postage to France. I think postage will cost approximately £14.

The opto-isolator is current-operated. The Atmel ATMega328P runs at 5 V or 3.3 V, therefore the series resistor for the opto-isolator (R1) is 180 Ω when the power supply is 5 V, the resistor is 120 Ω when the voltage is 3.3 V).

If I remember correctly, there is the “Mk2_fasterControl_1a” sketch that works well with Linky meters, though I cannot guarantee that it will work with yours.

Hi David – if you want to try mine version of a energy diverter. I use the fotek SSR that you show ( only in 80 amp) and built home made SSR based on BTA41A… and i being using mine now for 3 years with out issue… but my grid is 60hz but I just made one that universal for any hz - self detecting and configures … you just have to adjust the FRAC and see what the best pulse is for you as I have no experience with 50hz… – how do I determine that is set up a properly is use a ~ -50watt source that shows negative ( imitating uploading to the grid) and then on the element side put small induction motor of some form ie hair dryer or small vent fan-- and then let it pulse it way up it should start turning the the motor at about 10 rpm near it lowest setting and should be fairly smooth all the way up to the to full speed …

this is my cutting edge version so i have not tested it much and nothing with 50hz. but my older version based on standard pwm signal have worked for over 3 year with out issue

65535 step pwm
diveter-auto-hz-detection-65535.zip (5.1 KB)

255 step pwm
Diverter-auto hz-standard.zip (4.9 KB)

these current ones use
servo hardware pwm 16 bit from the Arduino library

you can set it to only use one SSR just set ios to 1 and the grid is CT3 the 16 pwm code is cleaner as I currently was interest in how well that one works ( the 255 - 8 bit version ) works fine it just needs some lines reorder and some safety functions – disabling the PWM if the ac adapter fails…

I also be curious if it works with 50 hz systems

here the orginal oem link

Thank you Stephen,
It seems to be an other possibility for me… do you know what are the % of power with 5V aduino 8bit (255step) with opto isolator compared with your SSR system?
Also do you have an electric drawing explaining your instalation ? how is pilot the SSR?

hi there the installation is just on top of an emontx arduino shield with stackable header

and then a cat45 to where the SSR are located in my case about 20 feet from the location of emontx shield( wemos uno/wifi board it can be just an ordinary uno if you like if you do not wish the send the info to a database)

and then the connector board where you wire the SSR too.

part23

if you are building your own SSR with triac moc3043 i find work the best as they will work with both 5 volt and 3 volt systems

here if you were curious - here is the 16 bit Diverter firing a standard FORTEK SSR-40-DA it slowly going up through the steps ( not all 65000 of them it going through about 120 different blocks of about 500 steps from 0 -65535) as it bubble searching for the correct step…

you see the 1% is slow pulse , and slowly increases the fan speed… at the end is 100% fan speed you see that the even though it doing a bubble search it way through trying to find the correct pulse the speed increase is fairly smooth and precisely

this is the exact sketch with my setting set at 1 SSR
FRAC set at 4
but I added another function before it fires the PWM it delays it a 1/4 cycle and then pulse begins…

diverter_16bit_autohz.zip (5.1 KB)

Hey Stephen,
I begin to built your PV router, I am now waiting for the Fortek delivery


I already reach to measure the voltage, frequency and the 3 power
As my system is :
50Hz - 240V
only 1 SSR 80DA driving the water heater (waiting delivry)
power of the water heater 3000W
PV installed 1300Wc

Could you confirm the setting I have to use… I don’t understand yet all the logic of the program particulary the FRAC parameter

#define FILTERSETTLETIME 5000 //  Time (ms) to allow the filters to settle before sending data  
#include "EmonLib.h"
EnergyMonitor ct1,ct2,ct3, ct4;   // Create  instances for each CT channel

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
#include <PWM.h>

//###### Adjustable settings ####### 
int upperRANGE = 15; // the range in which it will not search for better output 
int lowerRANGE = -15;

int PWM =1 ;  //1=enables PWM.h  smother output 0=disable
int FRAC =4 ;  // fraction of grid Hertz ie  60hz-> 2=1/2 (30hz pwm)   4 =1/4 (15 hz pwm)

const int CT1 = 1;          //  divert sensor - Set to 0 to disable if using  optional  diaplay ( wind)
const int CT2 = 1;         // Inverter sensor - Set to 0 to disable 
const int CT3 = 1;        //grid sensor 
const int CT4 = 0;       // windgen  sensor - Set to 0 to disable  disable if using diverter display
int LCD = 1;             // 1=enable 0=disable
float element = 3000; //wattage of  element  for diversion -  make bigger  then then what you have to decrease  buuble search sensitivity
int SSR4 =1;          // 1=  4 ssr and disables static,  0=  3 SSR & 1 static ( disable PWM.h)
int ios = 3;          /// Number of SSR to control 4 MAX if PWM.h diasble otherwise 3
int pulse = 11;       // pin for pulse  disable if you cascade on 4 ssr  pin 11 does not work if PWM.h enabled 
int pulse1 = 9;
int pulse2 = 10;
int pulse3 = 3;
int pulse4 = 11;     //enable pulse 4 if you wish 4 cassacding ssr
float DRIFT =1 ;      // if you wish to adust hz output 

int invstatus = 5;    // pin for led display  showing overproduction 
int type = 1;         // 0= casdading -  1 = equal for diverting 
int ssr=0;            // 0= zerocrossing 1 = phase angle  currently only supports one ssr 
int AVG=5;

 //#### Non - adjustable 
 int power1=0;
 int power2=0;
 int power3=0;
 float volt=0;
 int avg_255 =0;
 int avg_ios=0;
 
 int count =0;
int count2 =0;
int count3=0;
int  FREQ;
float FREQ_F = 0;
const int aIn = 0;
int positive;
unsigned long period;
unsigned long mark;
 
float grid = 0;     //grid   usage
float stepa = 0;   // 
float stepb = 1;
float stepc = 1;
float prestep =1;
float step1 = 0;   // 
float step2 = 1;
float step3 = 1;
float prestep1 =1;
float curinvt = 1; //percentage of power uage comparison over or below grid usage 
float curelem =1;
float kw = 0;
int curgrid = 0;       // current  PMW step
int curgrid2 = 0;     //current triac step
float invert =100;
float wind = 100;
float diverter =100;
float per = 0;
int stat ;
int stepbu;
float stepa4 = 0;   
float stepb4 = 1;
float stepc4 = 1;
float prestep4 =0; 
int stepbu4;
int stat4 ;
float curelem4 =1;
int curgrid4 = 0;
int sV;
int full;
int DIVERT = 0;
String value;
int percent = 0;
float TMP;
float DIVS;

typedef struct { int power1, power2, power3, power4, Vrms;} PayloadTX;      // create structure - a neat way of packaging data for RF comms
PayloadTX emontx;                                                       
 
boolean settled = false;

void setup() 
{
  
 //############### pwm pulse freq  for  standard pwm  #####################
 TCCR1B = TCCR1B & B11111000 | B00000101; // for PWM frequency of 30.64 Hz 9 10
 //TCCR0B = TCCR0B & B11111000 | B00000101; // for PWM frequency of 61.04 Hz 5 6
 TCCR2B = TCCR2B & B11111000 | B00000111; // for PWM frequency of 30.64 Hz 3 11
 //#########################
 if (PWM ==1){
   InitTimersSafe();  
 }  
  Serial.begin(115200);
  
 //##############LCD##################################
  if (LCD==1) {
   lcd.init();                      // initialize the lcd 
  lcd.init();
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(3,0);
  lcd.print("Power Diverter");
  lcd.setCursor(2,1);
  lcd.print("Stephen krywenko!");
  }

//################ detect Hz ############### 

  boolean st=false;                                  //an indicator to exit the while loop

  unsigned long start = millis(); 
  
  while(st==false) {
  
 while((millis()-start)<200 && analogRead(aIn)>512  );//wait for positive half period to expire
  while((millis()-start)<200 && analogRead(aIn)<512 );//wait for negative half period to expire
  //Serial.println("zero crossing");
  mark = micros();//zero crossing from negative to positive found
  while((millis()-start)<200 && analogRead(aIn)>512 );//wait for positive half period to expire
  while((millis()-start)<200 && analogRead(aIn)<512 );//wait for negative half period to expire
  period = micros()-mark;
  FREQ = ( 1000000 / period);
Serial.println(FREQ);
//Serial.println(analogRead(aIn));
 st = true;
 
 if (period < 5000){
  
  if (count ==0){
  Serial.println("plug in AC adaptor");
       if (LCD==1) {
          lcd.backlight();
          lcd.clear();  
          lcd.setCursor(0,2);
          lcd.print("Check AC Adaptor");
     }
  
  count++;
  
  }
  st = false;
  delay(10000);
 start = millis();
  
 }
  } 
  pinMode(pulse, OUTPUT); 
  if (PWM == 0){
  pinMode(pulse1, OUTPUT); 
  pinMode(pulse2, OUTPUT);
  analogWrite(pulse1, 0 );
  analogWrite(pulse2, 0 ); 
  }
  pinMode(pulse3, OUTPUT); 
  pinMode(pulse4, OUTPUT); 
  analogWrite(pulse3, 0 );
  analogWrite(pulse4, 0 );  //Enable  if you wish to cascade on  4 ssr /disable  pulse other below

   DIVS= 1 ;           // pwm step
  // DIVS= ios*2.55 ;  // percentage of usable steps

//###################### emontx settings  #######################

  if (CT1) ct1.current(1, 30.00);                                     // Setup emonTX CT channel (ADC input, calibration)
  if (CT2) ct2.current(2, 30.00);                                     // Calibration factor = CT ratio / burden resistance
  if (CT3) ct3.current(3, 30.00);                                     // emonTx Shield Calibration factor = (100A / 0.05A) / 33 Ohms
  if (CT4) ct1.current(1, 30.00); 
  
  if (CT1) ct1.voltage(0, 244, 1.7);                                // ct.voltageTX(ADC input, calibration, phase_shift) - make sure to select correct calibration for AC-AC adapter  http://openenergymonitor.org/emon/modules/emontx/firmware/calibration. Default set for Ideal Power adapter                                         
  if (CT2) ct2.voltage(0, 244, 1.7);                                // 268.97 for the UK adapter, 260 for the Euro and 130 for the US.
  if (CT3) ct3.voltage(0, 244, 1.7);
  if (CT4) ct1.voltage(0, 244, 1.7);


 FREQ = FREQ/FRAC;
  count=0;    
  if (PWM==1){
    SetPinFrequency(pulse1, FREQ); 
    SetPinFrequency(pulse2, FREQ);                                                                               
  }
}

//####### Grid Hertz detection ##################

 void Grid_Hz(){
  
  boolean DONE = false; 
 
 while(DONE==false)
 {

period = 0;
unsigned long start = millis(); 
 while((millis()-start)<200 && analogRead(aIn)>512  );//wait for positive half period to expire
 while((millis()-start)<200 && analogRead(aIn)<512 );//wait for negative half period to expire
  //Serial.println("zero crossing");
  mark = micros();//zero crossing from negative to positive found
  while((millis()-start)<200 && analogRead(aIn)>512 );//wait for positive half period to expire
  while((millis()-start)<200 && analogRead(aIn)<512 );//wait for negative half period to expire
  period = (micros()-mark);
  DONE = true;

  if (period < 10000){
    if (count2 ==0){
    
     Serial.println("Check  AC adaptor");
     count2++;     
     }
          if (LCD==1) {
          lcd.backlight();
          lcd.clear();  
          lcd.setCursor(0,2);
          lcd.print("Check AC Adaptor");
     }
         count=0;
         FREQ_F=0;
         //##### disable pwm  safty measure #######
         pwmWrite(pulse1, 0);
         pwmWrite(pulse2, 0);
         analogWrite(pulse3, 0);
         analogWrite(pulse4, 0);
         analogWrite(invstatus, 0);
        // analogWrite(invstatus2, 0);
         analogWrite(pulse, 0);
         delay(1000);
         DONE = false;  
         start = millis();      
  }else
  {
    count2=0;
  FREQ = ( 1000000 / period);
  FREQ_F = FREQ_F+ FREQ;
  count++;

  
  if (count ==10){ 
  // Serial.print("Frequency =  "); Serial.println(FREQ_F/10);
   Serial.print("TaskValueSet,2,3,"); Serial.println((FREQ_F/10)*DRIFT); //Frequency
    count=0;
    FREQ_F=0;
  }
 }}}

//############## PWM.h  setting pulse if used #########
 
void settingPWM( int _PIN, int _PWM)
{ 


  while(analogRead(aIn)>512);//wait for positive half period to expire
  while(analogRead(aIn)<512);//wait for negative half period to expire
  delayMicroseconds(period/2);

   pwmWrite(_PIN,_PWM ); 

   /*
      while(analogRead(aIn)>512);//wait for positive half period to expire
  while(analogRead(aIn)<512);//wait for negative half period to expire
   //setting the duty to 50% with the highest possible resolution that 
   //can be applied to the timer (up to 16 bit). 1/2 of 65536 is 32768.
   pwmWriteHR(led, 32768);
   //Serial.println("High Resolution PWM");
   delay(1000);*/

}


void loop() 
{ 
 count3++;
 
  if (CT1) {

    ct1.calcVI(20,2000);                                                  // Calculate all. No.of crossings, time-out 
    emontx.power1 = ct1.realPower;
    diverter =  emontx.power1;
    power1= (power1+emontx.power1);
    if (count3 >= AVG){
      power1=(power1/AVG);
    Serial.print("TaskValueSet,1,3,"); Serial.println(power1);
    }                                 
  }
  
  emontx.Vrms = ct1.Vrms*100;                                            // AC Mains rms voltage 
  
  if (CT2) {
   
    ct2.calcVI(20,2000);                                                  // Calculate all. No.of crossings, time-out 
    emontx.power2 = ct2.realPower;
    invert = emontx.power2;
    power2=(power2+emontx.power2);
    if (count3 >= AVG){
    power2=(power2/AVG);
    Serial.print("TaskValueSet,1,2,"); Serial.println(power2);  
    }
  } 

  if (CT3) {
    ct3.calcVI(20,2000);                                                  // Calculate all. No.of crossings, time-out 
    emontx.power3 = ct3.realPower;
    grid = emontx.power3; 
    power3=(power3+emontx.power3);
    if (count3 >= AVG){
   power3=(power3/AVG);
    Serial.print("TaskValueSet,1,1,"); Serial.println(power3);
    }
  } 
  
   if (CT4) {
     ct1.calcVI(20,2000);                                                  // Calculate all. No.of crossings, time-out 
    emontx.power1 = ct1.realPower;
    wind = emontx.power1; 
    power1=(power1+emontx.power1);
    if (count3 >= AVG){
    power1=(power1/AVG);
    Serial.print("TaskValueSet,1,3,"); Serial.println(power1);
    
    }

  }
  volt= (volt+ct1.Vrms);
  /*
  if (count3 >= AVG){
    
   volt=volt/AVG;
   Serial.print("TaskValueSet,1,4,"); Serial.println(volt);
   power1=0;
   power2=0;
   power3=0;
   volt=0;
   count3=0;
   }*/
   
 //######################## Start if bubble Search ###########################
 
  if (invert <0){       // for capture ac adaptor errors is it display consant zero on inverter display -- ct or ac adaptor need to be reversed
    invert = 0;
  }
  if (wind <0){       // for capture ac adaptor errors is it display consant zero on inverter display -- ct or ac adaptor need to be reversed
    wind = 0;
  }
  
/////############### old code left in for later modification #################
if (grid != 0 ) {  
if (invert >=0) {

  step1 = ( grid / invert);
  prestep1 = (step2);

step2 = (prestep1 + step1);
  if (step2 > 1) {
    step2 =1;
  }
  if (step2 < 0) {
    step2 = 0;
  }
  curinvt = (0  + step2);
  curgrid2 = ( 254 * curinvt  );
  curgrid2 =(254-curgrid2);  //inverts the value of curgrid if need be 
}
}
//#############################################################
//################# Cascading bubble search ###################
if (CT3){
if ( (grid < lowerRANGE) || (grid > upperRANGE)){   
//if (grid !=0) {
  //curgrid = 0;
  stepc = (grid / element); 
  prestep = (stepb);

stepb = (prestep + stepc);
  if (stepb > 0) {
    stepb =0;
  }
  if (stepb < (0-ios)) {
    stepb = (0-ios);
  }
  curelem = (0  + stepb);
stepbu=curelem;
curelem = (curelem - stepbu);
  curgrid = ( 254 * curelem  );
  curgrid =(0-curgrid);  //inverts the value of curgrid if need be 
}

//############ static bubble search ###############################
if ( (grid < lowerRANGE) || (grid > upperRANGE)){ 
//if (grid !=0) { 
  //curgrid = 0;
  stepc4 = (grid / element); 
  prestep4 = (stepb4);

stepb4 = (prestep4 + stepc4);
  if (stepb4 > 1) {
    stepb4 =1;
  }
  if (stepb4 < 0) {
    stepb4 = 0;
  }
  curelem4 = (0  + stepb4);
  curgrid4 = ( 255 * curelem4  );
  curgrid4 =(255-curgrid4);  //inverts the value of curgrid if need be 
}

}
//##################  determines  location of  cascading SSR ############
int statc ;
int ivar;
int statb ;

stat = (0-stepbu);
if (curgrid==256){curgrid=0;}

if (stat > (ios-1)) {stat=(ios-1);curgrid=255;full=1;}
if (stat ==0) {ivar = 1;}
else  {ivar = 0;}

//################### end of bubble search ######################


//################### Pusle  for triac or ssr ###################


if (ssr ==0){

  boolean st=false;                                  //an indicator to exit the while loop

  unsigned long start = millis();                    //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

  while(st==false)                                   //the while loop...
  {
    sV = analogRead(0);                              //using the voltage waveform
    if ((sV < (1024*0.55)) && (sV > (1024*0.45))) st=true;  //check its within range
    if ((millis()-start)>2000) st = true;
  }

  DIVERT = curgrid;
     //DIVERT=map(DIVERT,0,255,0,120);                    //delay before pulse  
    // DIVERT=map(DIVERT,0,120,0,255);  

//##############Static Pulse###############//
if (SSR4 ==0){
analogWrite(pulse,curgrid4);  // single pulse signal for SSR off arduino board // disable if you want 4 cascading ssr
avg_255=avg_255+curgrid4;
if (count3 >= AVG){
avg_255=avg_255/AVG;
Serial.print("TaskValueSet,2,2,"); Serial.println(avg_255); //curgrid4
}
}
//############################//
//########## Cascading Pulse ####### 
Grid_Hz();

  if ( type == 0){
   // Serial.println(" solar Diversion - Cascading");
if (stat != statb) {
  statc=(stat+1);
  statb=stat;
  for(int i=ivar;i < stat; i++){
   
if ( i == 0){
  if (PWM ==0 ){
  analogWrite(pulse1, 255 );
  }else{
    settingPWM(pulse1, 255);
  }
}
if ( i == 1){
  if (PWM ==0 ){
  analogWrite(pulse2, 255 );
  }else{
    settingPWM(pulse2, 255);
  }  
  analogWrite(pulse2, 255 );
}
if ( i == 2){
  analogWrite(pulse3, 255 );
}
if ( i == 3){                   //enable for 4th ssr
  analogWrite(pulse4, 255 );
}
  }
   
  for(int i=statc;i <ios; i++){
if ( i == 0){
  if (PWM ==0 ){
  analogWrite(pulse1, 0 );
  }else{
    settingPWM(pulse1, 0);
  }
}
if ( i == 1){
  if (PWM ==0 ){
  analogWrite(pulse2, 0 );
  }else{
    settingPWM(pulse2, 0);
  }
}
if ( i == 2){
  analogWrite(pulse3, 0 );
}
 if ( i == 3){                  //enable for 4th ssr
  analogWrite(pulse4, 0 );
}
     }
     }


if ( stat == 0){
   while((millis()-start)<200 && analogRead(aIn)>512  );//wait for positive half period to expire
  while((millis()-start)<200 && analogRead(aIn)<512 );//wait for negative half period to expire
  //Serial.println("zero crossing");
  delayMicroseconds(period/2);
 if (PWM ==0 ){ 
  analogWrite(pulse1, DIVERT );
  analogWrite(pulse2, 0 );
 }else{
  settingPWM(pulse1, DIVERT);
  settingPWM(pulse2, 0);
 }
  analogWrite(pulse3, 0 );
  if (SSR4 == 1){
  analogWrite(pulse4, 0 );                  //enable for 4th ssr
  }
  percent = ((DIVERT)/DIVS);
  avg_ios=avg_ios+percent;
  if ( count3 >= AVG){
  avg_ios= avg_ios/AVG;
  Serial.print("TaskValueSet,2,1,"); Serial.println(avg_ios);  // percent --  Diverter Percentage 
  }
}
if ( stat == 1){
   while((millis()-start)<200 && analogRead(aIn)>512  );//wait for positive half period to expire
   while((millis()-start)<200 && analogRead(aIn)<512 );//wait for negative half period to expire
 //Serial.println("zero crossing");
   delayMicroseconds(period/2);
  if (PWM == 0){
  analogWrite(pulse2, DIVERT );
  }else{
   settingPWM(pulse2, DIVERT); 
  }
  analogWrite(pulse3, 0 );
  if (SSR4 == 1){
  analogWrite(pulse4, 0 );  //enable for 4th ssr
  }
 TMP = (DIVERT+255); percent = (TMP/DIVS);
 
  avg_ios=avg_ios+percent;
  if ( count3 >= AVG){
  avg_ios= avg_ios/AVG;
  Serial.print("TaskValueSet,2,1,"); Serial.println(avg_ios);  // percent --  Diverter Percentage 
  }
}
if ( stat == 2){
   while((millis()-start)<200 && analogRead(aIn)>512  );//wait for positive half period to expire
  while((millis()-start)<200 && analogRead(aIn)<512 );//wait for negative half period to expire
 if (PWM == 0) delayMicroseconds(period/2);
  //Serial.println("zero crossing");
  analogWrite(pulse3, DIVERT );
  if (SSR4 == 1){
  analogWrite(pulse4, 0 );                  //enable for 4th ssr
  }
 TMP = (DIVERT+510);  percent = (TMP/DIVS);
   avg_ios=avg_ios+percent;
  if ( count3 >= AVG){
  avg_ios= avg_ios/AVG;
  Serial.print("TaskValueSet,2,1,"); Serial.println(avg_ios);  // percent --  Diverter Percentage 
  }
}
if ( stat == 3){
   while((millis()-start)<200 && analogRead(aIn)>512  );//wait for positive half period to expire
  while((millis()-start)<200 && analogRead(aIn)<512 );//wait for negative half period to expire
 delayMicroseconds(period/2);
  //Serial.println("zero crossing");
  analogWrite(pulse4, DIVERT );                  //enable for 4th ssr
  TMP = (DIVERT+765); percent = (TMP/DIVS);
    avg_ios=avg_ios+percent;
  if ( count3 >= AVG){
  avg_ios= avg_ios/AVG;
  Serial.print("TaskValueSet,2,1,"); Serial.println(avg_ios);  // percent --  Diverter Percentage 
  }
}    
  }

 //####### Unison   pulse ######### 
    
  if (type == 1){
   // Serial.println(" solar Diversion -  In Unison");
    for(int i=0;i < ios; i++){

 DIVERT = curgrid ;

if ( i == 0){
  analogWrite(pulse1, DIVERT );
}
if ( i == 1){
  analogWrite(pulse2, DIVERT );
}
if ( i == 2){
  analogWrite(pulse3, DIVERT );
}
if ( i == 3){
  analogWrite(pulse4, DIVERT );                  //enable for 4th ssr
}
 percent = (DIVERT/DIVS);
   avg_ios=avg_ios+percent;
  if ( count3 >= AVG){
  avg_ios= avg_ios/AVG;
  Serial.print("TaskValueSet,2,1,"); Serial.println(avg_ios);  // percent --  Diverter Percentage 
  }
  } 
  }

analogWrite(invstatus, curgrid4);      // led display  showing overproduction 

}

//############################# phase angle #########################
      if (ssr==1){
    
    //####### Zerocrossing #######
        
      boolean st=false;                                  //an indicator to exit the while loop
      unsigned long start = millis();                    //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

  while(st==false)                                       //the while loop...
  {
    sV = analogRead(0);                                  //using the voltage waveform
    if ((sV < (1024*0.55)) && (sV > (1024*0.45))) st=true;  //check its within range
    if ((millis()-start)>2000) st = true;
  }
     sV=map(curgrid4,0,255,10000,0);                    //delay before pulse  
     delayMicroseconds(sV); 
     analogWrite(pulse,curgrid4);                        
     Serial.print("TaskValueSet,2,2,"); Serial.println(curgrid4);
    }

//################# End of  PWM  controll ############################   
//############## LCD ############ 

if (LCD==1) {
kw =  (grid / 1000) ;
per = ( curgrid / 254);
per = (1 - per);
//per = ( 100 * per);
    lcd.backlight();
    lcd.clear();      
    lcd.setCursor(0,0);
    lcd.print("KW ");
    lcd.print(kw);
    lcd.setCursor(8,0);
    lcd.print("V ");
    lcd.print(ct1.Vrms);
//    lcd.print(FREQ);
    lcd.setCursor(0,1);
    lcd.print("GTI ");
    lcd.print(invert);
    if (CT1){
    lcd.setCursor(8,1);  
    lcd.print("Div ");   //displays Diverter usage   
    //lcd.print ( "-");
    lcd.print (diverter);
    }
    if (CT4){
      lcd.setCursor(0,3);
      lcd.print("Wind   ");   // displays  wind inverter output 
      lcd.print (wind);
    }
}
 if (count3 >= AVG){
    
   volt=volt/AVG;
   Serial.print("TaskValueSet,1,4,"); Serial.println(volt);
   power1=0;
   power2=0;
   power3=0;
   volt=0;
   count3=0;
   avg_255=0;
   avg_ios=0;
   }
  // because millis() returns to zero after 50 days ! 
  if (!settled && millis() > FILTERSETTLETIME) settled = true;
  //// ##### if you wish to send data  
  if (settled)                                                            
  {                                                                                                              
  }

}

Thank you

[EDIT - code prefixed and postfixed by a line with 3 backticks - ```

Moderator - RW]

Out of interest, what does the Linky do when you have PV but no “PV router” and you’re exporting bulk power to the grid? Does it count exports and imports in two different registers, or is there just a single register that starts counting backwards, or a single register that stops counting when you’re exporting?

There are 2 counter, first one measure the kVA (apparent power) use by the house; and the second measure the kVA injected to the grid (in autoconsommation mode there is no remuneration for these kVA). Up to now to limit as much as possible the injection I have only 4 PV connected instead of 6.

your emontx setting do you have outlet wattage tester that you can test your setting to?? as it seams to me you are not using a emontx shield so they are probably different then the norm

FRAC is just fractional… if you set at FRAC at 1 it pulse it set the pwm freq at what ever your grid frequency is. after experimenting I found 13-15 frequency pwm works the best on 60hz grid… so FRAC of 4 just divides the grid hertz by 4 to give me a frequency of 14-15 hertz… I just assume that, what applies for me will apply for 50 hertz.
example observation;
FRAC= 0.25: PWM 4 times grid (240 pwm) one large hole ( but faster the pulse and the hole shrinks to the same as pwm of 60)

FRAC =0.5; PWM double the grid 120 pwm works but fairly big holes in firing pattern

FRAC =1; pwm matches grid. works but with some holes in the fire pattern

FRAC=2; PWM 1/2 the Grid hertz (30 pwm)- works but with slight undulation

FRAC=4; PWM 1/4 fairly smoothly fire pattern

as the FRAC gets higher the pattern becomes more more pulse like

Yes all my measure seem to be ok:
Voltage
frequency
Power grid
Power PV = power GTI
Power diverted to water

Yesterday I built an arduino osciloscop to check all the measure and all seem ok
But I do not reach to get the SSR command working on pin 11
So that’s why I think there is a mistake of setting in my progam, could you please have a look



thank you

okay pin 11 only works if not using pwm.h and using standard arduino pwm but then you are restricted to 30 hz… which works okay for me on a 60hz grid not sure how well it works on a 50hz grid – pwm.h allows you to adjust pwm pulse from 1 and up… if you want to use arduino standard pwm just change

int PWM =1 ;

to

int PWM =0 ;

then you have all 4 SSRs

but you said you only want to use 1 ssr so you should change

int ios = 3;  

to

int ios = 1;  

or if you want to use all 4  then

 int ios = 4;  

I have newer version if you like that control four relays on top of SSR…

oh I just notice you are using a mega you need to use different pins Mega (2, 3, 5, 6, 7, 8, 11, 12, 44, 45, and 46) the uno – only 9 and 10 operate at 15 hz and pin 3 operated 30hz – pin 11 does not work when pwm.h on an uno – but I never tried on a Mega I am only going by the documents for pwm.h