Arduino MKRGSM 1400: Connection issues and webhook problems

Dear all,
first of all I want to thank you for contributing to this excellent forum.
Without it I would not have gotten so far with my automated greenhouse project.
Now, I want to document my project progress and need some help to tackle the last two issues I have:

  1. Connection/stability problems: Before I implemented the watchdog function (shown below) the device used to go offline in the Blynk app after a random time period (sometimes after 30 min, sometimes after day or more). After implementation of the watch dog I have restarts instead. I still want to determine if its a software issue or a hardware issue (power, antenna …).
    Things that I have tried:
  • Connect the step down converter to VIN/GND and attach a LiPo to the battery connector (problem remains)
  • Reduce the sketch to the bare minimun, but still gsm connection via blynk.begin (problem remains)
  • the sketch with gsm/blynk removed works flaweless over several days
  1. Webhook to openweathermap.org (The final goal is to automatically close the windows when a storm comes up).
    Things that I have tried:
  • There are a lot of examples in the forum for ESP8266 using Arduino_JSON.h and ESP8266HTTPClient.h. However those libs don’t work for my board.
  • I found a working sketchfor my board (that neither uses a dedicated HTTPClient nor JSON module) but it does not uses blynk.begin to establish the gsm connection and I cant figure out how to combine it with by sketch. Any insights?

My Hardware:

  • Arduino MKR GSM 1400 (powered by a 12V car batter via a small Small step down converter attached battery connector of the MKR GSM 1400 )
  • GSM Antenna
  • 2 Grove DHT11 modules
  • 4 Channel relay (channel 1 and 2 connceted to two linear actuator that work as window openers; channel 3 controlls a magnetic valve to water the plants)

Software:
This is my current sketch:

// Set Blynk hertbeat interval (in seconds)
#define BLYNK_HEARTBdEAT 60

#define BLYNK_TEMPLATE_ID "XXX"
#define BLYNK_DEVICE_NAME "XXX"
#define BLYNK_AUTH_TOKEN "XXX"
#include "arduino_secrets.h"

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

#define BLYNK_PRINT Serial

#include <MKRGSM.h>
#include <BlynkSimpleMKRGSM.h>
#include "DHT.h"
#include <multi_channel_relay.h>
#include <WDTZero.h>
WDTZero MyWatchDoggy; // Define WDT

Multi_Channel_Relay relay;

GSMClient client;
GPRS gprs;
GSM gsmAccess;


// Your access credentials.
// Set password to "" for open networks.
char pin[] = SECRET_PINNUMBER;
char apn[]  = SECRET_GPRS_APN;
char user[] = SECRET_GPRS_LOGIN;
char pass[] = SECRET_GPRS_PASSWORD;


//   ----------For DHT-------------
#define DHT1PIN 3     // Digital pin connected to the indoor DHT sensor
#define DHT2PIN 4     // Digital pin connected to the outdoor DHT sensor

#define DHT1TYPE DHT11   // DHT 11
#define DHT2TYPE DHT11   // DHT 11

DHT dht1(DHT1PIN, DHT1TYPE);
DHT dht2(DHT2PIN, DHT2TYPE);

BlynkTimer timer;

int latchButton;
int latchFlag;

//for connection/uptime managment
int DeviceLED = 6;  // Define internal LED - will be used to indicate connection status
int ReCnctFlag;  // Reconnection Flag
int ReCnctCount = 0;  // Reconnection counter


// function to brake the window motor
void brake()
{
  Serial.println("WindowOpener: Braking");
  relay.turn_off_channel(1);
  relay.turn_off_channel(2); //Deactivate both relays to brake the motor
}

// sequence to open the window
void openWindow()
{
  timer.setTimeout(2000L, brake); // wait 2 seconds - potential cool down for relay than brake motor

  timer.setTimeout(4000L, []() // wait further 2 seconds (i.e. 4 seconds in total) than initiate opening
  {
    Serial.println("WindowOpener: Opening sequence in progress");
    relay.turn_on_channel(1);
    relay.turn_off_channel(2); //Activate the relay one direction, they must be different to move the motor - forward
  });

  timer.setTimeout(29000L, brake); // wait further 25 seconds (i.e. 29 seconds in total) to complete opening than brake motor
}

// sequence to close the window
void closeWindow()
{
  timer.setTimeout(2000L, brake); // wait 2 seconds - potential cool down for relay than brake motor

  timer.setTimeout(4000L, []() // wait further 2 seconds (i.e. 4 seconds in total) than initiate closing
  {
    Serial.println("WindowOpener: Closing sequence in progress");
    relay.turn_on_channel(2);
    relay.turn_off_channel(1); //Activate the relay one direction, they must be different to move the motor - backward
  });

  timer.setTimeout(29000L, brake); // wait further 25 seconds (i.e. 29 seconds in total) to complete closing than brake motor

}


