We have launched a new Community! Please post any new forum topics there. This forum will remain available as an archive, but we hope you enjoy the new experience and feature set the latest NCD Community will offer!

Publish

Hi, I am using a NCD4relay controller and a 2 channel current monitor with an electron. Is there away to only publish the current when my load is actually running, in order to limit data usage?

Any suggestions would be greatly appreciated.

B

Hi,

You can use a if statement and put a condition like this

if( current > 500) /// it means currrent if more then 500mA and this value will be high only and only when load is running and consuming the power

publish the event

Thanks

 

W

Hi,

where do I need to insert the if statement into the code

    // Output data to dashboard
    Particle.publish("Channel : ", String(j));
    delay(1000);
    Particle.publish("Current Value : ", String(current));
    delay(1000);
  }

 

Thanks again for your help,

T

Can you post the entirety of your code here?  I can put the if statement in there for you so an event will be published when the load switches on, then another event when it switches off(this sounds like what you need).

W

Travis, thanks for the help. That sounds like what I need. Relays 3 & 4 will be controling the loads that I will be monitoring current on. I know nothing about coding so any help is greatly apperciated.

 

 

 

/* Includes ------------------------------------------------------------------*/
#include "NCD4Relay.h"

NCD4Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[4];

int debugTrips[4];

int minTrips = 5;
#include  <spark_wiring_i2c.h>
#include <application.h>

// PECMAC125A I2C address is 0x2A(42)
#define Addr 0x2A

unsigned int data[36];
int typeOfSensor = 4;
int maxCurrent = 20;
int noOfChannel = 2;
double current = 0.0;

/* This function is called once at start up ----------------------------------*/
void setup()
{
    Particle.function("controlRelay", triggerRelay);
    Serial.begin(115200);
    relayController.setAddress(0,0,0);
    // Set variable
   Particle.variable("i2cdevice", "PECMAC125A");
   Particle.variable("typeOfSensor", typeOfSensor);
   Particle.variable("maxCurrent", maxCurrent);
   Particle.variable("noOfChannel", noOfChannel);
   Particle.variable("Current", current);

}

/* This function loops forever --------------------------------------------*/
void loop()
{
    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 9; i*=2){
        if(status & i){
            debugTrips[a]++;
            if(debugTrips[a] >= minTrips){
                if(!tripped[a]){
                    tripped[a] = true;
                    //set input trip event to true
                    String eventName = "Input_";
                    eventName+=(a+1);
                    Particle.publish(eventName, "ON");
                    Serial.print("eventName: ");
                    Serial.println(eventName);
                    Serial.print("eventContents: ");
                    Serial.println("ON");
                }
            }
        }else{
            debugTrips[a] = 0;
            if(tripped[a]){
                tripped[a] = false;
                //set input trip event to false
                String eventName = "Input_";
                eventName+=(a+1);
                Particle.publish(eventName, "OFF");
                Serial.print("eventName: ");
                Serial.println(eventName);
                Serial.print("eventContents: ");
                Serial.println("OFF");
            }
        }
        a++;
    }
}

