Strange Electron event

I looked for the category “Troubleshooting” but it isn’t selectable, so this category is my best guess as to where this query should be posted.

Application:
My application employs two Electrons that, together, control the on/off status of a pump in a water well. Under normal circumstances, firmware on an Electron named ‘Tank’ at the location of a large water storage tank sends a ‘0’ or a ‘1’ to another Electron named ‘Pump’ located at the wellhead about 1500 feet away. A ‘0’ indicates that the pump should be off, while a ‘1’ indicates - as a function of a float switch in the tank - that the pump should come on.

Issue:
Due to problems with a float switch in the tank, the ‘Tank’ Electron has been unplugged for a while and the pump has been controlled manually by calling an on/off function in the firmware running on the ‘Pump’ Electron. Yesterday, the ‘Pump’ Electron went off line briefly, likely due to a loss of cellular signal (happens a lot; signal is very weak at all times). When the device came back on line, the code on that Electron executed a Particle.publish command that placed an entry in the event log suggesting that the ‘Tank’ Electron sent a ‘1’ and the pump was turned on. If I hadn’t noticed it and manually turned the pump off, the tank would have eventually overflowed.

Since the ‘Tank’ Electron is off line - and has been for a couple of weeks - there is no way it could have sent anything. So my question is: how/why was the myHandler routine invoked if there is no incoming event? This has never happened before, so I am both perplexed and concerned that it could happen again.

Following is the myHandler routine. I have also attached a screenshot of the event log that shows the event in question…At the very bottom of this post I have also provided the entire code running on the ‘Pump’ Electron.

void myHandler(const char *event, const char *data)
    {
    if (manualTimer){ // Do not react to publishes if command was sent to manually turn pump on for time period.
        return;
    }
    if (manualSwitch){ // Do not react to publishes if command was sent to manually turn pump on.
        return;
    }
    lastTankUpdate = millis();
    if ( linkUp == false ){
        linkUp = true; // If the ink was previously down, it just now came up
//        Particle.publish("Link", "Up", PRIVATE); // Send status to IFTTT for notification and logging
    }
  String d = String(data);
    int status = d.toInt();
    if (status & 1){
        controller.turnOnRelay(1);
        pumpOn = true;
        if (relayState == 0){
            relayState = controller.readRelayStatus (1);
            pumpOnTime = millis(); // Set start time
            pumpFault = false;
            Particle.publish("Status", "Tank On", PRIVATE); // Send status to IFTTT for notification and logging         
        }
    }else{
        controller.turnOffRelay(1);
        pumpOn = false;
        pumpFault = false;
        if (relayState == 1){
            relayState = controller.readRelayStatus (1);
            Particle.publish("Status", "Tank Off", PRIVATE); // Send status to IFTTT for notification and logging
        }
    }
}

Does anyone have any idea what could have caused this?

Entire code:

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

NCD2Relay controller;

SYSTEM_THREAD(ENABLED)
unsigned long previousMillis = 0; 
unsigned long lastPublish = millis();
unsigned long lastReset = millis();
unsigned long lastTankUpdate = millis();
static unsigned long pumpOnTime = 0;
static unsigned long tempRuntime = 0;
int relayState;
int previousStatus;
bool manualTimer = false;
bool manualSwitch = false;
bool linkUp = true;
bool pumpFault = false;
bool pumpOn = false;

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

void setup() {
    Particle.variable("Pump_Status", relayState);
    Particle.function("Pump_On_Off", triggerRelay);    
    Particle.function("Pump_Minutes", pumpWaterNow);  // Gets runtime in minutes from calling funtion on Particle Console; value must be an Integer....1,2,3, etc.
    controller.setAddress(0,0,0); // Re-initialize processor
    relayState = controller.readRelayStatus(1); // Set variable to current state of relay #1
    Particle.subscribe("IO", myHandler, MY_DEVICES); // Look for incoming IO message from tank
    linkUp = true;
    lastReset = millis();
}

