Problem of Disabling the MKR GSM 1400 VIA MQTT TOPIC

Hi All,
I am a biginner working in a project where I need to send to topics one for the settings only and the other one for enable/disable the process of sending messages to the backend.When I send the settings it goes ok and when I send the enable/disable topic goes fine when it receives the message "1" .but When I try to send "0",it did not stop sending messages. I want the process of sending data to be on demand, meaning when it receives thesecond topic and the message is "1" to keep sending until it receives "0".
Below is my code.

#include <MKRGSM.h>
#include <MQTT.h>
#include <ArduinoHttpClient.h>
#include <ArduinoJson.h>
#include "ArduinoLowPower.h"
GSMLocation location;
GSMSSLClient clienth;
GSMClient net;
GPRS gprs;
GSM gsmAccess;
GSM_SMS sms;
MQTTClient client;
StaticJsonDocument<350> jsonBuffer;

JsonObject root = jsonBuffer.to<JsonObject>();

char server[] = "fb5c-154-125-6-18.eu.ngrok.io";
char path[] = "/data/add";
int port = 443;
HttpClient httpClient = HttpClient(clienth, server,port);
//global variable used for location management
String GSMlatitude ;
String GSMlongitude ;

const char pin[]      = "";
const char apn[]      = "apn";
const char login[]    = "login";
const char password[] = "password";
const int sensor= A4;
const int sensorvalue= A0;
double temp;
double vout;
//Alarm sensor
//int buzzer = 8;
// choc sensor
#define DetIn   4
bool detVal=false; 
char senderNumber2[20] ;
char senderNumber1[20] ;
int frequence;
float temperatureMax;
float voltageMax= 5.000;
unsigned long lastMillis = 0;
#define ARRAYSIZE 10
String results[ARRAYSIZE];

String topic1 ="padlock/settings";
String topic2="enable/disable";

bool activated = false;
bool isSubscribe = false;
;



void setKeepAlive(int keepAlive);
bool subscribe(const String &topic){
}

  


void connect() {
  // connection state
  bool connected = false;

  Serial.print("connecting to cellular network ...");

  // After starting the modem with gsmAccess.begin()
  // attach to the GPRS network with the APN, login and password

 connectionGsm(connected);
 connectionBroker();
// subscriptionBroker("hello");
 Serial.println("\nconnected!");
}

void subscriptionBroker(String topic1){
    client.subscribe(topic1);
    client.onMessage(messageReceived);

  }
void connectionGsm(bool connected){
  gprs.setTimeout(100000);
  gsmAccess.setTimeout(100000);
  while (connected==false) {
    if ((gsmAccess.begin(pin) == GSM_READY) &&(gprs.attachGPRS(apn, login, password) == GPRS_READY)) {
      connected = true;
      Serial.print("connection GSM reussi!!! ");
      } else {
        Serial.print(".");
        delay(1000);
      }
      location.begin();
      }
   }
void connectionBroker(){
  Serial.print("\nconnecting...");
  while (!client.connect("arduino", "public", "public")) {
    Serial.print(".");
    delay(1000);
    }
    Serial.print("connection Broker reussi!!! ");
    
    
  }

 