int triggerRelay(String command){
    if(command.equalsIgnoreCase("turnonallrelays")){
        relayController.turnOnAllRelays();
        return 1;
    }
    if(command.equalsIgnoreCase("turnoffallrelays")){
        relayController.turnOffAllRelays();
        return 1;
    }
    if(command.startsWith("setBankStatus:")){
        int status = command.substring(14).toInt();
        if(status < 0 || status > 255){
            return 0;
        }
        Serial.print("Setting bank status to: ");
        Serial.println(status);
        relayController.setBankStatus(status);
        Serial.println("done");
        return 1;
    }
    //Relay Specific Command
    int relayNumber = command.substring(0,1).toInt();
    Serial.print("relayNumber: ");
    Serial.println(relayNumber);
    String relayCommand = command.substring(1);
    Serial.print("relayCommand:");
    Serial.print(relayCommand);
    Serial.println(".");
    if(relayCommand.equalsIgnoreCase("on")){
        Serial.println("Turning on relay");
        relayController.turnOnRelay(relayNumber);
        Serial.println("returning");
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("off")){
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("toggle")){
        relayController.toggleRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("momentary")){
        relayController.turnOnRelay(relayNumber);
        delay(300);
        relayController.turnOffRelay(relayNumber);
        return 1;
    }


  // Initialise I2C communication as MASTER
  Wire.begin();
  // Initialise Serial Communication, set baud rate = 9600
  Serial.begin(9600);

  // Start I2C transmission
  Wire.beginTransmission(Addr);
  // Command header byte-1
  Wire.write(0x92);
  // Command header byte-2
  Wire.write(0x6A);
  // Command 2 is used to read no of sensor type, Max current, No. of channel
  Wire.write(0x02);
  // Reserved
  Wire.write(0x00);
  // Reserved
  Wire.write(0x00);
  // Reserved
  Wire.write(0x00);
  // Reserved
  Wire.write(0x00);
  // CheckSum
  Wire.write(0xFE);
  // Stop I2C transmission
  Wire.endTransmission();

  // Request 6 bytes of data
  Wire.requestFrom(Addr, 6);

  // Read 6 bytes of data
  if (Wire.available() == 6)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
    data[2] = Wire.read();
    data[3] = Wire.read();
    data[4] = Wire.read();
    data[5] = Wire.read();
  }
  typeOfSensor = data[0];
  maxCurrent = data[1];
  noOfChannel = data[2];

  // Output data to dashboard
  Particle.publish("Type Of Sensor : ", String(typeOfSensor));
  delay(1000);
  Particle.publish("Max Current : ", String(maxCurrent));
  delay(1000);
  Particle.publish("No. Of Channel : ", String(noOfChannel));
  delay(1000);

  for (int j = 1; j < noOfChannel + 1; j++)
  {
    // Start I2C Transmission
    Wire.beginTransmission(Addr);
    // Command header byte-1
    Wire.write(0x92);
    // Command header byte-2
    Wire.write(0x6A);
    // Command 1
    Wire.write(0x01);
    // Start Channel No.
    Wire.write(j);
    // End Channel No.
    Wire.write(j);
    // Reserved
    Wire.write(0x00);
    // Reserved
    Wire.write(0x00);
    // CheckSum
    Wire.write((0x92 + 0x6A + 0x01 + j + j + 0x00 + 0x00) & 0xFF);
    // Stop I2C Transmission
    Wire.endTransmission();
    delay(500);

    // Request 3 bytes of data
    Wire.requestFrom(Addr, 3);

    // Read 3 bytes of data
    // msb1, msb, lsb
    int msb1 = Wire.read();
    int msb = Wire.read();
    int lsb = Wire.read();
    current = (msb1 * 65536) + (msb * 256) + lsb;

    // Convert the data to ampere
    current = current / 10;

    // Output data to dashboard
    Particle.publish("Channel : ", String(j));
    delay(1000);
    Particle.publish("Current Value : ", String(current));
    delay(1000);
  }
}

 

T

Give this a try:

 

// This #include statement was automatically added by the Particle IDE.
#include <NCD4Relay.h>

NCD4Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[4];

int debugTrips[4];

int minTrips = 5;
#include  <spark_wiring_i2c.h>
#include <application.h>

// PECMAC125A I²C address is 0x2A(42)
#define Addr 0x2A

unsigned int data[36];
int typeOfSensor = 4;
int maxCurrent = 20;
int noOfChannel = 2;
double current = 0.0;

unsigned long currentPublishInterval = 4000;
unsigned long lastCurrentPublish = 0;

/* This function is called once at start up ----------------------------------*/
void setup()
{
    Particle.function("controlRelay", triggerRelay);
    Serial.begin(115200);
    relayController.setAddress(0,0,0);
    // Set variable
    Particle.variable("i2cdevice", "PECMAC125A");
    Particle.variable("typeOfSensor", typeOfSensor);
    Particle.variable("maxCurrent", maxCurrent);
    Particle.variable("noOfChannel", noOfChannel);
    Particle.variable("Current", current);
   
    // Initialise I²C communication as MASTER
    Wire.begin();
    // Initialise Serial Communication, set baud rate = 9600
    Serial.begin(9600);

    // Start I²C transmission
    Wire.beginTransmission(Addr);
    // Command header byte-1
    Wire.write(0x92);
    // Command header byte-2
    Wire.write(0x6A);
    // Command 2 is used to read no of sensor type, Max current, No. of channel
    Wire.write(0x02);
    // Reserved
    Wire.write(0x00);
    // Reserved
    Wire.write(0x00);
    // Reserved
    Wire.write(0x00);
    // Reserved
    Wire.write(0x00);
    // CheckSum
    Wire.write(0xFE);
    // Stop I²C transmission
    Wire.endTransmission();

    // Request 6 bytes of data
    Wire.requestFrom(Addr, 6);

    // Read 6 bytes of data
    if (Wire.available() == 6){
        data[0] = Wire.read();
        data[1] = Wire.read();
        data[2] = Wire.read();
        data[3] = Wire.read();
        data[4] = Wire.read();
        data[5] = Wire.read();
    }
    typeOfSensor = data[0];
    maxCurrent = data[1];
    noOfChannel = data[2];

    // Output data to dashboard
    Particle.publish("Type Of Sensor : ", String(typeOfSensor));
    delay(1000);
    Particle.publish("Max Current : ", String(maxCurrent));
    delay(1000);
    Particle.publish("No. Of Channel : ", String(noOfChannel));
    delay(1000);
}

