How do I stop erronious triggers of commands during startup or watchdog resets?

I have hardware I'm using on some remote controller units for my roller shutters. This hardware emulates a hardware button press via bridging circuit (similar to the hardware pad). I'm using the IoT Cloud functionality so I can integrate it into smart assistent & automation. This code works as expected. But when the unit it turned on or, it seems, the communication to the cloud service or watchdog resets the unit, the unit triggers the blinds to close. Looking at the functions of IoT Cloud it appears to trigger all of the defined triggers as part of the start up/end function. I've attempted to put in a timer, and this appears to work for the initial start up. But I don't think timer reset on cloud issues or watchdog resets?

What I'm after is how do I ensure that the Up or Down onChange events can only be triggered by an actual command process sent via the IoT App or intrgrated assistant (Alexa)? Or how do I stop the initialization or soft reset from triggering the events (which appear to be UP, STop & Down in that order, if I could change it to STOP being last might help)

I'm using a D1 Mini ESP8266 device, plus a custom PCB for connection to the shutter controller. Trnasistors are used for the 'switches', to bridge the buttons on the shutter controller.

/* 
  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  CloudSwitch k_down;
  CloudSwitch k_stop;
  CloudSwitch k_up;
  bool led_state;
  bool cloud_check;
  bool up_initialize;
  bool stop_initialize;
  bool down_initialize;

  Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
  which are called when their values are changed from the Dashboard.
  These functions are generated with the Thing and added at the end of this sketch.
*/

#include "thingProperties.h"

// Define OUTPUT pins here
#define RS_UP    5
#define RS_STOP  4
#define RS_DOWN  0

void setup() {
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 

  // Defined in thingProperties.h
  initProperties();
  
  // Station mode
  WiFi.mode(WIFI_STA);
  
  // Define OUTPUT pins and set to LOW
  up_initialize = true;
  stop_initialize = true;
  down_initialize = true;
  pinMode(RS_UP, OUTPUT);
  pinMode(RS_DOWN, OUTPUT);
  pinMode(RS_STOP, OUTPUT);
  pinMode(BUILTIN_LED, OUTPUT); //For LED flash on activity
  digitalWrite(RS_UP, LOW);
  digitalWrite(RS_DOWN, LOW);
  digitalWrite(RS_STOP, LOW);
  digitalWrite(BUILTIN_LED, led_state); //set ON/OFF state via dashboard

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);

  /*
     The following function allows you to obtain more information
     related to the state of network and IoT Cloud connection and errors
     the higher number the more granular information you’ll get.
     The default is 0 (only errors).
     Maximum is 4
  */
  setDebugMessageLevel(2);
  ArduinoCloud.printDebugInfo();
}

void loop() {
  ArduinoCloud.update();
  if ((ArduinoCloud.connected() == 0) && cloud_check==true) {
    digitalWrite(BUILTIN_LED, !digitalRead(LED_BUILTIN));
    delay(500);
  }
  if (millis() < 30000) {
    digitalWrite(RS_STOP, HIGH);
    led_state = !led_state;
    digitalWrite(BUILTIN_LED, led_state);
    delay(500);
    digitalWrite(RS_STOP, LOW);
    led_state = !led_state;
    digitalWrite(BUILTIN_LED, led_state);
  }
}

void onKUpChange() {
  if ((ArduinoCloud.connected() == 1) && up_initialize == true) {
    up_initialize = false;
    } 
  else if ((ArduinoCloud.connected() == 1) && k_up == true && up_initialize == false && millis() > 40000) {
  digitalWrite(RS_UP, HIGH);
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  delay(500);
  digitalWrite(RS_UP, LOW);
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  k_up=false; //reset defined variable for UP
  }
  else { Serial.print("UP do nothing"); }
}

void onKDownChange() {
  if ((ArduinoCloud.connected() == 1) && down_initialize == true) { 
    down_initialize = false;
  }
  else if ((ArduinoCloud.connected() == 1) && k_down == true && down_initialize == false && millis() > 40000) {
  digitalWrite(RS_DOWN, HIGH);
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  delay(500);
  digitalWrite(RS_DOWN, LOW);
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  k_down=false; //reset defined variable for DOWN
  }
  else { 
    digitalWrite(RS_STOP, HIGH);
    led_state = !led_state;
    digitalWrite(BUILTIN_LED, led_state);
    delay(500);
    digitalWrite(RS_STOP, LOW);
    led_state = !led_state;
    digitalWrite(BUILTIN_LED, led_state);
    Serial.print("DOWN do nothing"); 
  }
}