//===== Latching button attached to V1 =====
BLYNK_WRITE(V1) {  // Button Widget set as switch
  latchButton = param.asInt();
  if (latchButton == 1 && latchFlag == 0) {
    latchFlag = 1;  // Keeps from allowing button press more then once while relay activated
    Blynk.setProperty(V1, "isDisabled", true); // Keeps from allowing the widget button press more then once while relay activated
    // ----- Start your timed thing here
    openWindow();
    // -----
    timer.setTimeout(29000L, []() {  // Timed Lambda Function - Latching Button release after 29 seconds
      latchFlag = 0;  // resets to allow next interaction
      Blynk.setProperty(V1, "isDisabled", false);
    });  // END Timer Function
  } else {
    if (latchButton == 0 && latchFlag == 0) {
      latchFlag = 1;  // Keeps from allowing button press more then once while relay activated
      Blynk.setProperty(V1, "isDisabled", true); // Keeps from allowing the widget button press more then once while relay activated
      // ----- Start your timed thing here
      closeWindow();
      // -----
      timer.setTimeout(29000L, []() {  // Timed Lambda Function - Latching Button release after 29 seconds
        latchFlag = 0;  // resets to allow next interaction
        Blynk.setProperty(V1, "isDisabled", false);
      });  // END Timer Function
    }
  }
}


// DHT sensors send

void sendSensor()
{
  float h1 = dht1.readHumidity();
  float t1 = dht1.readTemperature();

  float h2 = dht2.readHumidity();
  float t2 = dht2.readTemperature();

  if (isnan(h1) || isnan(t1) || isnan(h2) || isnan(t2)) {
    Serial.println("Failed to read from DHT sensor(s)!");
    return;
  }
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  Serial.println("Reading DHT sensor(s)");
  Blynk.virtualWrite(V5, t1);
  Blynk.virtualWrite(V6, h1);

  Blynk.virtualWrite(V7, t2);
  Blynk.virtualWrite(V8, h2);
}

// function called on shut down by watchdog

void myshutdown()
{

  Serial.print("\nWe gonna shut down ! ...");

}


void setup()
{
  int t = 20; //Initialize serial and wait for port to open, max 10 seconds
  Serial.begin(9600);
  while (!Serial) {
    delay(500);
    if ( (t--) == 0 ) break;
  }
  Serial.print("Setup Soft Watchdog at 32S interval");
  MyWatchDoggy.attachShutdown(myshutdown);
  MyWatchDoggy.setup(WDT_SOFTCYCLE32S);  // initialize WDT-softcounter refesh cycle on 32sec interval

  // Here your Arduino connects to the Blynk, through begin you can set all the access credential required to establish a connection with the app
  Blynk.begin(auth, gsmAccess, gprs, client, pin, apn,  user, pass);

  dht1.begin();
  dht2.begin();

  // Set I2C address and start relay
  relay.begin(0x11);

  // Setup DHT sendSensor function to be called every 100 seconds
  timer.setInterval(100000L, sendSensor);

  // UpTime function to be called every minute
  timer.setInterval(60000L, UpTime);

  // UpTimeBlink function to be called every 1 seconds
  timer.setInterval(1000L, UpTimeBlink);

  // start with windows closed
  closeWindow();

}

BLYNK_CONNECTED() {
  Serial.println("Connected");
  ReCnctCount = 0;
}


void UpTime() {
  Blynk.virtualWrite(V0, millis() / 60000);  // Send UpTime minutes to App
  Serial.print("UpTime: ");
  Serial.println(millis() / 60000);  // Send UpTime seconds to Serial
  Serial.print("minute(s)");
}

void UpTimeBlink() {
  digitalWrite(DeviceLED, !digitalRead(DeviceLED));  // Blink onboard LED
}

void loop()
{
  MyWatchDoggy.clear();  // refresh wdt - before it loops

  //this start the blynk utilities and make run the iteration with the app

  timer.run();

  if (Blynk.connected()) {  // If connected run as normal
    Blynk.run();
  } else if (ReCnctFlag == 0) {  // If NOT connected and not already trying to reconnect, set timer to try to reconnect in 30 seconds
    ReCnctFlag = 1;  // Set reconnection Flag
    Serial.println("Starting reconnection timer in 30 seconds...");
    timer.setTimeout(30000L, []() {  // Lambda Reconnection Timer Function
      ReCnctFlag = 0;  // Reset reconnection Flag
      ReCnctCount++;  // Increment reconnection Counter
      Serial.print("Attempting reconnection #");
      Serial.println(ReCnctCount);
      Blynk.connect();  // Try to reconnect to the server
    });  // END Timer Function
  }
}