/* This function loops forever --------------------------------------------*/
void loop()
{
    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 9; i*=2){
        if(status & i){
            debugTrips[a]++;
            if(debugTrips[a] >= minTrips){
                if(!tripped[a]){
                    tripped[a] = true;
                    //set input trip event to true
                    String eventName = "Input_";
                    eventName+=(a+1);
                    Particle.publish(eventName, "ON");
                    Serial.print("eventName: ");
                    Serial.println(eventName);
                    Serial.print("eventContents: ");
                    Serial.println("ON");
                }
            }
        }else{
            debugTrips[a] = 0;
            if(tripped[a]){
                tripped[a] = false;
                //set input trip event to false
                String eventName = "Input_";
                eventName+=(a+1);
                Particle.publish(eventName, "OFF");
                Serial.print("eventName: ");
                Serial.println(eventName);
                Serial.print("eventContents: ");
                Serial.println("OFF");
            }
        }
        a++;
    }
    
    if(millis() > lastCurrentPublish+currentPublishInterval){
        lastCurrentPublish = millis();
        for (int j = 1; j < noOfChannel + 1; j++){
            // Start I²C Transmission
            Wire.beginTransmission(Addr);
            // Command header byte-1
            Wire.write(0x92);
            // Command header byte-2
            Wire.write(0x6A);
            // Command 1
            Wire.write(0x01);
            // Start Channel No.
            Wire.write(j);
            // End Channel No.
            Wire.write(j);
            // Reserved
            Wire.write(0x00);
            // Reserved
            Wire.write(0x00);
            // CheckSum
            Wire.write((0x92 + 0x6A + 0x01 + j + j + 0x00 + 0x00) & 0xFF);
            // Stop I²C Transmission
            Wire.endTransmission();
            delay(500);

            // Request 3 bytes of data
            Wire.requestFrom(Addr, 3);

            // Read 3 bytes of data
            // msb1, msb, lsb
            int msb1 = Wire.read();
            int msb = Wire.read();
            int lsb = Wire.read();
            current = (msb1 * 65536) + (msb * 256) + lsb;

            // Convert the data to ampere
            current = current / 10;
            
            char channelChar[100];
            sprintf(channelChar, "Channel %i: %0.2fmA", j, current);
            Particle.publish("Reading", String(channelChar));
        }
    }
}

int triggerRelay(String command){
    if(command.equalsIgnoreCase("turnonallrelays")){
        relayController.turnOnAllRelays();
        return 1;
    }
    if(command.equalsIgnoreCase("turnoffallrelays")){
        relayController.turnOffAllRelays();
        return 1;
    }
    if(command.startsWith("setBankStatus:")){
        int status = command.substring(14).toInt();
        if(status < 0 || status > 255){
            return 0;
        }
        Serial.print("Setting bank status to: ");
        Serial.println(status);
        relayController.setBankStatus(status);
        Serial.println("done");
        return 1;
    }
    //Relay Specific Command
    int relayNumber = command.substring(0,1).toInt();
    Serial.print("relayNumber: ");
    Serial.println(relayNumber);
    String relayCommand = command.substring(1);
    Serial.print("relayCommand:");
    Serial.print(relayCommand);
    Serial.println(".");
    if(relayCommand.equalsIgnoreCase("on")){
        Serial.println("Turning on relay");
        relayController.turnOnRelay(relayNumber);
        Serial.println("returning");
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("off")){
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("toggle")){
        relayController.toggleRelay(relayNumber);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("momentary")){
        relayController.turnOnRelay(relayNumber);
        delay(300);
        relayController.turnOffRelay(relayNumber);
        return 1;
    }

  for (int j = 1; j < noOfChannel + 1; j++)
  {
    // Start I²C Transmission
    Wire.beginTransmission(Addr);
    // Command header byte-1
    Wire.write(0x92);
    // Command header byte-2
    Wire.write(0x6A);
    // Command 1
    Wire.write(0x01);
    // Start Channel No.
    Wire.write(j);
    // End Channel No.
    Wire.write(j);
    // Reserved
    Wire.write(0x00);
    // Reserved
    Wire.write(0x00);
    // CheckSum
    Wire.write((0x92 + 0x6A + 0x01 + j + j + 0x00 + 0x00) & 0xFF);
    // Stop I²C Transmission
    Wire.endTransmission();
    delay(500);

    // Request 3 bytes of data
    Wire.requestFrom(Addr, 3);

    // Read 3 bytes of data
    // msb1, msb, lsb
    int msb1 = Wire.read();
    int msb = Wire.read();
    int lsb = Wire.read();
    current = (msb1 * 65536) + (msb * 256) + lsb;

    // Convert the data to ampere
    current = current / 10;

    // Output data to dashboard
    Particle.publish("Channel : ", String(j));
    delay(1000);
    Particle.publish("Current Value : ", String(current));
    delay(1000);
  }
}

 

