ESP8266-MQTT

Updated with unlink, disconnect recovery and async queue event on 29 April, 2015

The best system to interchange data between different systems remains MQTT and there are about libraries for all operating systems and for all development systems. MQ Telemetry Transport (MQTT) is a lightweight broker-based publish/subscribe messaging protocol designed to be open, simple, lightweight and easy to implement.

These characteristics make it ideal for use in constrained environments, for example, but not limited to where the network is expensive, has low bandwidth or is unreliable or when run on an embedded device with limited processor or memory resources.

I wanted to try my hand from here in the thing and I started with good examples on the net and converting the various sources to get a library working with the protocol 3.1 This protocol has only a few restrictions in the use of wildcard characters but lends itself to interchange messages string between systems without great waste of resources and every system support it.

Features of the protocol include the publish/subscribe message pattern to provide one-to-many message distribution and decoupling of applications, a messaging transport that is agnostic to the content of the payload and the use of pure TCP/IP to provide basic network connectivity. Three qualities of service for message delivery ar supported:

  • "At most once", where messages are delivered according to the best efforts of the underlying TCP/IP network. Message loss or duplication can occur. This level could be used, for example, with ambient sensor data where it does not matter if an individual reading is lost as the next one will be published soon after.
  • "At least once", where messages are assured to arrive but duplicates may occur.
  • "Exactly once", where message are assured to arrive exactly once. This level could be used, for example, with billing systems where duplicate or lost messages could lead to incorrect charges being applied.

So from here MQTT library for Wiz550io I wanted to try my hand in the conversion of it for a WiFi module and which if not ESP8266 already repeatedly named in Firewing forums.

I started from a library example that David John Barker gave me and I referred to it in the MQTT-ESP8266.BAS module. The example gave me performed automatically the settings, join wifi network, transfer data and then close the connection. While in the case of the MQTT I needed a continuous connection I remodeled the library for this purpose.

This library has been tested with Firewing R2 PIC24 version and is for this reason that in the source I put a locking check for different conditions. If you want to try their hand at some willing to test different hardware I remind you that the PIC18 version could not support even 2048 bytes needed for the MQTT receive buffer then remains only PIC32 version for which perhaps you need to change some interrupt registers.

The ESP8266 module is certainly among the most nominated in the network for its low cost and ease of use. The library uses the main serial for debugging and uses the second serial to drive the ESP8266 through the i/o lines D2 and D3 as shown (remember also to connect the pin CH_PD to 3.3 volts):

So only 5 of 8 wires are connected to the Firewing board, GPIO lines can be used as general purpose I/O or can be used to update the firmware.. you can find several examples of how to do it in web.

You can download Firewing library modules here: ESP8266 WiFi Module MQTT Library

As usual to update the UserLibrary drag and drop the compressed file directly into the Firewing IDE editor window and two folders will be created, ESP8266 and MQTT, in your UserLibrary folder.

For the debugging I used two programs written in VB.NET that reference the open source library M2Mqtt (m2mqtt.codeplex.com) which among other things allows to get executables for Windows / Linux (Mono) and Windows Phone (7.8 and 8.1) a boon. However, nothing prevents you from using other development systems since this protocol is well established and there are a lot of libraries/sources for Android and iOS.

You can download vb.net windows client examples here: VB.NET test client

To use MQTT need a server named "Broker" and even in this case there are open source libraries for all operating systems and I used mosquitto for windows that provides two of his application to send new and receive messages from the command line. Mosquitto also provides a service broker on line at 85.119.83.194 IP address.

In this protocol is defined "Topic" a message queue and one of the most important features is the ability to define a Topic (named WillTopic ) to send a message (named WillMessage) to other connected clients that occurred a single client disconnection. If we add the fact that everyone can have a broker in your own home and can make visible the internet service by opening a single port of a router .. hello internet of things.

Clearly not going to go into too much detail of MQTT but would definitely recommend to take a ride on the Internet to gather information and in a week or so you'll be more than satisfied.

ESP8266 MQTT Reader program

clock = 80