Thank you for reading.

Hey there,
First of all you must read this
https://docs.blynk.io/en/legacy-platform/legacy-articles/keep-your-void-loop-clean

Any reason why you chose that particular hardware?

Pete.

Thank you for the prompt reply. The green house is very remote and I failed to establish a LoRA (or even WiFi) connection, so I went for GSM. The number of ready to go GSM board is also limited so the Arduino GSM MKR 1400 was a natural choice.

Personally, I’d have gone for the TTGO T-Call board, which is ESP32 based.

Are you maintaining a constant GSM connection? If so, is this economical as far as GSM data is concerned?

Pete.

1 Like

@John93: Thank you for the reference to “Keep your void loop() clean”, but which specific part of my loop is not clean?

In my loop there are:

  • my doggy
  • Blynk.run() and timer.run()
  • a connection check part that I found in this forum.

In addition, I avoided to use “delay” in the timed functions. Did I miss something?

@PeterKnight: Wow, the"TTGO T-Call board" is very cheap compared to the Arduino MKR 1400. I am pretty new to electronics and when I started I did not realize that there are non-arduino MCU for hobyiists.

The only downside of this board is, that I cant find a connector carrier/shield for the grove sytem that I use (and I am not sure if the libary for the grove relay would work with ESP).

In order to further check if its and hardware error I will use the following hardware setup 1) seeeduino 2)SIM800L module 3) a grove shield

The ideal blynk void loop should look like this


void loop()
{
  Blynk.run();
  timer.run ();
}

Only, nothing else.

@PeteKnight:

Your question on the GSM connection made me think:

In the current sketch the GSM connection is established by blynk.begin in setup().

So theoretically it should run all the time, but I think I dont have something to re-establish the GSM connection in the current sketch.

From a economical poit of view GSM data should no be a problem (I have 200MB per month free) on the other side less GSM traffic would be good for the battery.

I need a more or less constant GSM conncetion to be able to open the greenhouse windows with the blynkapp.

Could it be that my provider terminates the connection and my script does not re-establish it? I will adapt the sketch …

TBH, very few people use Arduino hardware, especially for IoT projects.
There must have been hundreds of millions of Uno, Nano and Mega boars sold, but they have no native IoT connectivity, so most people end-up attaching them to an ESP-01 anyway, or netter still throwing them in the bin and using an ESP8266 or ESP32 instead.

From what I can see the Grove system is really just an expansion system that uses I2c to allow a variety of various analog, digital and bus devices to be connected.
It should simply be a case of connecting your Seed system via I2c and power to an ESP32, and there seem to be people who have done this before if you do a quick search.

Pete.

I though that is what the “clutter” in your void loop was attempting to do?

On a different subject, is there a treason why you didn’t nest your lambda timeout timers inside each other?

Pete.

Yes the “clutter” in my void loop is supposed to reestablish the connection to the blynk server by calling Blynk.connect().
I just started to wonder if Blynk.connect() would also reestablish the gsm connection.

As to the lambda timeout timers, the reason is that the sketched has grown over time and I am pretty new to programming. I guess this way its not nice but it works.

A far better approach is to use a timer to check your connection on a regular basis and do the re-connection from there if needed. That approach could also be used to perform a reboot if the timed function has failed multiple times.

That would remove the need for the watchdog (I have to say that I don’t like software watchdogs).

Blynk.connect() is normally used in conjunction with Blynk.config(), instead of Blynk.begin().
However that approach would require you to establish the GSM connection and use that connection object in your Blynk.config() command.

Lots of examples of this for the ESP32 GSM boards, but I guess fewer for your hardware.

Pete.

@PeteKnight I am sorry for asking, but can you please point me to a specific sketch for this far better approach (even if it is for ESP32 GSM)? I tried the search function of the board and google, but can’t find it.

Here’s a sketch I was using with Blynk Legacy and the TTGO T-Call board…

#define BLYNK_PRINT Serial    
#define BLYNK_HEARTBEAT 30
#define TINY_GSM_MODEM_SIM800

#include <TinyGsmClient.h>
//#include <BlynkSimpleSIM800.h>
#include <BlynkSimpleTinyGSM.h>

#include <Wire.h>
#include "utilities.h"