void messageReceived(String &topic, String &payload) {
  Serial.println("incoming: " + topic + " - " + payload);
  
  if (topic == "padlock/settings" ) {
  
    int i1 = payload.indexOf(',');
    int i2 = payload.indexOf(',', i1+1);
    int i3 = payload.indexOf(',', i2+1);
    int i4 = payload.indexOf(',', i3+1);
    int i5 = payload.indexOf(',', i4+1);
    int i6 = payload.indexOf(',', i5+1);
    int i7 = payload.indexOf(',', i6+1);
    int i8 = payload.indexOf(',', i7+1);
    int i9 = payload.indexOf(',', i8+1);
    int i10 = payload.indexOf(',', i9+1);
   
    String latiOuv = payload.substring(0, i1);
    String longiOuv = payload.substring(i1 + 1, i2);
    String tempMax = payload.substring(i2 + 1,i3);
    String numRec2= payload.substring(i3 + 1,i4);
    String heureOuv = payload.substring(i4 + 1,i5);
    String heureFerm = payload.substring(i5 + 1,i6);
    String numSerie = payload.substring(i6 + 1,i7);
    String idMission = payload.substring(i7 + 1,i8);
    String numRec1 = payload.substring(i8 + 1,i9);
    String freque = payload.substring(i9 + 1);
  
    results[0]=latiOuv;
    results[1]=longiOuv;
    results[2]=tempMax;
    results[3]=numRec2;
    results[4]=heureOuv;
    results[5]=heureFerm;
    results[6]=numSerie;
    results[7]=idMission;
    results[8]=numRec1;
    results[9]=freque;
  
    //convert a string to char array
    results[8].toCharArray(senderNumber1,20);
    results[3].toCharArray(senderNumber2,20);
    frequence = results[9].toInt() *1000;
    temperatureMax = results[2].toFloat();
    
    Serial.println("latitude:");
    Serial.println(latiOuv);
    Serial.println("longitude:");
    Serial.println(longiOuv);
    Serial.println("tempMax:");
    Serial.println(tempMax);
    Serial.println("numRec2:");
    Serial.println(numRec2);
    Serial.println("heureOuv:");
    Serial.println(heureOuv);
    Serial.println("heureFerm:");
    Serial.println(heureFerm);
    Serial.println("numSerie:");
    Serial.println(numSerie);
    Serial.println("idMission:");
    Serial.println(idMission);
    Serial.println("numRec:");
    Serial.println(numRec1);
    Serial.println("freque:");
    Serial.println(freque);
   // sendSMSDisable(senderNumber1);
  }
  if (topic == "enable/disable" ) {
    
    String message = payload;
  
    if(message == "1"){

      activated=true;
    
      enablePadlock();
    
    }
    if(message == "0"){

      activated=false;
    
      sendSMSDisable(senderNumber1);
    
  }
   
  }
    
 }
void clientsslconect(){
  Serial.print("\nconnectingtoNGROK...");
  while (!clienth.connect(server, port)) {
    Serial.print(".");
    delay(1000);
    }
    Serial.print("connection NGROK reussi!!! ");

}
double getTemperature(int sensor){
    vout=analogRead(sensor);
    vout=vout/10.24;
    temp=vout;
    return temp;
}
    
float getVoltage(int sensorValue){
  //cheking the state open/close
   int newSensorValue = analogRead(sensorValue);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
   float voltage = newSensorValue * (5.0 / 1023.0);
   //Serial.println(voltage);
   return voltage;
  }
float getChock(){
  detVal=digitalRead(DetIn);
  //Serial.println(5*(!detVal));
  return detVal;
  }

// This function use the location's APIs to get the device coordinates and update the globa variable if all the requirement are satisfied
void measureLocation() {
  unsigned long timeout = millis();
  while (millis() - timeout < 45000) {
    if (location.available() && location.accuracy() > 300 && location.accuracy() != 0) {
      GSMlatitude = String(location.latitude(), 6);
      GSMlongitude = String(location.longitude(), 6);
      
    }
  }
}
void sendSMSVoltage(char senderNumber1[20],char senderNumber2[20]){
    sms.beginSMS(senderNumber1);
    sms.print("Alert your lock has been open,Voltage detected is less than 1. ");
    sms.endSMS();

    sms.beginSMS(senderNumber2);
    sms.print("Alert your lock has been open,Voltage detected is less than 1. ");
    sms.endSMS();
    } 
void sendSMSTemp(char senderNumber1[20],char senderNumber2[20]){
    sms.beginSMS(senderNumber1);
    sms.print("Alert Temperature changes detected. ");
    sms.endSMS();
    
    sms.beginSMS(senderNumber2);
    sms.print("Alert Temperature changes detected. ");
    sms.endSMS();
    } 
void sendSMSChock(char senderNumber1[20],char senderNumber2[20]){
    sms.beginSMS(senderNumber1);
    sms.print("Alert chock detected. ");
    sms.endSMS();
    
    sms.beginSMS(senderNumber2);
    sms.print("Alert chock detected. ");
    sms.endSMS();
    }