#option MQTT_DEBUG         = False
#option MQTT_DUMP          = False

// If MQTT_TICKS = True MQTT module use his MQTT-Tick module
//               = False caller program must implement a timer to call the 
//                 sub MQTTSetKeepAlive every KeepAlive seconds

#option MQTT_TICKS         = False   

// If MQTT_ASYNC = True caller program use OnMQTTQueueChanges event
//               = False caller program must test MQTTIsQueueChanged(nQueue) 
//                 for changes

#option MQTT_ASYNC         = True

#option _gccOptimise = s 
imports "MQTT-ESP8266"

#if MQTT_TICKS = False
// Main program use his KeepAlive management 
// so declare a variable and a constant 
// then set only one timer and import Timers module

Private Dim 
   KeepAlive        as UInteger    = 0

Const cKeepAliveSecs = 20

   #option TIMER_AVAILABLE = 1  
   Imports Timers
#endif


// ##################################################################################

// ##################################################################################

Private Const 
    BrokerAddr(4)   As Byte     = {85,119,83,194},   // Mosquitto MQTT Broker Service
    Topic1                      = "/mqtt/topic1",
    Topic2                      = "/mqtt/topic2",
    WillTopic                   = "/mqtt/willtopic"  

Private Dim 
    MessQueue1      As String(256) = "",
    MessQueue2      As String(256) = "",
    WillMessage     As String(256) = "Sorry, see you later"

private dim
    WiFiNetName     as string = "<WiFiNetName>",
    WiFiNetPassword as string = "<WiFiNetPassword>"    

#if MQTT_TICKS = False
// Main program use his KeepAlive management 
// So this sub handle Timers.OnTimeout event 
Sub OnTimeout(ByRef timer As TimerItem) Handles Timers.OnTimeout
   Dim Item As TimerItem = timer                       
   Select Item.ID                                      
   Case 0 
      Item.Interval = 10
      If KeepAlive > (99 * cKeepAliveSecs) Then
         console.write("MQTTSetKeepAlive",13,10)
         MQTT_ESP8266.MQTTSetKeepAlive()
         KeepAlive = 0
      Else
         KeepAlive = KeepAlive + 1
      End If 
   End Select

   Item.Enabled = True
   timer = Item  
End Sub
#endif

#if MQTT_ASYNC = True
// Main program want use an async mode to read queues.. 
// So this sub handle MQTT_ESP8266.OnMQTTQueueChanges event 
private sub QueueChanges(n as byte) handles MQTT_ESP8266.OnMQTTQueueChanges
   select n
   case 0    
      console.write("OK, message on 'MessQueue1'",13,10)
      console.write("->", MessQueue1,"<-",13,10) 
   case 1                                        
      console.write("OK, message on 'MessQueue2'",13,10)
      console.write("->", MessQueue2,"<-",13,10) 
   end select   
end sub 
#endif

// This sub handle the broker connection event
private sub HelloMessage() handles MQTT_ESP8266.OnMQTTBrokerConnected
   console.write("Broker is connected!!",13,10)     
end sub 