W

Travis, seems to be working pretty good, just a few bugs. I'm running 5.0 amps thru card  and dashboard shows current to be 708.06ma. Also  is there a way on mobicle to display both channels at sametime? Thanks again for all your help

T

What does the max current variable say on Mobicle?  Does it match the current sensor on your board?

How many channels are on the current monitoring board?  Two right?

W

max current on mobicle is 20 same as board and yes 2 channels

T

Hi,

Do you have only the hot leg of the AC circtuit passing through the sensor?  It is important that you do not pass both the hot an neutral legs through the sensor as they will cancel each other out.  If you can provide a photo of your install that may be a good idea.

W

Travis, had to send pic via email. Yes just one wire thru sensor.

T

Did you make sure the wire is going the correct direction through the sensor?  There are arrows on the board indicating which way power should flow through the sensor.

Also do your readings change at all when the current draw changes?

W

Yes when iput 2amps in it sends 282.80 ma to dashboard. 282.ma is 2.82 amps so im thinking its in the calibration.

ryan fontaine's picture

All my code for CT's divide by 1000 instead of 10 (that Travis Posted)

I have:

    current = (msb1 * 65536) + (msb * 256) + lsb;
    // Convert the data to amp
    amps = current / 1000;

instead of :

 current = (msb1 * 65536) + (msb * 256) + lsb;
    // Convert the data to ampere
    current = current / 10;

 That would explain your 2 Decimal Places, right ?

 

[edit]

Oops,  I see Travis is using sprintf to report mA...... nevermind.

{/edit]

W

Let me tell ya what I am trying to accomplish using the electron, you may know of a better way.

I have a large generator set that is capable of running 2 - 140 HP electric pumps. The genset has to be started locally. It has current monitors installed for both pumps. During bad weather these pump need to run but usually you can't easily get to generator. Current draw on these pumps range from 100 to as high as 170. Less than 100 your not moving any water so we drop out the contactor feeding that pump. To save diesel and wear on gen after 5 mins of current below 10 amps the diesel engine shuts down. Starting and stopping of generator and the contactors with the electron I think I have a handle on.

The pump controllers have CTs with a Ratio of 250 - 5. 250 amps thru window equals 5 amps out to monitor. Monitor converts it back to actual amps.

 I can't run 100 amps or more thru the I2C current controller, Have to run my output wire from ct thru sensor. Now I need to convert it back into actual current draw and be able to only read over celluar when needed. Thanks again  

T

Are the lines you are testing the current monitor on powered by a generator or are you testing back at a bench?  To keep things simple for right now I would test the current monitor on something like an incondecent light bulb powered by AC from home/office power.  Generator produced AC may make the current monitors act a bit strange(honestly I don't know, never tried).  For now I think it is good to focus on getting the code to do what you want in a known trouble free environment.

Also it is known that inductive loads such as AC motors could cause the on board current monitor sensors to give false readings.  It is really ideal to use off board current monitors for that sort of application.  Are your current monitor sensors PCB mounted or off board?

ryan fontaine's picture

WvinTX, 

Thanks for the info, but I have a few questions.

Is this pumping StormWater or a sewage pumping station (just curious)

Are these centrifugal pumps, vertical turbine, submersible, or suction/lift (like a Gorman Rupp) ?

When the Amps drop to 100 amps or below, is that due to changing head conditions, or just a loss of suction @ pump inlet?

It appears your existing pump controller does what you want it to do, but you would like to add remote start capability via Electron ?

 

 

I can help you with the Hardware and Software if you want this to operate like a Pumping Station.

I'd recommend installing CT's and contactor relays independent of the existing pump controller, so that ALL remote control capability can be manually turned off Locally.  

Water Level could be the primary control, with Amps, pump outlet pressure, Gen Coolant Temp, etc,  as secondary control & Alarms.

ControlEverything.com sells everything you'd need (even if it's not listed on the website).

 

 