void onKStopChange() {
  if ((ArduinoCloud.connected() == 1) && stop_initialize == true) {
    stop_initialize = false;
    }
  else if ((ArduinoCloud.connected() == 1) && k_stop == true && stop_initialize == false && millis() > 40000) {
  digitalWrite(RS_STOP, HIGH);
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  delay(500);
  digitalWrite(RS_STOP, LOW);
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  k_stop=false; //reset defined variable for STOP
  }
  else { Serial.print("STOP do nothing"); }
}

void onLedStateChange() {
  digitalWrite(BUILTIN_LED, led_state);
}

void onCloudCheckChange() {
  digitalWrite(BUILTIN_LED, !digitalRead(LED_BUILTIN));
    delay(500);
  digitalWrite(BUILTIN_LED, !digitalRead(LED_BUILTIN));
    delay(500);
}
void onUpInitializeChange() {
  // Do something
}
void onStopInitializeChange() {
  // Do something
}
void onDownInitializeChange() {
  // Do something
}

Sounds like a hardware solution is needed. Post your schematic, not a frizzy thing showing all connections and links to technical info on the hardware devices.

So there is no way to stop the Arduino IoT Cloud from calling all defined triggers as it starts up? There isn't any currently hardware solution, other than switching to relay or mosfets, and I'm hoping still that there can be things turned off at the IoT Cloud parts of the initialization.

Here is a quick schematic.
image

No that is just three open collector transistors, it shows nothing.

Are you sure it is the cloud that is triggering these events? When an Arduino starts off all the pins are set to input until the boot loader sees it is not required and then runs the code. If you have any pins that are an output driving things then the fact that their input floats is often enough to trigger them. In which case a 10K pull down is normally sufficient to stop this.

Disclaimer: I’ve just spent a few minutes looking at a tutorial since I had no idea how the Arduino cloud works.

Anyway, I guess your problem is this, that after a crash somewhere, the system has lost synchronization with your application. That is, it no longer “knows” what the state is of your blinds. To re-synchronize, it forces everything to a known state. That could mean unwanted changes to the position of your blinds.

I suppose you have no means of reading the actual current position of the blinds so you can correct the status within the cloud to reflect the real situation.

At the moment, all you have done is trying to suppress the cloud’s synchronization attempt.

I imagine you have used the relay template for your application. A relay has only two states: on and off. It looks like you need, in addition, a third state such as “no action “

That is the whole circuit. The collector and emitter are connected to an open pad circuit on the shutter controller itself. The transister just close that circuit and emulate the physical pad on the button in the controller bridging.

Yes, I'm sure as it's showing the events in the serial monitor after the Arduino IoT. I had put in serial prints into the code to see what was happening on start up, as I had made hardware changes to try and address the issue, with the following and got the serial output immediately after startup. This is when I tried the 'first run' bool and even the millis timer.

Some of the hardware changes were a 10k resister at the GND terminals and also 10k resistors bridged between the base and emitter. As the commands seem to be valid commands run by the IoT connection process, then the pull down resistors didn't help.

Serial Monitor output

Connected to Arduino IoT Cloud
Up HighUp Lowstop Highstop lowdown Highdown low
void onLrUpChange() {
  digitalWrite(RS_UP, HIGH);
  Serial.print("Up High");
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  delay(500);
  digitalWrite(RS_UP, LOW);
  Serial.print("Up Low");
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  lr_up=false; //reset defined variable for UP
}

void onLrDownChange() {
  digitalWrite(RS_DOWN, HIGH);
  Serial.print("down High");
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  delay(500);
  digitalWrite(RS_DOWN, LOW);
  Serial.print("down low");
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  lr_down=false; //reset defined variable for DOWN
}

void onLrStopChange() {
  digitalWrite(RS_STOP, HIGH);
  Serial.print("stop High");
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  delay(500);
  digitalWrite(RS_STOP, LOW);
  Serial.print("stop low");
  led_state = !led_state;
  digitalWrite(BUILTIN_LED, led_state);
  lr_stop=false; //reset defined variable for STOP
  
}

The code never knows what position the blinds are, and doesn't factor into how it operates. It will always cycle through the triggers, with the close command the last. If they reset and the blinds are closed, then there is a small up motion and then the close command. If blinds are open in a significant way, it'll go up a little and then finish on the close command which it will close the blind fully (unless stopped manually).

OK. If you can't reliably suppress the unwanted external triggering of actions in your sketch during start and crash cases, can you expose a simpler model to the cloud service so it does not see the actions ?

Say the cloud service manages only a single by variable (control_byte). You assign values. 0 = no action, 1 = blinds down, 2 = blinds up etc.

In your sketch, you check control_byte:

loop() {

  switch (control_byte) {

     case 0 : {
        // no action
        break ;
     }

     case 1 : {
        // blinds down code here
        control_byte = 0 ;    
        break
     }

     case 2 : {
        // blinds up code here
        control_byte = 0 ;    
        break
     }
  
     . . . 

  }
  . . . 
}

