The bridge doesn't receive all the packets from the mesh node
I'm working on a mesh of camera nodes connected to an MQTT broker via bridge. The node (actually, for test, there is only one camera node) take a picture every 20 seconds (TAKE_PHOTO_INTERVAL_S
) and it should send it to the bridge that should in turn send it to the MQTT broker. My first problem was that if the picture size is greater than about 5-10 Kbyte, the node send it (?) but the bridge doesn't receive nothing! I asked in #413 (closed) for this issue but sadly no response yet. After that, I have divided the picture in smaller packets to avoid the problem and to make it possible to send big pakets through the mesh. But now I have another problem: when I divide the picture in 6 packets for example, the bridge receives only the first one, not the other 5! I'm wondering why. Maybe cause the sendData
function is inside a my scheduler task? Can someone give me suggestions?
Following the code of the camera node and the bridge, and the relatives outputs
The camera node code:
#include <Arduino.h>
#include <Base64.h>
#include "esp_camera.h"
#include "soc/soc.h" // Disable brownour problems
#include "soc/rtc_cntl_reg.h" // Disable brownour problems
#include <map>
#include <painlessMesh.h>
using namespace painlessmesh;
/*******************************************************************************
* Macro Definitions
******************************************************************************/
#define CFG_MESH_PREFIX "MyMesh"
#define CFG_MESH_PASSWORD "mymesh1234"
#define CFG_MESH_PORT 5555
#define CFG_MESH_CHANNEL 11
#define CFG_MESH_PACKET_TYPE_REQUEST "request"
#define CFG_MESH_PACKET_TYPE_SENSOR "sensor"
#define CFG_MESH_MAX_PACKET_SIZE 1000
#define NODE_ID "NODE01"
#define TAKE_PHOTO_INTERVAL_S 20
#define BRIDGE_NODE_ID "BRIDGE"
/*******************************************************************************
* NAMED MESH
******************************************************************************/
typedef std::function< void( String &from, String &msg ) > namedReceivedCallback_t;
class namedMesh : public painlessMesh
{
public:
namedMesh()
{
auto cb = [ this ]( uint32_t from, String &msg )
{
// Try to parse it.. Need to test it with non json function
DynamicJsonDocument jsonBuffer( 1024 + msg.length() );
DeserializationError error = deserializeJson( jsonBuffer, msg );
if ( error )
{
Serial.print( F( "DeserializeJson() failed: " ) );
Serial.println( error.c_str() );
return;
}
JsonObject root = jsonBuffer.as< JsonObject >();
if ( root.containsKey( "topic" ) && String( "nameBroadCast" ).equals( root[ "topic" ].as< String >() ) )
{
nameMap[ from ] = root[ "name" ].as< String >();
}
else
{
if ( userReceivedCallback )
{
// If needed send it on to userReceivedCallback
userReceivedCallback( from, msg );
}
if ( userNamedReceivedCallback )
{
String name;
// If needed look up name and send it on to
// userNamedReceivedCallback
if ( nameMap.count( from ) > 0 )
{
name = nameMap[ from ];
}
else
{
name = String( from );
}
userNamedReceivedCallback( name, msg );
}
}
};
painlessMesh::onReceive( cb );
changedConnectionCallbacks.push_back( [ this ]( uint32_t id )
{
if ( nameBroadCastTask.isEnabled() )
nameBroadCastTask.forceNextIteration();
} );
}
bool checkNode( String &name )
{
for ( auto && pr : nameMap )
{
if ( name.equals( pr.second ) )
{
if ( this->isConnected( pr.first ) )
{
return true;
}
}
}
return false;
}
void printMap( void )
{
Serial.println( "Name Map:" );
for ( auto && pr : nameMap )
{
Serial.println( "( " + String ( pr.first ) + " ; " + pr.second + " )" );
}
}
String getNodeName( uint32_t nodeId )
{
// Look up name
for ( auto && pr : nameMap )
{
if ( nodeId == pr.first )
{
String name = pr.second;
return name;
}
}
return String( "NULL" );
}
String getLocalName( void )
{
return nodeName;
}
void setName( String &name )
{
nodeName = name;
// Start broadcast task if not done yet
if ( !nameBroadCastInit )
{
// Initialize
nameBroadCastTask.set( 5 * TASK_MINUTE, TASK_FOREVER, [ this ]()
{
String msg;
// Create arduinoJson msg
DynamicJsonDocument jsonBuffer( 1024 );
JsonObject root = jsonBuffer.to< JsonObject >();
root[ "topic" ] = "nameBroadCast";
root[ "name" ] = this->getName();
serializeJson( root, msg );
this->sendBroadcast( msg );
} );
// Add it
mScheduler->addTask( nameBroadCastTask );
nameBroadCastTask.enableDelayed();
nameBroadCastInit = true;
}
nameBroadCastTask.forceNextIteration();
}
using painlessMesh::sendSingle;
bool sendSingle( String &name, String &msg )
{
// Look up name
for ( auto && pr : nameMap )
{
if ( name.equals( pr.second ) )
{
uint32_t to = pr.first;
return painlessMesh::sendSingle( to, msg );
}
}
return false;
}
virtual void stop()
{
nameBroadCastTask.disable();
mScheduler->deleteTask( nameBroadCastTask );
painlessMesh::stop();
}
virtual void onReceive( receivedCallback_t onReceive )
{
userReceivedCallback = onReceive;
}
void onReceive( namedReceivedCallback_t onReceive )
{
userNamedReceivedCallback = onReceive;
}
protected:
String nodeName;
std::map< uint32_t, String > nameMap;
receivedCallback_t userReceivedCallback;
namedReceivedCallback_t userNamedReceivedCallback;
bool nameBroadCastInit = false;
Task nameBroadCastTask;
};
/*******************************************************************************
* Global Variables
******************************************************************************/
Scheduler userScheduler;
namedMesh mesh;
String bridgeNodeName = BRIDGE_NODE_ID;
String nodeName = NODE_ID;
char encodedString[ 16384 ];
/*******************************************************************************
* Functions Definitions
******************************************************************************/
void droppedConnectionCallback( uint32_t nodeId )
{
String name = mesh.getNodeName( nodeId );
Serial.println( "Dropped connection with " + name );
}
void newConnectionCallback( uint32_t nodeId )
{
String name = mesh.getNodeName( nodeId );
Serial.println( "New connection with " + name );
}
void changedConnectionsCallback( void )
{
Serial.println( "Layout of the mesh changed" );
}
Task taskSendMessage( TASK_SECOND * TAKE_PHOTO_INTERVAL_S, TASK_FOREVER, []()
{
if ( mesh.checkNode( bridgeNodeName ) )
{
Serial.println( "BRIDGE node found" );
capturePhoto();
}
else
{
Serial.println( "BRIDGE node not found" );
}
} );
void sendData( String sensorType, long idPacket, int indexPacket, int totalPackets, String dataSensor )
{
String msg;
String to = bridgeNodeName;
DynamicJsonDocument jsonBuffer( 1024 + dataSensor.length() );
JsonObject root = jsonBuffer.to< JsonObject >();
root[ "nodeId" ] = nodeName;
root[ "type" ] = CFG_MESH_PACKET_TYPE_SENSOR;
JsonObject packet = root.createNestedObject( "packet" );
packet[ "sensor" ] = sensorType;
packet[ "idPacket" ] = String( idPacket );
packet[ "indexPacket" ] = String( indexPacket );
packet[ "totalPackets" ] = String( totalPackets );
packet[ "data" ] = dataSensor;
serializeJson( root, msg );
Serial.println( msg );
Serial.println( "---> Send " + sensorType + " packet " + String( indexPacket ) + "/" + String( totalPackets ) + " to " + to );
mesh.sendSingle( to, msg );
}
void setupCamera( void )
{
// Turn-off the 'brownout detector'
WRITE_PERI_REG( RTC_CNTL_BROWN_OUT_REG, 0 );
// OV2640 camera module
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
if ( psramFound() )
{
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
}
else
{
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// Camera init
esp_err_t err = esp_camera_init( &config );
if ( err != ESP_OK )
{
Serial.printf( "Camera init failed with error 0x%x", err );
ESP.restart();
return;
}
sensor_t * s = esp_camera_sensor_get();
// initial sensors are flipped vertically and colors are a bit saturated
if ( s->id.PID == OV3660_PID )
{
s->set_vflip( s, 1 ); // flip it back
s->set_brightness( s, 1 ); // up the brightness just a bit
s->set_saturation( s, -2 ); // lower the saturation
}
// drop down frame size for higher initial frame rate
s->set_framesize( s, FRAMESIZE_QVGA );
randomSeed( 42 );
}
void capturePhoto( void )
{
// Retrieve camera framebuffer
camera_fb_t * fb = NULL;
uint8_t* _jpg_buf = NULL;
size_t _jpg_buf_len = 0;
esp_err_t res = ESP_OK;
Serial.print( "Capturing Image .." );
fb = esp_camera_fb_get();
if ( !fb )
{
Serial.println( "Camera capture failed" );
res = ESP_FAIL;
}
else
{
Serial.println( "Done!" );
Serial.println( String( "Size of the image..." ) + String( fb->len ) );
if ( fb->format != PIXFORMAT_JPEG )
{
Serial.println( "Compressing" );
bool jpeg_converted = frame2jpg( fb, 80, &_jpg_buf, &_jpg_buf_len );
esp_camera_fb_return( fb );
fb = NULL;
if ( !jpeg_converted )
{
Serial.println( "JPEG compression failed" );
res = ESP_FAIL;
}
}
else
{
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
int encodedLength = Base64.encodedLength( _jpg_buf_len );
Serial.println( "Size of the base64 encoded image..." + String( encodedLength ) );
Base64.encode( encodedString, ( char * )_jpg_buf, _jpg_buf_len );
encodedString[ encodedLength ] = 0;
Serial.println( "Encoded string created" );
int tailPacketLength = encodedLength % CFG_MESH_MAX_PACKET_SIZE;
long idPacket = random( LONG_MIN, LONG_MAX );
if ( tailPacketLength == encodedLength )
{
sendData( "camera", idPacket, 1, 1, String( encodedString ) );
}
else
{
String photoString( encodedString );
int numPackets = ( encodedLength / CFG_MESH_MAX_PACKET_SIZE ) + 1;
String fractPacket;
int i;
for ( i = 0; i < ( numPackets - 1 ); i++ )
{
fractPacket = photoString.substring( i * CFG_MESH_MAX_PACKET_SIZE, ( i * CFG_MESH_MAX_PACKET_SIZE ) + CFG_MESH_MAX_PACKET_SIZE );
sendData( "camera", idPacket, i + 1, numPackets, String( fractPacket ) );
vTaskDelay( 1000 / portTICK_PERIOD_MS );
fractPacket = "";
}
fractPacket = photoString.substring( i * CFG_MESH_MAX_PACKET_SIZE );
sendData( "camera", idPacket, i + 1, numPackets, String( fractPacket ) );
vTaskDelay( 1000 / portTICK_PERIOD_MS );
fractPacket = "";
}
if ( fb)
{
esp_camera_fb_return( fb );
fb = NULL;
_jpg_buf = NULL;
}
}
if ( res != ESP_OK )
{
return;
}
}
/*******************************************************************************
*******************************************************************************
*
* SETUP FUNCTION
*
*******************************************************************************
******************************************************************************/
void setup()
{
Serial.begin( 115200 );
// CAMERA SETUP
setupCamera();
// MESH SETUP
mesh.setDebugMsgTypes( ERROR | STARTUP ); // set before init() so that you can see startup messages
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT, WIFI_AP_STA, CFG_MESH_CHANNEL );
mesh.setName( nodeName );
mesh.setRoot( false );
mesh.setContainsRoot( true );
mesh.onDroppedConnection( &droppedConnectionCallback );
mesh.onNewConnection( &newConnectionCallback );
mesh.onChangedConnections( &changedConnectionsCallback );
// USER TASK SETUP
userScheduler.addTask( taskSendMessage );
taskSendMessage.enable();
// VARIABLES SETUP
nodeConnected = false;
Serial.println( "\n********** Hi! I'm the " + String( NODE_ID ) + " **********\n" );
}
/*******************************************************************************
*******************************************************************************
*
* LOOP FUNCTION
*
*******************************************************************************
******************************************************************************/
void loop()
{
mesh.update();
}
The bridge code:
#include <Arduino.h>
#include <PubSubClient.h>
#include <map>
#include <painlessMesh.h>
using namespace painlessmesh;
/*******************************************************************************
* Macro Definitions
******************************************************************************/
#define MQTT_BROKER_IP 192, 168, 1, 111
#define MQTT_BROKER_PORT 1883
#define MQTT_CLIENT_ID "my-client"
#define MQTT_USER "myUser"
#define MQTT_PASS "myPass"
#define MQTT_CHECK_CONNECTION_S 60
#define CFG_MESH_PREFIX "MyMesh"
#define CFG_MESH_PASSWORD "MyMesh1234"
#define CFG_MESH_PORT 5555
#define CFG_MESH_CHANNEL 11
#define CFG_MESH_PACKET_TYPE_REQUEST "request"
#define CFG_MESH_PACKET_TYPE_SENSOR "sensor"
#define CFG_STATION_SSID "StationId"
#define CFG_STATION_PASSWORD "StationPass"
#define CFG_HOSTNAME "MyMesh_Bridge"
#define CFG_TOPIC_ROOT "MyRootTopic/"
#define CFG_TOPIC_SYSTEM_IN "MyRootTopic/system/to/service"
#define CFG_TOPIC_SYSTEM_OUT "MyRootTopic/system/from/service"
#define CFG_TOPIC_CAMS_IN "MyRootTopic/sensors/cams/to/"
#define CFG_TOPIC_CAMS_OUT "MyRootTopic/sensors/cams/from/"
#define NODE_ID "BRIDGE"
#define TIMING_INTERVAL_S 10
/*******************************************************************************
* NAMED MESH
******************************************************************************/
typedef std::function< void( String &from, String &msg ) > namedReceivedCallback_t;
class namedMesh : public painlessMesh
{
public:
namedMesh()
{
auto cb = [ this ]( uint32_t from, String &msg )
{
// Try to parse it.. Need to test it with non json function
DynamicJsonDocument jsonBuffer( 1024 + msg.length() );
DeserializationError error = deserializeJson( jsonBuffer, msg );
if ( error )
{
Serial.print( F( "DeserializeJson() failed: " ) );
Serial.println( error.c_str() );
return;
}
JsonObject root = jsonBuffer.as< JsonObject >();
if ( root.containsKey( "topic" ) && String( "nameBroadCast" ).equals( root[ "topic" ].as< String >() ) )
{
nameMap[ from ] = root[ "name" ].as< String >();
}
else
{
if ( userReceivedCallback )
{
// If needed send it on to userReceivedCallback
userReceivedCallback( from, msg );
}
if ( userNamedReceivedCallback )
{
String name;
// If needed look up name and send it on to
// userNamedReceivedCallback
if ( nameMap.count( from ) > 0 )
{
name = nameMap[ from ];
}
else
{
name = String( from );
}
userNamedReceivedCallback( name, msg );
}
}
};
painlessMesh::onReceive( cb );
changedConnectionCallbacks.push_back( [ this ]( uint32_t id )
{
if ( nameBroadCastTask.isEnabled() )
nameBroadCastTask.forceNextIteration();
} );
}
bool checkNode( String &name )
{
for ( auto && pr : nameMap )
{
if ( name.equals( pr.second ) )
{
if ( this->isConnected( pr.first ) )
{
return true;
}
}
}
return false;
}
void printMap( void )
{
Serial.println( "Name Map:" );
for ( auto && pr : nameMap )
{
Serial.println( "( " + String ( pr.first ) + " ; " + pr.second + " )" );
}
}
String getNodeName( uint32_t nodeId )
{
// Look up name
for ( auto && pr : nameMap )
{
if ( nodeId == pr.first )
{
String name = pr.second;
return name;
}
}
return String( "NULL" );
}
String getLocalName( void )
{
return nodeName;
}
void setName( String &name )
{
nodeName = name;
// Start broadcast task if not done yet
if ( !nameBroadCastInit )
{
// Initialize
nameBroadCastTask.set( 5 * TASK_MINUTE, TASK_FOREVER, [ this ]()
{
String msg;
// Create arduinoJson msg
DynamicJsonDocument jsonBuffer( 1024 );
JsonObject root = jsonBuffer.to< JsonObject >();
root[ "topic" ] = "nameBroadCast";
root[ "name" ] = this->getName();
serializeJson( root, msg );
this->sendBroadcast( msg );
} );
// Add it
mScheduler->addTask( nameBroadCastTask );
nameBroadCastTask.enableDelayed();
nameBroadCastInit = true;
}
nameBroadCastTask.forceNextIteration();
}
using painlessMesh::sendSingle;
bool sendSingle( String &name, String &msg )
{
// Look up name
for ( auto && pr : nameMap )
{
if ( name.equals( pr.second ) )
{
uint32_t to = pr.first;
return painlessMesh::sendSingle( to, msg );
}
}
return false;
}
virtual void stop()
{
nameBroadCastTask.disable();
mScheduler->deleteTask( nameBroadCastTask );
painlessMesh::stop();
}
virtual void onReceive( receivedCallback_t onReceive )
{
userReceivedCallback = onReceive;
}
void onReceive( namedReceivedCallback_t onReceive )
{
userNamedReceivedCallback = onReceive;
}
protected:
String nodeName;
std::map< uint32_t, String > nameMap;
receivedCallback_t userReceivedCallback;
namedReceivedCallback_t userNamedReceivedCallback;
bool nameBroadCastInit = false;
Task nameBroadCastTask;
};
/*******************************************************************************
* Global Variables
******************************************************************************/
IPAddress myIP( 0, 0, 0, 0 );
IPAddress mqttBroker( MQTT_BROKER_IP );
namedMesh mesh;
WiFiClient wifiClient;
PubSubClient mqttClient;
bool mqttClientConnected = false;
String nodeName = NODE_ID;
uint32_t nexttime = 0;
bool initialized = false;
/*******************************************************************************
* Functions Definitions
******************************************************************************/
void namedReceivedCallback( String &from, String &msgFrom )
{
DynamicJsonDocument jsonBufferFrom( 1024 + msgFrom.length() );
DeserializationError error = deserializeJson( jsonBufferFrom, msgFrom );
if ( error )
{
Serial.print( F( "DeserializeJson() failed: " ) );
Serial.println( error.c_str() );
return;
}
JsonObject rootFrom = jsonBufferFrom.as< JsonObject >();
if ( rootFrom.containsKey( "type" ) && String( "request" ).equals( rootFrom[ "type" ].as< String >() ) )
{
String request = rootFrom[ "packet" ].as< String >();
if ( String( "MQTT ready?" ).equals( request ) )
{
String response = mqttClientConnected ? "true" : "false";
String msgTo;
String to = from;
DynamicJsonDocument jsonBufferTo( 1024 );
JsonObject rootTo = jsonBufferTo.to< JsonObject >();
rootTo[ "nodeId" ] = nodeName;
rootTo[ "type" ] = CFG_MESH_PACKET_TYPE_REQUEST;
rootTo[ "packet" ] = String( nodeName + " ready " + response );
serializeJson( rootTo, msgTo );
Serial.println( "<--- Received " + String( CFG_MESH_PACKET_TYPE_REQUEST ) + " from " + from );
mesh.sendSingle( to, msgTo );
}
}
else if ( rootFrom.containsKey( "type" ) && String( "sensor" ).equals( rootFrom[ "type" ].as< String >() ) )
{
if ( mqttClientConnected == true )
{
String msgTo;
DynamicJsonDocument jsonBufferTo( 1024 + msgFrom.length() );
JsonObject rootTo = jsonBufferTo.to< JsonObject >();
rootTo[ "nodeId" ] = from;
rootTo[ "sensor" ] = rootFrom[ "packet" ][ "sensor" ].as< String >();
rootTo[ "idPacket" ] = rootFrom[ "packet" ][ "idPacket" ].as< String >();
rootTo[ "indexPacket" ] = rootFrom[ "packet" ][ "indexPacket" ].as< String >();
rootTo[ "totalPackets" ] = rootFrom[ "packet" ][ "totalPackets" ].as< String >();
rootTo[ "data" ] = rootFrom[ "packet" ][ "data" ].as< String >();
serializeJson( rootTo, msgTo );
Serial.println( msgTo );
Serial.println( "<--- Received " + rootFrom[ "packet" ][ "sensor" ].as< String >() + " from " + from );
String topic = TOPIC_CAMS_OUT + String( from );
mqttClient.publish( topic.c_str(), msgTo.c_str() );
}
}
}
void droppedConnectionCallback( uint32_t nodeId )
{
String name = mesh.getNodeName( nodeId );
Serial.println( "Dropped connection with " + name );
}
void newConnectionCallback( uint32_t nodeId )
{
String name = mesh.getNodeName( nodeId );
Serial.println( "New connection with " + name );
}
void changedConnectionsCallback( void )
{
Serial.println( "Layout of the mesh changed" );
}
void mqttCallback( char* topic, uint8_t* payload, unsigned int length )
{
char* cleanPayload = ( char* )malloc( length + 1 );
memcpy( cleanPayload, payload, length );
cleanPayload[ length ] = '\0';
String msg = String( cleanPayload );
free( cleanPayload );
String targetStr = String( topic ).substring( 8 );
if ( targetStr == "system/to/service" )
{
if ( msg == "getNodes" )
{
auto nodes = mesh.getNodeList( true );
String str;
for ( auto && id : nodes )
{
str += String( id ) + String( " " );
}
mqttClient.publish( TOPIC_SYSTEM_OUT, str.c_str() );
}
else
{
mqttClient.publish( TOPIC_SYSTEM_OUT, "Service message unknown" );
}
}
else
{
mqttClient.publish( TOPIC_SYSTEM_OUT, "Wrong topic" );
}
}
void mqttConnectionHandle( void )
{
while ( !mqttClient.connected() )
{
Serial.println( "Attempting MQTT connection..." );
if ( mqttClient.connect( MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS ) && mqttClient.setBufferSize( 16384 ) )
{
Serial.println( "Connected to MQTT broker" );
mqttClient.publish( TOPIC_SYSTEM_OUT, "Ready!" );
mqttClient.subscribe( TOPIC_SYSTEM_IN );
mqttClientConnected = true;
}
else
{
Serial.print( "Failed, rc=" );
Serial.print( mqttClient.state() );
Serial.println( " try again in 2 seconds" );
delay( 2000 );
mesh.update();
mqttClient.loop();
}
}
}
/*******************************************************************************
*******************************************************************************
*
* SETUP FUNCTION
*
*******************************************************************************
******************************************************************************/
void setup()
{
Serial.begin( 115200 );
// MESH SETUP
mesh.setDebugMsgTypes( ERROR | STARTUP | CONNECTION );
mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT, WIFI_AP_STA, CFG_MESH_CHANNEL );
mesh.setName( nodeName );
mesh.onReceive( &namedReceivedCallback );
mesh.onDroppedConnection( &droppedConnectionCallback );
mesh.onNewConnection( &newConnectionCallback );
mesh.onChangedConnections( &changedConnectionsCallback );
mesh.stationManual( STATION_SSID, STATION_PASSWORD );
mesh.setHostname( HOSTNAME );
mesh.setRoot( true );
mesh.setContainsRoot( true );
mesh.initOTAReceive( NODE_ID );
mqttClient.setServer( mqttBroker, MQTT_BROKER_PORT );
mqttClient.setCallback( mqttCallback );
mqttClient.setClient( wifiClient );
Serial.println( "\n********** Hi! I'm the " + String( NODE_ID ) + " **********\n" );
}
/*******************************************************************************
*******************************************************************************
*
* LOOP FUNCTION
*
*******************************************************************************
******************************************************************************/
void loop()
{
mesh.update();
mqttClient.loop();
if ( myIP != getlocalIP() )
{
myIP = getlocalIP();
Serial.println( "My IP is " + myIP.toString() );
initialized = true;
}
if ( ( millis() >= nexttime ) && ( initialized ) )
{
nexttime = millis() + MQTT_CHECK_CONNECTION_S * 1000;
if ( !mqttClient.connected() )
{
mqttClientConnected = false;
mqttConnectionHandle();
}
}
}
The output log of camera node:
BRIDGE node found: it's connected
Capturing Image ..Done!
Size of the image...3997
Size of the base64 encoded image...5332
Encoded string created
{"nodeId":"NODE01","type":"sensor","packet":{"sensor":"camera","idPacket":"2147483647","indexPacket":"1","totalPackets":"6","data":"/9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDAAoHCAkIBgoJCAkLCwoMDxkQDw4ODx8WFxIZJCAmJiQgIyIoLToxKCs2KyIjMkQzNjs9QEFAJzBHTEY/Szo/QD7/2wBDAQsLCw8NDx0QEB0+KSMpPj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj7/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/wAARCADwAUADASEAAhEBAxEB/9oADAMBAAIRAxEAPwDQ1pY/LI2ivMtVIa7JA2+1dVR6WOOnTS1RnEVG3ArBHStBYk3Sj3rv/D9sn2dCY1PejqTNdzqoYIsf6tae0Uf/ADzWtDLkRC0UX/PNay7zygPuii5XIjlNTkTngCsCX5mzUyn0NIobtFAXipLEwPSmkUAgxQBzS3AtQwg9q2LW"}}
---> Send camera packet 1/6 to BRIDGE
{"nodeId":"NODE01","type":"sensor","packet":{"sensor":"camera","idPacket":"2147483647","indexPacket":"2","totalPackets":"6","data":"2Q/8sxUga0FrH/zzWr6W8eP9WtDDlRKII/8AnmKcII/+ea0EciHeTH/zyWjyYv8AnmKYciE8mL/nmtNMMf8AcWgORCGKP/nmtM8mP/nmKBciGGGP/nmtMMUf/PNaQvZojMEf/PNaYYo/+ea1e4ciImhj/wCea01oYv8AnktFxciRG0UfTy1qIxR/881oFyoi8pOflFMMaY+4KQ+VHZ6++Aa8zvm33Lmt5jplXpUR96yNLIs2Kb7hB716Vo0WIU+lERSN9Bhaa1UQUbmXatc7qV2FBOaBnI3Uu6Q1VqDRCgUUbhsMNJUjDFWIYtxoA1bS39q2rWDA6UgNKOOpgtAEmKdikAuKSgQ3FNpiGGkNAxhFMNMQymGhCI2FRtTAjIqJqLE3IjUZpiOh8STYVsV55Jy5rWqFN2IWqImsrGr3Nnw9AZLwf3RXpWnphBxQkZy3NHoKqzyYFaCMTULjg1yOo3W89aRSMg9aKz6lCUpoYMZ3opDJY491alrBSA27WDA6VqRR8UDLCrUoWkA7bS4oAXFNIphcaaYaBDSKZQA0imGmAyoyKCSM0w0CIyKjamSQsKiNVYLl3xTN8m3OM9/euPbnpV1dwhFELCohWZtc6/wpa5G9hzXfWqYWmjJ7ksrYFZV3JVAcvqtzwev4GualO40noOJFSbazbGBphoK6CVKkZNDGjStrfNbdrbYAyKQGrFFVtEpAThacFoAdtpcUAJimkUwG4phFAiMikNADDTTQIiNMNMQwio2poCM1E3SjqSyMiojSuJIqeIpt90PasJhWs9Zlw2IG4FESGR1X1NQ9RnpOgQbLZOK6NTtSqMyvNLWLf3GO9WByt/JukPNZbVEmaJDOKQ1m2wI2NL1FBQ9Eya0ba36UmJG5a2uK1oIsVJRdSOp1WgRJilxTAdikoASmkUANIphFMBhphoEMNMNADDUZpiGGo2oAiIphFMkiYVE3WmIw9Qk8y5bvVE1dT4rlQ2IGxV3SIvNuvpio"}}
---> Send camera packet 2/6 to BRIDGE
{"nodeId":"NODE01","type":"sensor","packet":{"sensor":"camera","idPacket":"2147483647","indexPacket":"3","totalPackets":"6","data":"RTZ6VpqgIKvStxWiMjNup8L1rnNQudx69KvYaMG4ky1VzWLKG0wmguwlPRSaliNG2ts+1b1tbVLA1oIquxx1JRYVakC0CH4pcUwDFJTAbim0AJTDQBGaZQIjNMIoAaRUZoEMNRmqEyM8VGaEBG1REUyTmH5kaoXpyZcWV2rofDNvl/MpJBI7m24XAouZgorQzMG/u65y7n3E49at7FRKRPNMNYFje1NoAcBmtC0tizdKkDorS0xjitaGHFSxluOOrSpxSAlC08CgB2KMUwDFNNADaaRTAYaYaAGGmGgRHTDQAw0wigQw1GaYiNqjIpiIyKjqhHK1XkqdTQhQb2wOtdrosePu9DVq5Mjot/lx1lX10PWrRmc3eXO41msSz1DZqthDTC1ZDGU5RzVAXbS33npXR2NrgDipGbUMWKtRx1LGWkSpgKQEmKdimIXFFACU2mA2mUAMNNoAjIphFMCMimGgQw000CGNURpgMNRsKdxDCKiPWmhHItwKqSNzSbNCfT4WmuRhfrXc6eghi6VcdTKW5Jc3QWubu7vPHOa0aCO5lM+85NNrA0GE0zNJoa3HKM1bt4N7ijzEdBYWYA963oIcClcZdRKsolIZMq1IBSAeBTsUAGKKAExTTTEMNNIoAYRTDQAw1GaYDCKZQIjIphoYhhqM0AMIphFUIjNRNTQmcZI1RRRNPMFFFi2dVpVkLaHpgnrWi8mxTWuxjbqYmoXnvWQzb2qJyNBp6Uw1BYylC0mBZt4dzVvafadDikyTftoMAVoRR0ii0iVOq1IyQCn4pjH4pcUhBikxTGJTDQIaaYaYhhqM0ANNMoAYRUZFMRGRTDTAYaYRQIjNRmgQwiojVCscSiGWQAA810em6esCZbOavqObNB5Ai9ax729/uHOfStGTEyWOTTa5zXYbmmGmIMc1ZhiZ+AKljNuytehIrftbfAqAsaUUdW0SgCwq1KFoGPAp+2kA7FGKYBSYoGNplIQ00wimIYaYRVAR"}}
---> Send camera packet 3/6 to BRIDGE
{"nodeId":"NODE01","type":"sensor","packet":{"sensor":"camera","idPacket":"2147483647","indexPacket":"4","totalPackets":"6","data":"mm0ARmmGgQw0wimBGaYaBEZqM0xEbVGRTEZlhp6wjd1P8q0HcKK3SFuzEvr3napNZLMWOaicuhVhv40hJ7Vl1LGGlA707iLMMW6tmxsicH9alyGb9rbbcVpRx1mMuIlWFWgCYLT8UAPAp2KAFooGFNpiEIphpANNMNMCOmmgQwimGqAYaYaAIyKjNMQw1GaBDGqM0wI2qIimxFd5VQVj319n5RXTsRrcyWfdQBXO2a2Cmd6QxQuasQw5qGLl1Nizsjn+tb9tb4FQxmjFFV1EoAsKtTKKBkgFSAUAOpcUDCigAppoAaabQIYRTKYDKbQIYaZVAMNMNAEZphoERGozVCGNUZpARmozTEcvdXrHhcYrOrSe44ihTTu1QNjBzRtpDTLMMBPatqys2zyMUgNy3t8VoxRVAFuNKsotAyVVqUCkBIBTqBjsUtIAopjEppoENpppgMNMNADTTDTJGmmGmAw1GaAIzUZpiIzURpgNaozSERmojTA4f3zS4qmx2H0lSwEAO7irUFuznofwpbDNmyssYrbt4AO1SwL0cdW40pAWUWpgKBkoqQUgHCnUDFpaACkoAKbQMZTaYhpppoENpmKYDDTTTERmozQBG1RmmIiNRmgQ01GaYETVGaAOLCUuKVmUJQFovqBdtrY5B21s2lp3wKlsdjWhgx2q7GlIRbRasKKAJVFSgUASCn0hjxTqBi0UDCkpCEptMBtNoGNptMQ0000EjDTDTAjNRmmBGaiagCI0w0yRjVG1AERqNqAOU21GVptlW6AqZNX7e16Ur9BGxbWo9K04oqm2oy1GlWlWgCdRUyikMkWpBQA8U+gY4U6kAtFABSUwEpppAJTaAG02mIaabTEMNRmgCM1GaYEZqM0xERqM0gGGojTAjNRGmScz1pUi3NTkWy/b2gzn+ladvbhQKgRfijxVpEpDLKrUyigCUCpVpDJBTxQA8U4UDH0tIApaACkpAJTaYCU2gBKbVCG0ygQw1GaYEZqM"}}
---> Send camera packet 4/6 to BRIDGE
{"nodeId":"NODE01","type":"sensor","packet":{"sensor":"camera","idPacket":"2147483647","indexPacket":"5","totalPackets":"6","data":"0ARmojQBGajNAiNqjNAiJqjNUBhxW571ft7bHak9SkX44qtpHUgWEWrKigRKBUooGSCpBQA8U8UhjqeKBjqWgQtFIBKKQxKSmMSkoJG000wGmozTEMNRmmBGaYaAIjUTUCIzUZpgMaoqAI2qJqBDY4MVaSOkBOiVOi0DJwtTAUgJQKeKQD6eKYxwqSkA6nCgY6lpALRQMSkoGFFMQlJQIbTaYDDTDQIjNRmgCM1GaYiM1EaAIzTDQBGajamBEajNMkthalVakZMq1MBQMlFSUhjxTxQA8U4UwHinipAcKdQMcKWkAUUDCigQUlMYlJQA2mmmSMNR0wGGozQBGajNAEZqI0CGGozTEMNRGgCI1H3poDRC1KoqREqipKBkgp4oGOFPFADxThSGPpwpDHU6gB1LmkMM0tACUtABSUxCUlADaaaYiM1GaAGmozQBGajNMCI1GaYiMmmGkAxqiamIiNRnrTA1gKkFIRIKfSGPFOoGPFPoGLTxSAcKdQA6nUhiiloAWloAWigYUlAhKSmAym0CIzTDTAjNMNAEZqM0CIzUTUARmmmgCM1GaBERqM0xGxUgoAeKeKQDqdQMfT6ChRTqQDxTs0wFp1IY6ikIdmloAKWmMSkoASkNADaYTQIYajNAEZphpgMNRmkIiNRmmAw1GaAGE1GaCSJqjpgbNPWkIeKeKBjqfQUOFOoAcKdQMdTqQxaXNADqdSAWimhC5pc0AJRQMTNMoENzTDTAZTDQBGajNADCajNAiMmmGgQw1G1AEZqM0ARmo6YjZp4pMQ4VIKBjqdQMdThQMfS0hjqXNMB1LSAcKdQMWlpiCloASjNADSaYTQAmaYaAGE1GaQDDTCaAI2NR0xEZphoEMNRmgCM0xqBEZqImmSzZp+aXUY4GpBTGOFPpIYop1Ax1OFADqWkMdS0AOp1MBaWkAUUwEzRQA0mmZoAbmmk0AMzTCaQhhNMJoAjJqM0wGGmGgRGaYaAIjUbUxEZqNjQM"}}
---> Send camera packet 5/6 to BRIDGE
{"nodeId":"NODE01","type":"sensor","packet":{"sensor":"camera","idPacket":"2147483647","indexPacket":"6","totalPackets":"6","data":"2acDQTceKkBpDHZpwoAdThQUOFOFACin0DHCloAdS0ALS5oAM0maAEzSZoATNNzQA0mmZoAaaYTQIjJphoGRmmGgQw000EkRqM0DIzTCaBXI2qI1RJtU6kMcKeKQD6eKBjhTqChadQA+nUDFpaAHUtAC5ooAKSgBKSgBuabmgBuaaaBDSajNADDTDQDGGmGgBpqM0CIzTDQIjNRGgRG1RsadhG3S0MQ4VIKChwp4pDH5pwoAWnCgY+loGOpaAFpaAFpKYwozQAmabmkA2m5oEIaZmgBuaYTQAwmmE0CGUwmgBtMNAiM1GaAI2NRtQIiaoyfWqEf/2Q=="}}
---> Send camera packet 6/6 to BRIDGE
The output log of bridge:
{"nodeId":"NODE01","sensor":"camera","idPacket":"2147483647","indexPacket":"1","totalPackets":"6","data":"/9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDAAoHCAkIBgoJCAkLCwoMDxkQDw4ODx8WFxIZJCAmJiQgIyIoLToxKCs2KyIjMkQzNjs9QEFAJzBHTEY/Szo/QD7/2wBDAQsLCw8NDx0QEB0+KSMpPj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj7/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/wAARCADwAUADASEAAhEBAxEB/9oADAMBAAIRAxEAPwDQ1pY/LI2ivMtVIa7JA2+1dVR6WOOnTS1RnEVG3ArBHStBYk3Sj3rv/D9sn2dCY1PejqTNdzqoYIsf6tae0Uf/ADzWtDLkRC0UX/PNay7zygPuii5XIjlNTkTngCsCX5mzUyn0NIobtFAXipLEwPSmkUAgxQBzS3AtQwg9q2LW"}
<--- Received camera from NODE01