W

Ryan, this is being used for pit dewatering in a coal mine. We have ground water seapage and strom water that needs to be pumped. Submergable pumps mount on a barge. Gorman Rupp is the manufacturer.  The wide amp draw is due to both head conditions and suction. Got to monitor the current due to using a float or water level is is inpractable. Any hardware, software recommendations are apperciated.

 

Travis, right now I am bench testing this. I have basically a CT tester that can output 1 - 9.9 amps ac to pass current thru sensors. I first ordered the 4 relay contoller, got it working.Then figured it would be nice to monitor current. I ordered the off board monitor because it would be easier to install on exsiting equipment, not realizing it was also motherboard. Long story short I have both setups but would like go with the off board.

ryan fontaine's picture

WVinTx,  

I have a pilot system on a Gorman Rupp Station.  I'm planning on adding a Vacuum Sensor to the pump inlet in the near future.  Take a look at this Article.  You can diagnose many issues just by reading the inlet vacuum and outlet pressure for these suction lift pumps.  

I'm assuming you do not need the Generator to start automatically, but instead you want to send a start command to the Electron.  Then have the Gen warmup, and later start 1 (or both) pumps.  The Electron will monitor AMPS and stop each pump when it's no longer moving water.  Then have a cool-down period before stopping the Gen.  Restarting the Gen will require a new start command sent to the Electron.   Is this close to what you're looking for ?

As you already know, there are a couple of ways to accomplish this.  Depending on the existing Contol Panel, you may can leave the HOA swich for both pumps in "Hand", and use the Electron & a relay to switch the 120V control panel power source.  Your electron would live on an Off-Board Current Monitor board.  The Relay board would be a slave device on the I2C bus.  So when the Electron received a Gen Start Command you would fire the generator and later send the 120V to the existing control panel, which would start both pumps (HOA switches are on "HAND").  Once the AMPS for either pump dropped below 100, you would remove the 120V to the existing control panel.     

But your plan to operate either pump based on Amps (via the contactor) is better.  

I'd vote that you ask CE for a 2 channel 250 Amp or 400 Amp board and not wire to the existing pump controller's CT's.  That way you are independent of the existing control panel. It  may have a Phase Monitor, Current Monitors,etc already for protection.  Leave everything alone that's existing, so anyone can easily return to normal operation if the Electron System ever fails.  

 

 

ryan fontaine's picture

double post

 

T

We do have higher amperage CTs available upon request.  If you are interested in those please contact Bhaskar directly(bhaskar@controlanything.com)

W

Ryan, I believe were on same page. That sound exactly like what I need. I will check into the larger boards. Thank you and Travis for all your help.

P.S. is there an exsiting mobile app that you would recommend for this?

W

Ok, will do. Travis thanks for all your help!

ryan fontaine's picture

Mobicle.io is what I use for a mobile app  (Thank you ControlEverything !)

 

 

T

Of course I'm partial to Mobicle as well, it was just a fun little side project.  Blynk is also fantastic if you want something a bit more polished.  You will need to add Blynk specific code to the firmware on the module though to make it work with Blynk.

W

Travis and Ryan, below is copy of code that is working as needed with two exceptions. This is running on an off board 2-channel with an electron. One problem I am having is is trying to add a 4 relay I2c board and getting the code added correctly for a NCD4 relay. Not sure if its an address conflict  or using wrong code or what.  The second problem is it publishing all the time while its online.  

This code is just for the current card.

 

 

// Distributed with a free-will license.
// Use it any way you want, profit or free, provided it fits in the licenses of its associated works.
// PECMAC125A
// This code is designed to work with the PECMAC125A_DLCT03C20 I2C Mini Module available from ControlEverything.com.
// https://www.controleverything.com/content/Current?sku=PECMAC125A_DLCT03C20#tabs-0-product_tabset-2

#include  <spark_wiring_i2c.h>
#include <application.h>

// PECMAC125A I2C address is 0x2A(42)
#define Addr 0x2A

unsigned int data[36];
int typeOfSensor = 4;
int maxCurrent = 20;
int noOfChannel = 2;
double current = 0.0;

 