private sub Main()     
   DelayMS(2000)

   #if MQTT_TICKS = False
   // Main program use his KeepAlive management 
   // so add a single Timer at 1000 ms    
   Timers.Add(1000)   ' 1000 ms timer
   #endif

   console.write("First try a WiFi join..",13,10)

   if JoinToWiFi(WiFiNetName, WiFiNetPassword) then
      console.write("WiFi join successfully",13,10)
      console.write("Now set broker parms..",13,10)         
      If Not MQTTSetBroker(addressof(BrokerAddr)) Then
         console.write("Errors into configuration parms!",13,10)
         CloseSocket()
      Else
         console.write("Broker parms is ok..",13,10)
         console.write("Now store 2 subscriptions in memory",13,10)	
         If MQTTAddSubscription(addressof(Topic1),
                                QOS_LEVEL_EXACTLY_ONCE,
                                True,
                                True,
                                addressof(MessQueue1), 
                                SizeOf(MessQueue1)) Then
            console.write("Subscription added successfully on Topic1",13,10)
         Else
            console.write("Unable to set subscription on Topic1!",13,10)
         End If

         If MQTTAddSubscription(addressof(Topic2),
                                QOS_LEVEL_EXACTLY_ONCE,
                                True,
                                True,
                                addressof(MessQueue2), 
                                SizeOf(MessQueue2)) Then
             console.write("Subscription added successfully on Topic2",13,10)
         Else
             console.write("Unable to set subscription on Topic1!",13,10)
         End If


         console.write("Now can try a connection to broker...",13,10)

         If MQTTConnect("MyMQTTReader", false, false, 1, addressof(WillTopic), addressof(WillMessage)) Then 
            console.write("'MyMQTTReader' is now connected to broker",13,10)            
            console.write("Now send subscriptions to broker",13,10) 

            #if MQTT_TICKS = False
            // Main program use his KeepAlive management 
            // so start all defined Timers (only one)
            console.write("And start KeepAlive timer",13,10) 
            Timers.Start          
            #endif  

            If MQTTSubscribe() Then
               console.write("All subscriptions are made",13,10)            
               console.write("All is done.",13,10)
               console.write("Now you must send some messages with an MQTT Client please.",13,10)            

               while True
                  MQTTService()
                  #if MQTT_ASYNC = False
                  // Main program not use Async read method
                  // so read every queue changed flag
                  if MQTTIsQueueChanged(0) Then
                     console.write("OK, message on 'MessQueue1'",13,10)
                     console.write("->", MessQueue1,"<-",13,10) 
                  End If
                  If MQTTIsQueueChanged(1) Then
                     console.write("OK, message on 'MessQueue2'",13,10)
                     console.write("->", MessQueue2,"<-",13,10) 
                  End If
                  #endif
               end while                                             
            Else
               console.write("Unable to set subscriptions on broker!",13,10)
            End If
         Else
            console.write("Unable to set connection!",13,10)
         End If
      End If
   else
      console.write("Unable to join to this WiFi network!",13,10)      
   end if

   While true
   End While
end sub

ESP8266 MQTT Sender program

clock = 80

#option MQTT_DEBUG         = false
#option MQTT_DUMP          = False
#option _gccOptimise = s 
imports "MQTT-ESP8266"

// ##################################################################################

// ##################################################################################

Private Const
    BrokerAddr(4)   As Byte     = {85,119,83,194},   // Mosquitto MQTT Broker Service
    Topic1                      = "/mqtt/topic1",
    Topic2                      = "/mqtt/topic2",
    TopicNum        As Byte     = 2, 
    WillTopic                   = "/mqtt/willtopic"    

Private Dim 
    WillMessage     As String(256) = "Sorry, see you later",
    MessQueue1      as string(256) = "",
    MessQueue2      as string(256) = ""

private dim
    WiFiNetName     as string = "<WiFiNetName>",
    WiFiNetPassword as string = "<WiFiNetPassword>"    


private sub Main()

   DelayMS(2000)

   console.write("First try a WiFi join..",13,10)
   if JoinToWiFi(WiFiNetName, WiFiNetPassword) then
      If Not MQTTSetBroker(addressof(BrokerAddr)) Then
         console.writeline("Errors into configuration parms!")
         CloseSocket()
      Else
         console.writeline("Broker parms is ok..")
         console.writeline("Now connect to it")

         If MQTTConnect("MyMQTTSender", 
                        false, 
                        false, 
                        0, 
                        addressof(WillTopic), 
                        addressof(WillMessage)) Then

            console.writeline("'MyMQTTSender' is now connected to broker")            
            If MQTTPublish(addressof(Topic1),"Hello world on my wonderfull Topic1") Then
               console.writeline("Message published")
            Else
               console.writeline("Unable to publish message!")
            End If

            While true
               MQTTService()
            End While
         Else
            console.writeline("Unable to set connection!")
         End If      
      end if
   else
      console.write("Unable to join to this WiFi network!",13,10)      
   end if  
   while True
   end while   
end sub