MODBUS Solution

Hi ,
I was just wondering if there was a MODBUS solution with the particle ?, as i would like to communicate with modbus devices over the particle cloud

1 Like

Have you had a look at these topics?

https://community.particle.io/search?q=modbus

The search feature (top right corner :mag:) does help sometimes.

1 Like

HI Scruff.R

I wonder if you could point me in the right direction or even help with some development.

we are using the electron with a 3rd party simm to switch the particle 2 x relay board remotely , we are using a mains powered supply so do not need the battery pack, however although we have used the keep alive the unit seems to stop responding to our commands to switch, until the keep alive time elapses then we can connect again , the cyan led is always in heartbeat even when the unit is non responsive but every now and then it seems to re boot almost like it was in a sleep mode.

What’s your keepAlive() period?
Try shortening it - or rather start with the shortest (30) and then work your way up to a value when it stops working and then go back one step.

Also with the Electron not only voltage and current are important but also the responsiveness of your power supply to sudden spikes in current draw. Usually some extra caps should help with that.

The breathing cyan is not a very reliable indicator whether the connection is alive or not, since the Electron does not really ping home to check the status of the connection.

hi,

the keep alive is set to 5 at the moment , could the sleep mode be a factor ?

I think Particl.keepAlive(5) is a bit too short :wink:

To answer that we’d need to know what kind of sleep mode and how you’re using it.
Showing your code usually helps :sunglasses:

hi ,
please see below,i changed the code back to 30 and flashed with DFU mode since i rebooted i now get a green flashing led then a white heartbeat for 2 flashes then it goes back to green flashing.

#include "cellular_hal.h"
STARTUP(cellular_credentials_set("wlapn", "enerza", "enerza", NULL));

#include "NCD2Relay/NCD2Relay.h"

SYSTEM_THREAD(ENABLED);

NCD2Relay relayController;

SYSTEM_MODE(AUTOMATIC);

int triggerRelay(String command);

bool tripped[6];

int debugTrips[6];

int minTrips = 5;

long lastVariableUpdate;
int var = 0;
long interval = 5000;

int relayStatus = 0;

//Local variables for relay 1 and 2 state
String relay1Status = "...";
String relay2Status = "...";

void handler(const char *event, const char *data);

/* This function is called once at start up ----------------------------------*/
void setup()
{
    Particle.keepAlive(30 * 60);    // send a ping every 8 minutes
    
    Particle.subscribe("controlRelay", handler, MY_DEVICES);
    Particle.function("controlRelay", triggerRelay);
    //Particle Cloud variables for relay 1 and 2 state"
    Particle.variable("Relay1State", relay1Status);
    Particle.variable("Relay2State", relay2Status);
    Serial.begin(115200);
    relayController.setAddress(0,0,0);
    var = millis();
    lastVariableUpdate = millis();
    relayStatus = relayController.readRelayBankStatus();
    Particle.variable("Relay-Status", &relayStatus, INT);
    relayController.turnOnAllRelays();    //////// THIS IS MY NEW CODE
}

/* This function loops forever --------------------------------------------*/
void loop()
{
    if(millis() > lastVariableUpdate+interval){
        var = millis();
        Particle.variable("upTime", var);
        lastVariableUpdate = millis();
    }
    int status = relayController.readAllInputs();
    int a = 0;
    for(int i = 1; i < 33; 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++;
    }
    //Update local variables for relay 1 and 2 state.  These variables will be updated on Particle next checkin.
    if(relayController.readRelayStatus(1) == 1){
        relay1Status = "ON";
    }else{
        relay1Status = "OFF";
    }
    if(relayController.readRelayStatus(2) == 1){
        relay2Status = "ON";
    }else{
        relay2Status = "OFF";
    }
}

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");
        
        relayStatus = relayController.readRelayBankStatus();
        Particle.variable("Relay-Status", &relayStatus, INT);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("off")){
        relayController.turnOffRelay(relayNumber);
        
        relayStatus = relayController.readRelayBankStatus();
        Particle.variable("Relay-Status", &relayStatus, INT);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("toggle")){
        relayController.toggleRelay(relayNumber);
        
        relayStatus = relayController.readRelayBankStatus();
        Particle.variable("Relay-Status", &relayStatus, INT);
        return 1;
    }
    if(relayCommand.equalsIgnoreCase("momentary")){
        relayController.turnOnRelay(relayNumber);
        delay(300);
        relayController.turnOffRelay(relayNumber);
        return 1;
    }
    return 0;
}

void handler(const char *event, const char *data){
    triggerRelay(String(data));
}

When I said

I took your 5 from

as seconds (which is what the parameter stands for), but seeing your code you obviously meant 5 * 60 to indicate 5 minutes of keep alive.
Do try Particle.keepAlive(30) (= 30seconds) to remove any doubt about the keep alive.

For millis() calculations you should have all your variables used in that context declared as

unsigned long interval = 5000;
unsigned long lastariableUpdate = 0;

and the condition check should actually by this way

 if(millis() - lastVariableUpdate > interval)

to avoid issues with variable overrun.

Also these line should not appear in loop()

Particle.variable("upTime", var);
// nor
Particle.variable("Relay-Status", &relayStatus, INT);

Particle.variables() get only registered once and for all (usually in setup()).
Any change to the underlying variable will be retrieved on demand.

thanks,

we will give it a go and let you know, i am still unsure as to why i now get flashing green then white and back to green, after flashing the code