void setup()
{
  // Set variable
  Particle.variable("i2cdevice", "PECMAC125A");
  Particle.variable("typeOfSensor", 4);
  Particle.variable("maxCurrent", 20);
  Particle.variable("noOfChannel", 2);
  Particle.variable("Current", current);

  // Initialise I2C communication as MASTER
  Wire.begin();
  // Initialise Serial Communication, set baud rate = 9600
  Serial.begin(9600);

  // Start I2C transmission
  Wire.beginTransmission(Addr);
  // Command header byte-1
  Wire.write(0x92);
  // Command header byte-2
  Wire.write(0x6A);
  // Command 2 is used to read no of sensor type, Max current, No. of channel
  Wire.write(0x02);
  // Reserved
  Wire.write(0x00);
  // Reserved
  Wire.write(0x00);
  // Reserved
  Wire.write(0x00);
  // Reserved
  Wire.write(0x00);
  // CheckSum
  Wire.write(0xFE);
  // Stop I2C transmission
  Wire.endTransmission();

  // Request 6 bytes of data
  Wire.requestFrom(Addr, 6);

  // Read 6 bytes of data
  if (Wire.available() == 6)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
    data[2] = Wire.read();
    data[3] = Wire.read();
    data[4] = Wire.read();
    data[5] = Wire.read();
  }
  typeOfSensor = data[0];
  maxCurrent = data[1];
  noOfChannel = data[2];

  // Output data to dashboard
  Particle.publish("Type Of Sensor : ", String(typeOfSensor));
  delay(1000);
  Particle.publish("Max Current : ", String(maxCurrent));
  delay(1000);
  Particle.publish("No. Of Channel : ", String(noOfChannel));
  delay(1000);
}

void loop()
{
  for (int j = 1; j < noOfChannel + 1; j++)
  {
    // Start I2C Transmission
    Wire.beginTransmission(Addr);
    // Command header byte-1
    Wire.write(0x92);
    // Command header byte-2
    Wire.write(0x6A);
    // Command 1
    Wire.write(0x01);
    // Start Channel No.
    Wire.write(j);
    // End Channel No.
    Wire.write(j);
    // Reserved
    Wire.write(0x00);
    // Reserved
    Wire.write(0x00);
    // CheckSum
    Wire.write((0x92 + 0x6A + 0x01 + j + j + 0x00 + 0x00) & 0xFF);
    // Stop I2C Transmission
    Wire.endTransmission();
    delay(500);

    // Request 3 bytes of data
    Wire.requestFrom(Addr, 3);

    // Read 3 bytes of data
    // msb1, msb, lsb
    int msb1 = Wire.read();
    int msb = Wire.read();
    int lsb = Wire.read();
    current = (msb1 * 65536) + (msb * 256) + lsb;

    // Convert the data to ampere
    // Multiplier is equipment CT ratio
    current =( current / 1000 ) * 80;
   
    // Output data to dashboard
    Particle.publish("Channel : ", String(j));
    delay(1000);
    Particle.publish("Current Value : ", String(current));
    delay(1000);
  }
}

 

 

ryan fontaine's picture

WVinTx,  

The sample code for the Current Monitor and Relay Boards should work, but you will need to define 2 addresses, as you mentioned for Problem #1

Do something like this:

#define AddrCurrent 0x2A   // I²C Address for Current Monitor

#define AddrRelay 0x41     // I²C Address for Relay

Then you would replace Wire.beginTransmission(Addr) with Wire.beginTransmission(AddrCurrent); for the CT code.  Similar for the Relay Code

 

You will also need to establish a method to delay the Publish, per your Problem #2. 

 

 

 

unsigned long now = millis(); 
unsigned int lastPublish = 0; 

void setup() {
}