void sendSMSDisable(char senderNumber1[20]){
    sms.beginSMS(senderNumber1);
    sms.print("Cadenas desactivé avec success !!!!. ");
    sms.endSMS();
}

void buzzerSound (int x) {  //buzzer. The argument is the number of time the buzzer should ring
  for (int a = 0; a < x; a++) {
    tone(7, 22, 30);
    delay(200);

  }
}
void checkVoltage(float voltage,char sendNumber1[20],char sendNumber2[20]){
    char* senderNumber1=sendNumber1;
    char* senderNumber2=sendNumber2;
    if(voltage <= voltageMax){
     Serial.println("Alert voltage is low");
     sendSMSVoltage(senderNumber1,senderNumber2); 
     buzzerSound(4);
    }
   }
void checkTemperature(double temp,char sendNumber1[20],char sendNumber2[20]){
    char* senderNumber1=sendNumber1;
    char* senderNumber2=sendNumber2;
    if(temp <= temperatureMax){
     //Serial.println("Alert temperature is low");
     sendSMSTemp(senderNumber1,senderNumber2);
     //buzzerSound(4); 
    }
   }
void checkchoc(float chock,char sendNumber1[20],char sendNumber2[20]){
    char* senderNumber1=sendNumber1;
    char* senderNumber2=sendNumber2;
   if(!chock){
     //Serial.println("Alert chock occured");
    // sendSMSChock(senderNumber1,senderNumber2);
     //buzzerSound(buzzer); 
    }
    else{
      Serial.println("no choc");
    }
   }

    
void setup() {
  Serial.begin(9600);
  pinMode(7,OUTPUT); //buzzer
  //pinMode(buzzer ,OUTPUT);
  pinMode(DetIn,INPUT);
 
  client.begin("public.cloud.shiftr.io", net);
  
  client.onMessage(messageReceived);

  connect();
  //subscriptionBroker("hello");
  location.begin();
 
}
//location.begin();
void loop() {
  
  client.loop();
  if (!client.connected()) {
    connect();
  }
  subscriptionBroker(topic1);
  client.loop();
  
  Serial.println("topic1 done");
  client.subscribe(topic2);
  Serial.println("topic 2 done");
  if (!clienth.connected()) {
    clientsslconect();
  }

  //enablePadlock();
}


void enablePadlock(){
  while(activated){
  
    measureLocation();
    double temp = getTemperature(sensor);
    float voltage=getVoltage(sensorvalue);
    float chock=getChock();
    checkVoltage(voltage,senderNumber1,senderNumber2);
    checkTemperature(temp,senderNumber1,senderNumber2);
    checkchoc(chock,senderNumber1,senderNumber2);
  
    for(int i=0;i<10;i++){
    }
    String latOUV = results[0];
    String longOUV = results[1];
    String tempMax = results[2];
    String numRec2 = results[3];
    String heureOUV = results[4];
    String heureFerm = results[5];
    String numSerie= results[6];
    String idMission = results[7];
    String numRec1 = results[8];
    String freq = results[9];
      
    float tempf = temp;
    int tempi = round(tempf);
    String temps = String(tempi); 
    float voltf = voltage;
    int volti = round(voltf);
    String volts = String(volti);
      
      
      
    root["latitude"] = GSMlatitude;
    root["longitude"] = GSMlongitude;
    root["voltage"]= volts;
    root["date"] = "2022-08-03T10:15:30";
    root["numbSerie"] = numSerie;
    root["temperature"] = temps;
    root["latitudeOuv"] = latOUV;
    root["longitudeOuv"]= longOUV;
    root["rayonTolerance"] = " 3";
    root["heureOuverture"] = heureOUV;
    root["heureFermiture"] = heureFerm;
    root["voltageMax"] = voltageMax;
    root["temperatureMax"] = tempMax;
    root["idMission"] = idMission; 
    postToNgrok(root); 
    //delay(5000);
    
    connect();
   
    isSubscribe = client.subscribe(topic1);
    Serial.println("subscribe again");
    //isSubscribe = subscribe("enable/disable");
    Serial.println("isSubscribe:");
    Serial.println(isSubscribe);
    
    Serial.println(" passing issubscribe");
    if(isSubscribe == true ){

      break;
      Serial.println("trying to break the loop");
      
   }
    
   
  }
    
  }
