Hi,
I want to write a program that should communicate to a MQTT server and send various sensors data. I was testing the communication part between the wifi and the MQTT Server.
Using the ArduinoMqtt library, it works well if i just modify a little bit the example with my personal parameters. This example sends a test message every seconds and works perfectly :
// This example uses an Arduino/Genuino Zero together with
// a WiFi101 Shield or a MKR1000 to connect to shiftr.io.
//
// IMPORTANT: This example uses the new WiFi101 library.
//
// You can check on your device after a successful
// connection here: https://shiftr.io/try.
//
// by Gilberto Conti
// https://github.com/256dpi/arduino-mqtt
#include <WiFi101.h>
#include <MQTT.h>
const char ssid[] = "ssid";
const char pass[] = "password";
WiFiClient net;
MQTTClient client;
unsigned long lastMillis = 0;
void connect() {
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while (!client.connect("client_id", "user", "password")) {
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
client.subscribe("/hello");
// client.unsubscribe("/hello");
}
void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
}
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, pass);
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
// You need to set the IP address directly.
client.begin("server_url.com", net);
client.onMessage(messageReceived);
connect();
}
void loop() {
client.loop();
if (!client.connected()) {
connect();
}
// publish a message roughly every second.
if (millis() - lastMillis > 1000) {
lastMillis = millis();
client.publish("/hello", "esnqerbw");
}
}
To keep the code as clear as possible (I am used to object oriented programming), I want to make a class that would have to deal with all the MQTT part (sending data, receiving commands from server, getting parameters from FlashStorage, etc...). But then I made just the same program but with a MQTT wrapper object :
the .ino file :
// This example uses an Arduino/Genuino Zero together with
// a WiFi101 Shield or a MKR1000 to connect to shiftr.io.
//
// IMPORTANT: This example uses the new WiFi101 library.
//
// You can check on your device after a successful
// connection here: https://shiftr.io/try.
//
// by Gilberto Conti
// https://github.com/256dpi/arduino-mqtt
#include <WiFi101.h>
#include <MQTT.h>
#include "MqttWrapper.h"
const char ssid[] = "ssid";
const char pass[] = "password";
WiFiClient net;
MQTTClient client;
MqttWrapperClass MqttWrap(client, net);
void setup() {
MqttWrap.setup();
}
void loop() {
MqttWrap.loop();
}
the MqttWrapper.h :
// MqttWrapper.h
#ifndef _MQTTWRAPPER_h
#define _MQTTWRAPPER_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include <WiFi101.h>
#include <MQTT.h>
class MqttWrapperClass
{
private:
MQTTClient _client;
WiFiClient _netClient;
int _lastMillis;
public:
MqttWrapperClass();
MqttWrapperClass(MQTTClient &client, WiFiClient &netClient);
void connect();
void setup();
void loop();
void init();
void messageReceived(String & topic, String & payload);
};
extern MqttWrapperClass MqttWrapper;
#endif
The MqttWrapper.cpp :
//
//
//
#include "MqttWrapper.h"
MqttWrapperClass::MqttWrapperClass()
{
}
MqttWrapperClass::MqttWrapperClass(MQTTClient &client, WiFiClient &netClient)
{
this->_client = client;
_netClient = netClient;
}
void MqttWrapperClass::connect()
{
Serial.print("checking wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while (!this->_client.connect("client_id", "user", "passwd")) {
Serial.print(".");
delay(1000);
}
Serial.println("connected!");
this->_client.subscribe("/hello");
// this->_client.unsubscribe("/hello");
}
void MqttWrapperClass::setup()
{
WiFi.begin("ssid", "password");
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
// You need to set the IP address directly.
this->_client.begin("server_url", _netClient);
this->_client.onMessage(messageReceived);
connect();
}
void MqttWrapperClass::loop()
{
if (!this->_client.connected()) {
this->connect();
}
// publish a message roughly every second.
if (millis() - _lastMillis > 2000) {
_lastMillis = millis();
this->_client.publish("/hello", "esnqerbw");
}
}
void MqttWrapperClass::init()
{
}
void MqttWrapperClass::messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload);
}
MqttWrapperClass MqttWrapper;
With this way of coding, it works for a few messages to send, but it fails after 2 ou 3 successful messages upload. I get then an error in the WiFisocket.cpp in the write function with a SOCK_ERR_BUFFER_FULL error :
size_t WiFiSocketClass::write(SOCKET sock, const uint8_t *buf, size_t size)
{
m2m_wifi_handle_events(NULL);
if (_info[sock].state != SOCKET_STATE_CONNECTED) {
return 0;
}
#ifdef CONF_PERIPH
// Network led ON (rev A then rev B).
m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 0);
m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 0);
#endif
sint16 err;
while ((err = send(sock, (void *)buf, size, 0)) < 0) {
Serial.println("SocketWrite error");
// Exit on fatal error, retry if buffer not ready.
if (err != SOCK_ERR_BUFFER_FULL) {
size = 0;
break;
} else if (hif_receive_blocked) {
size = 0;
break;
}
m2m_wifi_handle_events(NULL);
}
#ifdef CONF_PERIPH
// Network led OFF (rev A then rev B).
m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 1);
m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 1);
#endif
return size;
}
This never happens if I put the code in the .ino file, why ? I tried the same config with a MKR1400 and I didn't have this kind of problem.
Any idea why ?