void myHandler(const char *event, const char *data)
    {
    if (manualTimer){ // Do not react to publishes if command was sent to manually turn pump on for time period.
        return;
    }
    if (manualSwitch){ // Do not react to publishes if command was sent to manually turn pump on.
        return;
    }
    lastTankUpdate = millis();
    if ( linkUp == false ){
        linkUp = true; // If the ink was previously down, it just now came up
//        Particle.publish("Link", "Up", PRIVATE); // Send status to IFTTT for notification and logging
    }
  String d = String(data);
    int status = d.toInt();
    if (status & 1){
        controller.turnOnRelay(1);
        pumpOn = true;
        if (relayState == 0){
            relayState = controller.readRelayStatus (1);
            pumpOnTime = millis(); // Set start time
            pumpFault = false;
            Particle.publish("Status", "Tank On", PRIVATE); // Send status to IFTTT for notification and logging         
        }
    }else{
        controller.turnOffRelay(1);
        pumpOn = false;
        pumpFault = false;
        if (relayState == 1){
            relayState = controller.readRelayStatus (1);
            Particle.publish("Status", "Tank Off", PRIVATE); // Send status to IFTTT for notification and logging
        }
    }
}

// Function to turn pump on or off manually:
int triggerRelay(String command){ 
    String relayCommand = command;
	if (relayCommand.equalsIgnoreCase("on")){
	   controller.turnOnRelay(1);
	   relayState = controller.readRelayStatus (1);
	   Particle.publish("Status", "Manual On", PRIVATE); // Send status to IFTTT for notification and logging
	   manualSwitch = true;
	   return 1;
	}
	if (relayCommand.equalsIgnoreCase("off")){
	   controller.turnOffRelay(1);
	   relayState = controller.readRelayStatus (1);
	   Particle.publish("Status", "Manual Off", PRIVATE); // Send status to IFTTT for notification and logging
	   manualSwitch = false;
	   return 1;
	}
}

// Function to turn pump on for a specified number of minutes
int pumpWaterNow(String command) { // Gets Runtime in Minutes; value must be an Integer....1,2,3, etc.
    tempRuntime = ( command.toInt() * 60 * 1000 ); // Minutes * 60 seconds * 1000 ms
    previousMillis = millis();
    controller.turnOnRelay(1); // Turn ON Water Pump
    relayState = controller.readRelayStatus (1);
    Particle.publish("Status", "Timer On", PRIVATE); // Send status to IFTTT for notifciation and logging
    manualTimer = true;
    while ( (millis() - previousMillis) < (tempRuntime) ) { // Better than delay()
       Particle.process();
    }  // End While
    controller.turnOffRelay(1);  // Turn OFF Water Pump
    relayState = controller.readRelayStatus (1);
	Particle.publish("Status", "Timer Off", PRIVATE); // Send status to IFTTT for notification and logging
    manualTimer = false;  
} // End pumpWaterNow Function

void loop(){
    if (pumpOn){
        if (pumpFault == false){ // No previous fault reported
            if ( millis() - pumpOnTime > 10800000){ // If pump has been on for over 3 hours
                Particle.publish("Status", "Pump Fail?", PRIVATE); // Send status to IFTTT for notification and logging if pump has been running longer than 2 hours
                pumpFault = true;
                pumpOnTime = millis(); // Set newstart time
            }
        }
    }
    if (pumpOn == false){ // Don't want to execute the following code if the pump is running
        if ( millis() > lastReset + 3600000 ){ // If it's been more than 60 minutes since last reset
        controller.setAddress(0,0,0); // Reinitialize the MCP23008 chip on the NCD relay board
        lastReset = millis(); // Reset last initialization time to current program time
        }
    }
    if ( millis() - lastTankUpdate > 720000 ){ // If it's been more than 12 minutes since last 'IO' message from tank
        controller.turnOffRelay(1); // In case pump was running when link was lost, turn it off to avoid overfilling
        lastTankUpdate = millis(); // Reset tank update time to current program time
//        Particle.publish("Link", "Down", PRIVATE); // Send status to IFTTT for notifciation and logging
        linkUp = false; // Link is down
    } 
    if ( millis() - lastPublish > 600000 ){ // Has 10 minutes elapsed since last keepalive?
//        Particle.publish("KA", "OK", PRIVATE); // Send an "I'm here" keepalive to tank
        lastPublish = millis(); // Reset last keepalive time to current program time
    }
}

What value do you get for int status = d.toInt() ?
Where are you getting your string d data from ?

Is your float switch loop powered ? (i.e; 2 wire or 3 wire sensor)

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.