// TTGO T-Call pin definitions
#define MODEM_RST            5
#define MODEM_PWKEY          4
#define MODEM_POWER_ON       23
#define MODEM_TX             27
#define MODEM_RX             26
#define I2C_SDA              21
#define I2C_SCL              22

// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial

// Hardware Serial on TTGO Call
#define SerialAT Serial1


const char apn[]  = "REDACTED";
const char user[] = "";
const char pass[] = "";
const char auth[] = "REDACTED";

TinyGsm modem(SerialAT);

void setup()
{
  // Set console baud rate
  SerialMon.begin(115200);
  delay(10);

  // Keep power when running from battery
  Wire.begin(I2C_SDA, I2C_SCL);
  bool   isOk = setPowerBoostKeepOn(1);
  SerialMon.println(String("IP5306 KeepOn ") + (isOk ? "OK" : "FAIL"));

  // Set-up modem reset, enable, power pins
  pinMode(MODEM_PWKEY, OUTPUT);
  pinMode(MODEM_RST, OUTPUT);
  pinMode(MODEM_POWER_ON, OUTPUT);

  digitalWrite(MODEM_PWKEY, LOW);
  digitalWrite(MODEM_RST, HIGH);
  digitalWrite(MODEM_POWER_ON, HIGH);

  // Set GSM module baud rate and UART pins
  SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
  delay(3000);

  // Restart takes quite some time
  // To skip it, call init() instead of restart()
  SerialMon.println("Initializing modem...");
  modem.restart();

  String modemInfo = modem.getModemInfo();
  SerialMon.print("Modem: ");
  SerialMon.println(modemInfo);

  // Unlock your SIM card with a PIN
  //modem.simUnlock("1234");

   SerialMon.print("Waiting for network...");
  if (!modem.waitForNetwork(240000L)) {
    SerialMon.println(" fail");
    delay(5000);
    return;
  }
  SerialMon.println(" OK");

  if (modem.isNetworkConnected()) {
    SerialMon.println("Network connected");
  }

  SerialMon.print(F("Connecting to APN: "));
  SerialMon.print(apn);
  if (!modem.gprsConnect(apn, user, pass)) {
    SerialMon.println(" fail");
    delay(5000);
    return;
  }
  SerialMon.println(" OK");

  //Blynk.begin(auth, modem, apn, user, pass);
  Blynk.config (modem, auth, "blynk-cloud.com", 8080); // Legacy server
  Blynk.connect();
}

void loop()
{
  Blynk.run();
}

and this is the contents of utilities.h…

#define IP5306_ADDR          0x75
#define IP5306_REG_SYS_CTL0  0x00

bool setPowerBoostKeepOn(int en)
{
  Wire.beginTransmission(IP5306_ADDR);
  Wire.write(IP5306_REG_SYS_CTL0);
  if (en) {
    Wire.write(0x37); // Set bit1: 1 enable 0 disable boost keep on
  } else {
    Wire.write(0x35); // 0x37 is default reg value
  }
  return Wire.endTransmission() == 0;
}

This is a legacy sketch and this line of code:

  Blynk.config (modem, auth, "blynk-cloud.com", 8080);

is telling the sketch to connect to the Blynk legacy server at blynk-cloud.com
The Blynk IoT server url is blynk.cloud and if the device is to be used in a mobile situation then it would probably be best to include the subdomain which specifies exactly which server is used for your project, as described here:

https://docs.blynk.io/en/blynk.cloud/troubleshooting

Documentation for Blynk.config() - which you should read - is here:

https://docs.blynk.io/en/blynk.cloud/troubleshooting

Pete.

@greenhouse

A few Checks and balances on the GSM side:

  1. Check with your MNO that the Blynk Server has been “authorised” as in some cases the server IP address needs to be provisioned on the MNO side.
  2. GPRS has a set time out of 8-15 minutes on the socket, if no activity after this time, you are booted and need to establish a new connection.
  3. If you have the 2G/LTE module, use LTE as the preferred connection, 2G is problematic currently (some regions worse than others).
    Also check your GSM module firmware has the latest firmware as this sometimes is also a problem and older versions might have bus and issues.

Thank you all for the input. The connection issues turned out to be a hardware/power supply issue and the following modifications solved it:

  1. I shortend the cable that is plugged into the battery connector (the cable that I use has the diameter of a typical breadboard cable which seems to give too much resistance)
  2. I added a big capacitator (4700 uF 16V , probably oversized butI I had it availible) close to the battery connector
  3. I chose a cable with a bigger diameter to connect the buck converter

I hope somebody finds this usefull and does not spend hours to solve a hardware problem with software tweaks like I did.

1 Like