void Loop() {
    now = millis();
    // Do all your Sensor Readings, etc

    // Then Publish At the bottom of the LOOP if enough time has passed since the last publish
    if (abs(now - lastPublish) > 300000)  {           // Only publish after 5 minutes
        Particle.publish( Blah-blah-blah, PRIVATE);      
        lastPublish = now;
    }

 

I just posted my Sample Code for a 4 Channel Current Monitor.  

Give it a test run, you can add your Relay code to it.

W

Travis, it's been awhile. I have my firmware working on mobicle. Trying to figure out how to control relays with Blynk using virtual pins. I am wondering if you have tried this? Any guidance would be greatly appreciated.

T

Hi,

Yes, I actually did an article on Hackster a while back about this.  You can take a look at it here:

https://www.hackster.io/ControlEverything/blynk-particle-controleverythi...

It was for a 2 relay controller but it would not be terribly difficult to modify it for other size boards.

If you have any questions on it please let me know.

W

Travis please look over this code. I cant get it to verify.

blynk_huh.ino:72:2: a function-definition is not allowed here before '{' token
error
blynk_huh.ino:84:13: a function-definition is not allowed here before '{' token
error
blynk_huh.ino:165:1: expected '}' at end of input

 

 

// This #include statement was automatically added by the Particle IDE.
#include <NCD4Relay.h>

NCD4Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[4];

int debugTrips[4];

int minTrips = 5;
#define AddrRelay 0x20

/*************************************************************
  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Follow us:                  http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************

  No coding required for direct digital/analog pin operations!

 *************************************************************/

#define BLYNK_PRINT Serial  // Set serial output for debug prints
//#define BLYNK_DEBUG       // Uncomment this to see detailed prints

// Uncomment this, if you want to set network credentials
//#include "cellular_hal.h"
//STARTUP(cellular_credentials_set("broadband", "", "", NULL));

// Run "ping blynk-cloud.com", and set Blynk IP to the shown address
#define BLYNK_IP        IPAddress(45,55,130,102)

// Set Blynk hertbeat interval.
// Each heartbeat uses ~90 bytes of data.
#define BLYNK_HEARTBEAT 60

// Set Particle keep-alive ping interval.
// Each ping uses 121 bytes of data.
#define PARTICLE_KEEPALIVE 20

#include <blynk.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "YourAuthToken";

void setup() {
  Serial.begin(9600);
  Particle.keepAlive(PARTICLE_KEEPALIVE);
  Blynk.begin(auth, BLYNK_IP);
 
 
 /* This function is called once at start up ----------------------------------*/
 void setup()
 {
     //Configure Blynk
     Blynk.begin(blynkAuth);
     //Initialize relay controller by passing status of the 3 on board address jumpers.  This function must be called prior to interfacing with the controller.
  relayController.setAddress(0,0,0);
  
  //Publish status of inputs to app on boot
  updateInputs(true);
 }
 
 
 /* This function loops forever --------------------------------------------*/
 void loop(){
 {
     //Perform Housekeeping of Blynk connection
     Blynk.run();
     //Check Blynk publish interval for temperature reading so we only publish every 1 second.
     if(millis() > lastTempPub + tempPubInt){
         lastTempPub = millis();
         tempF = tempSensor.temperatureF();
         char temp[8];
         sprintf(temp, "%.2fº", tempF);
         Serial.println(temp);
         //Publish the current temperature reading to the Blynk app.
         Blynk.virtualWrite(V8, temp);
     }
     //Read inputs on relay board:
     updateInputs(false);
  
 }
 
 
 BLYNK_WRITE(V0){
     //Recieved command to control relay 1.
     int value = param.asInt();
     Serial.printf("Blynk virtual write pin %i with param %i \n", V0, value);
     switch(value){
         case 1:
             relayController.turnOnRelay(1);
             break;
         case 0:
             relayController.turnOffRelay(1);
             break;
     }
 }
 BLYNK_WRITE(V1){
     //Recieved command to control relay 2.
     int value = param.asInt();
     Serial.printf("Blynk virtual write pin %i with param %i \n", V1, value);
     switch(value){
         case 1:
             relayController.turnOnRelay(2);
             break;
         case 0:
             relayController.turnOffRelay(2);
             break;
     }
 }
 
 
 void updateInputs(bool startup){
     //Read and debounce digital inputs on relay board.
  int status = relayController.readAllInputs();
  int a = 0;
  for(int i = 1; i < 33; i*=2){
   if(status & i){
    debugTrips[a]++;
    if(debugTrips[a] >= minTrips || startup){
     if(!tripped[a] || startup){
         //Input is closed
         Serial.println("Input Closed");
      tripped[a] = true;
      //Publish high status to LED indicator in Blynk app notifying user that input is closed.
      led[a].on();
      if(a == 3){
          //If this is input 4 on the relay board then push notification to user's phone.
          Blynk.notify("You're really pushing my buttons");
      }
     }
    }
   }else{
    debugTrips[a] = 0;
    if(tripped[a] || startup){
        Serial.println("Input Open");
        //Input is open
     tripped[a] = false;
     //Publish low status to LED indicator in Blynk app notifying user that input is open.
     led[a].off();
    }
   }
   a++;
  }
 }
}
 

W

Travis, finally got it to verify.

 

It verified and flashed fine.
I have a button set up for V0 .
When button is pushed the electron blinks red.
Any ideas?

// This #include statement was automatically added by the Particle IDE.
#include <NCD4Relay.h>

// This #include statement was automatically added by the Particle IDE.
#include <blynk.h>

#include <spark_wiring_i2c.h>
#include <application.h>
#define AddrCurrent 0x2A // I²C Address for Current Monitor
#define CT_delay 10000 // 10,000 = 10 seconds. The CT Current Monitor Data Sheet suggests only reading the Board every 8-10 seconds

SYSTEM_THREAD(ENABLED);

char msg[256];

unsigned long now = millis(); // Used as Time to compare the Ellapsed time for various readings
unsigned int lastPublish = 0; // Previous Publish to ThingSpeak
unsigned long nowCT = millis(); // Latest CT Current-Monitor Reading
unsigned int lastCT = millis(); // Previous CT Current-Monitor Reading

// Variables Req’d for I²C CT Current-Monitor Board
int msb1 = 0, msb = 0, lsb = 0;
unsigned int data[36];
int typeOfSensor = 0;
int maxCurrent = 0;
int noOfChannel = 0;

int CH1trueamps = 0;
int CH2trueamps = 0;

double current = 0;
double amps = 0;

// These 4 Floats will hold the values to send to ThinkSpeak.com for data logging to the Cloud :
float CH1, CH2, CH3, CH4; // Pump/Motor AMPS

// Arrays
static int oldVal[5] = {0,0,0,0,0}; // Previous Sensor Values to Compare if Run State has Changed - equality checks are safer with Integers, so we will multiply by 10 for all sensor values, But divide by 10 before publishing each value
static int nowVal[5] = {0,0,0,0,0}; // Most Recent Sensor Values * 10
static int Flag[3] = {0,0,0}; // A “0” Value means nothing to update. Flag[1] = 1 requests to Publish AMPS after the Publish Delay, Flag[2] = 1 requests an immediate Publish (no Delay - used for Pump Start/Stop Events)

// Remote Reset Function, used to RE-SET the Photon/Electron using www.Mobicle.io
#define DELAY_BEFORE_REBOOT 2000
unsigned int rebootDelayMillis = DELAY_BEFORE_REBOOT;
unsigned long rebootSync = millis();
bool resetFlag = false;

NCD4Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[4];

int debugTrips[4];

int minTrips = 5;
#define AddrRelay 0x20

/* This function is called once at start up ----------------------------------*/

/*************************************************************
Blynk is a platform with iOS and Android apps to control
Arduino, Raspberry Pi and the likes over the Internet.
You can easily build graphic interfaces for all your
projects by simply dragging and dropping widgets.

Downloads, docs, tutorials: http://www.blynk.cc
Sketch generator:           http://examples.blynk.cc
Blynk community:            http://community.blynk.cc
Follow us:                  http://www.fb.com/blynkapp
                            http://twitter.com/blynk_app

Blynk library is licensed under MIT license
This example code is in public domain.


No coding required for direct digital/analog pin operations!

*************************************************************/

#define BLYNK_PRINT Serial // Set serial output for debug prints
//#define BLYNK_DEBUG // Uncomment this to see detailed prints

// Uncomment this, if you want to set network credentials
//#include “cellular_hal.h”
//STARTUP(cellular_credentials_set(“broadband”, “”, “”, NULL));

// Run “ping blynk-cloud.com”, and set Blynk IP to the shown address
#define BLYNK_IP IPAddress(45,55,130,102)

// Set Blynk hertbeat interval.
// Each heartbeat uses ~90 bytes of data.
#define BLYNK_HEARTBEAT 60

// Set Particle keep-alive ping interval.
// Each ping uses 121 bytes of data.
#define PARTICLE_KEEPALIVE 20

#include <blynk.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = “209f4fede69f4627818b48bdea98353a”;

void setup() {
Serial.begin(9600);
Particle.keepAlive(PARTICLE_KEEPALIVE);
Blynk.begin(auth, BLYNK_IP);
}

/* This function loops forever --------------------------------------------*/
void loop()
{
//Perform Housekeeping of Blynk connection
Blynk.run();

 //Read inputs on relay board: 

// updateInputs(false);

}

BLYNK_WRITE(V0){
//Recieved command to control relay 1.
int value = param.asInt();
Serial.printf(“Blynk virtual write pin %i with param %i \n”, V0, value);
switch(value){
case 1:
relayController.turnOnRelay(1);
break;
case 0:
relayController.turnOffRelay(1);
break;
}
}
BLYNK_WRITE(V1){
//Recieved command to control relay 2.
int value = param.asInt();
Serial.printf(“Blynk virtual write pin %i with param %i \n”, V1, value);
switch(value){
case 1:
relayController.turnOnRelay(2);
break;
case 0:
relayController.turnOffRelay(2);
break;
}
}

 

T

Hi,

Sorry I am not ignoring your post, I just have not had a chance to flash your code.  I really have to flash the code to a board here and test and have not had an opportunity to do that yet.