Ical Tool gives unuseable code

I found some code to automatically calculate a value for ICAL but I can’t save it as a useable .ino.
How can I convert this or download useable code, please?
https://openenergymonitor.org/forum-archive/sites/default/files/ical_tool.html

A sample part looks like this:
totalV1squared,totalV2squared,totalI1squared,totalI2squared,totalP1,totalP2; long sumTimerCount; float realPower1,apparentPower1,powerFactor1; float realPower2,apparentPower2,powerFactor2; word cycleCount; boolean showCT2; float expectedEnergyPerPulse; long energyAccumulator,pulseEnergyAccumulator; char pulseCount; boolean calibrating; float Vratio,I1ratio,I2ratio; CycleData cd; void setup() { Serial.begin(9600); pinMode(LEDPIN, OUTPUT); digitalWrite(LEDPIN, HIGH); PLL.begin(&cd); // set calibration to default values PLL.updatePhaseShift((int)(ILEAD*16),false);

Sadly, that has been a victim of the automatic archiving process. I have some of MartinR’s sketches, but not that one. And I don’t think he’s active here any longer.

I fear the only way will be to edit the text by hand to make it into a usable sketch. It will need some changes anyway, as it was written for the emonTx V2.

I’ve done a bit of the file - it’s tedious but it’s not that hard as I do know Martin’s programming style.

It has only lost it’s formatting because of the way the documents are currently displayed via the oem site. if you checkout the raw file on github it’s fine. (See forum-archive/ical_tool.html at master · openenergymonitor/forum-archive · GitHub)

// ical_tool - calculates current scale factor (ICAL) for emonTx from OpenEnergyMonitor
// Martin Roberts 26/02/13
// requires an optical meter pulse sensor and the PLL50Hz library

//--------------------------------------------------------------------------------------------------
// default calibration values
#define VCAL 237.9  // 240:11.2 for transformer x 11:1 for resistor divider
#define ICAL 111.1 // 100A:0.05A for transformer / 18 Ohms for resistor
#define ILEAD 200.0 // time in microseconds that current leads voltage by
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
// other system constants
#define LOOPCYCLES 250 // number of mains cycles for outer loop, also time between radio transmissions
#define POWER_VOLTS 3.3 // used here because it's more accurate than the internal band-gap reference
#define SUPPLY_FREQUENCY 50
#define JOULES_PER_PULSE 3600.0 // number of Joules per meter pulse, 1Wh = 3600 Joules
#define PULSES_PER_CALC 10 // number of meter pulses accumulated before calculations are done
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
// constants calculated at compile time
#define LOOPSAMPLES (LOOPCYCLES * NUMSAMPLES)
//--------------------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------------------
// Arduino I/O pin useage
#define LEDPIN 9
#define PULSEPIN 7 // pin for meter pulse detector (0-7 only) (3 is used by PLL50Hz library)
//--------------------------------------------------------------------------------------------------
  
#include <PLL50Hz.h>

float Vrms,I1rms,I2rms,frequency;
long totalV1squared,totalV2squared,totalI1squared,totalI2squared,totalP1,totalP2;
long sumTimerCount;
float realPower1,apparentPower1,powerFactor1;
float realPower2,apparentPower2,powerFactor2;
word cycleCount;
boolean showCT2;
float expectedEnergyPerPulse;
long energyAccumulator,pulseEnergyAccumulator;
char pulseCount;
boolean calibrating;
float Vratio,I1ratio,I2ratio;
CycleData cd;

void setup()
{
  Serial.begin(9600);
  pinMode(LEDPIN, OUTPUT);
  digitalWrite(LEDPIN, HIGH);
  PLL.begin(&cd);
  
  // set calibration to default values
  PLL.updatePhaseShift((int)(ILEAD*16),false);
  PLL.updatePhaseShift((int)(ILEAD*16),true);
  Vratio=(VCAL * POWER_VOLTS)/1024;
  I1ratio=(ICAL * POWER_VOLTS)/1024;
  I2ratio=(ICAL * POWER_VOLTS)/1024;
  
  bitSet(PCMSK2,PULSEPIN); // unmask pin change interrupt for pulse detector
  showHelp();
}

void loop()
{
  if(PLL.newCycle) addCycle(); // a new mains cycle has been sampled
  
  if(calibrating)
  {
    calibrate();
    return;
  }
  
  if(cycleCount>=LOOPCYCLES)
  {
    calculateVIPF();
    showResults();
  }

  if(Serial.available())
  {
    int c=toupper(Serial.read());
    
    switch(c)
    {
      case 'H':
      case '?': showHelp(); break;
      case 'C': calibrating=true; break;
      case '1': showCT2=false; break;
      case '2': showCT2=true; break;
      case 'V': updateVCAL(); break;
      case 'D': displayCalVals(); break;
    }
  }

  digitalWrite(LEDPIN,digitalRead(PULSEPIN)); // copy pulse input state to LED
}

// add data for new 50Hz cycle to total
void addCycle()
{
  totalV1squared+=cd.cycleV1squared;
  totalV2squared+=cd.cycleV2squared;
  totalI1squared+=cd.cycleI1squared;
  totalI2squared+=cd.cycleI2squared;
  totalP1+=cd.cycleP1;
  totalP2+=cd.cycleP2;
  sumTimerCount+=(OCR1A+1); // for average frequency calculation

  energyAccumulator+=(showCT2?cd.cycleP2:cd.cycleP1);
  
  cycleCount++;
  PLL.newCycle=false;
}

// calculate voltage, current, power and frequency
void calculateVIPF()
{
  float V2rms; // need this because voltage interpolation makes it different from Vrms
  
  Vrms = Vratio * sqrt(((float)totalV1squared)/LOOPSAMPLES); 
  V2rms = Vratio * sqrt(((float)totalV2squared)/LOOPSAMPLES); 
  I1rms = I1ratio * sqrt(((float)totalI1squared)/LOOPSAMPLES); 
  I2rms = I2ratio * sqrt(((float)totalI2squared)/LOOPSAMPLES); 

  realPower1 = (Vratio * I1ratio * (float)totalP1)/LOOPSAMPLES;
  apparentPower1 = Vrms * I1rms;
  powerFactor1=abs(realPower1 / apparentPower1);
  realPower2 = (Vratio * I2ratio * (float)totalP2)/LOOPSAMPLES;
  apparentPower2 = V2rms * I2rms;
  powerFactor2=abs(realPower2 / apparentPower2);
  frequency=((float)LOOPCYCLES*16000000.0)/((float)sumTimerCount*NUMSAMPLES);
 
  totalV1squared=0;
  totalV2squared=0;
  totalI1squared=0;
  totalI2squared=0;
  totalP1=0;
  totalP2=0;
  cycleCount=0;
  sumTimerCount=0;
}

void showResults()
{
  Serial.print("CT");
  Serial.write(showCT2?'2':'1');
  Serial.write(' ');
  Serial.print("V=");
  Serial.print(Vrms);
  Serial.print(" I=");
  Serial.print(showCT2?I2rms:I1rms);
  Serial.print(" RP=");
  Serial.print(showCT2?realPower2:realPower1,0);
  Serial.print(" AP=");
  Serial.print(showCT2?apparentPower2:apparentPower1,0);
  Serial.print(" PF=");
  Serial.print(showCT2?powerFactor2:powerFactor1,4);
  Serial.print(" F=");
  Serial.print(frequency);
  Serial.println(", 'H' or ? for help");
}

void calibrate()
{
  static int oldPulseCount;
  static boolean initialised=false;

  if(!initialised)
  {
    Serial.println();
    Serial.print("Waiting for meter pulses.");
    pulseCount=-2;
    oldPulseCount=pulseCount;
    pulseEnergyAccumulator=0;
    float Iratio=showCT2?I2ratio:I1ratio;
    float joulesPerBufferUnit = (Vratio * Iratio)/(SUPPLY_FREQUENCY*NUMSAMPLES);
    expectedEnergyPerPulse = JOULES_PER_PULSE/joulesPerBufferUnit;

    bitSet(PCICR,PCIE2); // enable pin change interrupt
    cycleCount=0;
    initialised=true;
    return;
  }
      
  if(pulseCount>=PULSES_PER_CALC)
  {
    bitClear(PCICR,PCIE2); // disable pin change interrupt
    float energyPerPulse=pulseEnergyAccumulator/PULSES_PER_CALC;
    Serial.println();
    float error=(energyPerPulse-expectedEnergyPerPulse)*100/expectedEnergyPerPulse;
    Serial.print("Current error ");
    Serial.print(error,1);
    Serial.print("% ");
    Serial.print("Old ICAL=");
    float Iratio=showCT2?I2ratio:I1ratio;
    Serial.print(Iratio*1024/POWER_VOLTS);
    Iratio*=(expectedEnergyPerPulse/energyPerPulse);
    Serial.print(", new ICAL=");
    Serial.println(Iratio*1024/POWER_VOLTS);
    if(showCT2) I2ratio=Iratio;
    else I1ratio=Iratio;
    Serial.println();
    calculateVIPF(); // to clear accumulators
    initialised=false;
    calibrating=false;
    return;
  }
    
  if(cycleCount>=(30*SUPPLY_FREQUENCY))
  {
    bitClear(PCICR,PCIE2); // disable pin change interrupt
    Serial.println(" timed out");
    Serial.println();
    calculateVIPF();
    initialised=false;
    calibrating=false;
    return;
  }
    
  if(pulseCount!=oldPulseCount) Serial.write('.');
  oldPulseCount=pulseCount;
}

ISR(PCINT2_vect)
{
  if(digitalRead(PULSEPIN)==HIGH) return; // we want the falling edge
  if(pulseCount>=0) pulseEnergyAccumulator+=energyAccumulator;
  pulseCount++;
  energyAccumulator=0;
}

void updateVCAL()
{
  Serial.println();
  Serial.print("VCAL");
  Serial.write('=');
  Serial.print(Vratio*1024/POWER_VOLTS);
  Serial.print(" enter new value or 's' to skip ");
  
  while(!Serial.available());
  if(toupper(Serial.peek())=='S')
  {
    Serial.write(Serial.read());
    Serial.println();
    return;
  }
  
  float Vcal=Serial.parseFloat();
  Serial.println(Vcal);
  Vratio= Vcal * POWER_VOLTS/1024;
  Serial.println();
}

void displayCalVals()
{
  Serial.println();
  Serial.print("VCAL=");
  Serial.println(Vratio*1024/POWER_VOLTS);
  Serial.print("I1CAL=");
  Serial.println(I1ratio*1024/POWER_VOLTS);
  Serial.print("I2CAL=");
  Serial.println(I2ratio*1024/POWER_VOLTS);
  Serial.println();
}

void showHelp()
{
  Serial.println();
  Serial.println("ical_tool");
  Serial.println("H,? - display this Help");
  Serial.println("1,2 - display data for CT1/2");
  Serial.println("C   - Calibrate ICAL");
  Serial.println("V   - enter new VCAL");
  Serial.println("D   - Display calibration data");
  Serial.println();
}

[edit - If you follow the link in the first post of this thread and then right click and “view page source” you can see why it’s wrong, the file is not html, even though it has an html extension, it’s raw Arduino/C/C++ code.]

It requires this too:

https://github.com/openenergymonitor/forum-archive/sites/default/files/PLL50Hz.zip

Thanks Robert and Paul. I now have a some code I can use.
I had already got the PLL50Hz library and it all compiles.

Thanks very much, gentlemen :smile:

That’s as far as you’ll get, unless you’re using an emonTx V2. The library and the sketch will need changing if you’re using anything else, because the I/O pins have moved around.

This might help:
https://community.openenergymonitor.org/uploads/default/original/2X/d/d3fedc62d1e881cfefae0abfe7ea3635850ce6b4.txt
(rename it to .html)

I should be able to change the I/Os following that list - they seem to be specified in PLL50Hz.h.
Thanks again.