void postToNgrok(JsonObject& data) {
  String dataStr = ""; 
  String contentType = "application/json";
  serializeJson(data, dataStr);
  httpClient.beginRequest();
  httpClient.post(path);
  httpClient.sendHeader("Content-Type", "application/json");
  httpClient.sendHeader("Content-Length", dataStr.length());
  //httpClient.sendHeader("Authorization", "Bearer " + String(device_secret_key));
  httpClient.beginBody();
  httpClient.print(dataStr);
  Serial.println(dataStr);
  httpClient.endRequest();

  int statusCode = httpClient.responseStatusCode();
  String response = httpClient.responseBody();

  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);
}

That while loop is completely wrong. It won't terminate because client.loop() is never called again. Arduino is not multi-threaded, so without special programming (like interrupts) such a while loop will never terminate as the condition isn't changed inside the loop.

You should call enablePadlock() from your loop() and change the while to an if.

hi @pylon thanks for your help.
I've tried what you said, now i can enter again the void loop.
but the problem is :even when I publish topic2 with message "0" it never did the subscribe ,
therefore it is still sending the data.

Is there a way to increase the chance that it get the message when it does the subscription , I was thinking about setting keep Alive but don't know how to use them ,just to make sure that once it enters back in the loop the subscription are done.Bacause these topics are sent by clicking one button(1 time) of my web App . Any ideas of how to make it happens will be welcomed!

I don't understand, you do subscribe to topic2 (although in the loop() I would have expected it after connecting):

I get the impression you didn't understand yet how MQTT works. If you subscribe a topic you get all messages posted to that topic you don't have to re-subscribe as long as your connection is still active.
Subscribe to the topics you're interested in as soon as you connected to the MQTT server, then call the loop() method of the client object as often as you can (at least once every loop() run).

@pylon ,I did the client.subscribe(topic2); to be able to subscribe to the second topic.I did two different subscribes after the connection to the broker. It would be nice if you write this part as code source so that I can better understand what you mean.
thanks in advance

Extend the subscriptionBroker() to really do all the subscriptions:

void subscriptionBroker() {
    client.subscribe(topic1);
    client.subscribe(topic2);
    client.onMessage(messageReceived);
}

Call that at the end of the connect() routine.

Shorten your loop():

void loop() {
  client.loop();
  if (!client.connected()) {
    connect();
  }
  enablePadlock();
}

Does it receive a "1" message?

Check the return value of the subscribe() calls, it should always be a true value. If it is for both calls, you might be sending to the wrong topic.

Yes It receives the "1" succesfully but never receive the "0"

isSubscribe1= client.subscribe(topic1);
isSubscribe2= client.subscribe(topic2);
    Serial.println("isSubscribe1");
    Serial.println(isSubscribe1);
    Serial.println("isSubscribe2");
    Serial.println(isSubscribe1);

Hi @pylon am I doing it right ? I mean checking the return value of the subscribe()
I think the problem is if(activated){ in the enablePadlock()
because if I send "0" first it receives it well.But when I send the "1" first it just keep going sending data even though I send "0" .
any ideas on this?

Post the serial output if you publish a "0" and a "1" to the "enable/disable" topic!

Yes, what output do you get?

I don't see why that if should be a problem. The activated flag is set if a "1" is received and cleared if a "0" is received.

But remove the connect() call from enablePadlock() as well as the subscribe there.

Once you have done that all post your current complete code!

Hi @pylon ,
Do you think that it is because of my to different clients in the loop ,
I mean the mqtt client and the http client.

No, I don't think so.

There is no looping in the output you sent. BTW, please post text output as text and not as a picture!

How do you publish to the enable/disable topic? Do you set the retain flag?

I did not use retain flag

I guess your problem is that the GSM device isn't able to have several TCP connections open concurrently. That means if you send your data to the HTTP server the MQTT connection is disconnected.

You should open the HTTPS connection only if you want to use it immediately after.

You probably should set the retain flag for publishing values to the enable/disable topic. That way you get a message immediately after subscribing holding the current value published there.