The default value of control_byte ( start up, crash etc.) is always zero so no action happens.
Of course, what I can't see is if that gives a nice user experience with whatever you have integrated with the cloud service.

I'll take a look and think about the type of logic you're suggesting. I've tried to have a code that is only valid when a legit trigger is initiated. As for whatever integrated with the cloud, is present in the code at the start. I'm using the Arduino IoT Cloud, and I do not perform anything else. Other than defining the IoT Cloud variables via their interface.

The assistant or IoT app, access if directly via the IoT Cloud integration.

No it is not.

You said

So that should be shown, at least in block form, along with where the power is derived from and the common ground between the Arduino and these controls.

OK. I think I see. You have simply defined a dashboard, (visible on a PC, smartphone etc.) and are controlling the blinds via widgets.

I see that it is also possible to use a sort of bridge between the Arduino Cloud Service and Amazon's Alexa so ultimately voice commands could be used.

EDIT

GPIO 0 on an ESP8266 is generally pulled HIGH so may not be ideal for your application. If you use pins GPIO 0 , 2 or 15 , check what the consequences are to avoid strange results.

Yes it is, for the purpose of this thread (not sure how to show it in a circuit, if I could) The unit is modular and isn't connected to the actual controller when testing or experiencing this issue. So the collector and emitter aren't connected during testing, but operate in the same fashion when connected/not connected to the shutter controller.

image

But this is the unit that it connects too, at the red points.

If it's a process of the IoT Cloud to trigger/cycle through defined variables, then a hardware solution of changing to mosfet or low power relays would still be an issue.

I defined and set the defined pins to LOW. I've also swapped the hardware for the STOP/DOWN on one unit of 0/4 pins and still no help. I had thought it was a hardware issue.

But ultimately, if the initalization of the IoT and Arduino code that it runs through a random order of defined variables. It's always going to trigger it erroniously.

Your schematic is not much help, I do not see the power source, its filtering etc. Also at reset your output pins are at an unknown state, put something in the range of 10K to pull the port pins down, not at the transistor. Where are all the ground connections? You have open collector outputs what are they connected to and where and how do you connect to that ground? How long are the wires?

Using a D1 Mini so that is the power source (5v & 3.3V at the pins) and custom PCB as follows. Which when testing isn't connected to anything other than itself.
image image

As per of the initalization process of the IoT Cloud seems to run through all defined variables, or at least the three affecting the triggering of transistors. Adding in pull down resistors wouldn't have the desired affect.

As per post #6 after the connection to the cloud is established, it processes those commands. The triggers for the shutters aren't a result of a pins being at HIGH/LOW or unknown states, or I would have been able to fix the issue with the ordering of the connections (which I tried putting the STOP as the last pin in the sequence of wiring).

When first starting up, and millis is under < 40000 the code is able to stop those erronious triggers, but it appears the 'soft' resets does not reset the millis value or if it's a watchdog reset it's not reseting the millis value either.

Does anyone know if a soft reset via break in IoT Cloud or Watchdog runs the setup() process again?

That is a very bad coding technique and should not be used.

Instead you need to take the value of the millis() in the setup function and in the if statement see if the current value of millis() minus this start value exceeds 40000.

Yes that is what I'm coming to learn and the purpose of this thread. How to overcome, what I've found, is a current limitation with the Arduino IoT Cloud.

Hopefully we can shift back to software solutions in this thread. I had just asked if the setup() runs during various reset scenarios, as was about to try that option.

I've only been using Arduino IDE for a few weeks now, so still learning. I had tried the IoT section with not much success.

why don't you write a separate piece of code that simply captures and reports the messages (or events) it receives to see what the code needs to deal with.

doesn't seem like a HW problem

Yeah, I did this via the Serial Monitor and added Serial.Print entries for all of my code. But the issue seems to be with the Arduino IoT Cloud part [ArduinoCloud.begin(ArduinoIoTPreferredConnection);] which is a whole suite of libraries that I cannot control the output from.

The majority of that takes place before the serial connection or even increasing the [setDebugMessageLevel(2);] to 4 doesn't yield any additional information. As I assume it's all non-debug processes that cause the triggering of events.

I suppose you could still try the approach outlined in post #8 where, instead of defining actions in the IoT Cloud which trigger stubs in your sketch, you simply pass a single variable and interpret that yourself in the code and trigger the desired function on noticing that the variable has changed.

Whereas it is possible to believe that the IoT Cloud, on startup, goes through some sort of synchronisation routine which involves an initial trigger of all defined actions, it is more difficult to believe that it would randomly change a variable from a default value to one which had some significance in your code.