View previous topic :: View next topic |
Author |
Message |
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Tue May 31, 2016 6:27 pm Post subject: Ultra Light MQTT client |
|
|
This is a Ultra Light MQTT client. An Arduino Mega 2560 with a W5100 ethernet shield acting as a Ultra Light MQTT client.
If you want to read more about this MQTT protocol check
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html
On the left our Arduino Mega 2560 with W5100 ethernet shield. Doing a connect / publish / disconnect. This can be all kind of information published to a MQTT broker server. On PC, Mobiel, you can subscribe to these messages and get an update everytime new information is published.
The flow of the network traffic in WireShark. You will find each item back in the Bascom-code below
Code: | 'Bascom Ultra Light MQTT client
'Hardware: Arduino Mega 2560 with W5100 Ethernet shield
'Ben Zijlstra - 2016
$regfile = "m2560def.dat" ' specify the used micro
$crystal = 16000000 ' used crystal frequency
$baud = 56700 ' use baud rate
$hwstack = 200
$swstack = 220
$framesize = 250
Config Portb.4 = Output
Wiz5100_cs Alias Portb.4
Wiz5100_cs = 1
Waitms 500
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 0
Spiinit
Config Tcpip = Noint , Mac = 12.128.12.33.46.74 , Ip = 192.168.0.221 , Submask = 255.255.255.0 , Gateway = 192.168.0.1 , _
Localport = 1000 , Tx = $55 , Rx = $55 , Chip = W5100 , Spi = 1 , Cs = Portb.4
Dim Idx As Byte
Dim Bclient As Byte
Dim Result As Word
Dim X As Byte
Dim S As Word
Dim I As Byte
Dim Tempw As Word
Dim Helpw As Word
Const Cdebug = 1 'for debug purpose
Const Connect = "{016}{025}{000}{004}MQTT{004}{002}{000}{030}{000}{013}Bascom-Client"
Const Publish = "{048}{034}{000}{007}mcselecBascom-MQTT-client online"
Const Pingreq = "{192}{000}" '&HC0 &H00 - keep alive
Const Disconnect = "{224}{000}" '&HE0 &H00
Print "Programm start"
Idx = 0
Bclient = Getsocket(idx , Sock_stream , 7000 , 0)
Result = Socketconnect(idx , <ip-address of your MQTT-broker> , 1883) 'the IP-address of the MQTT broker and the port
Do
Tempw = Socketstat(idx , 0) 'get status
If Tempw = Sock_established Then
#if Cdebug
Print "Socket established with MQTT broker"
#endif
Exit Do
End If
Loop
#if Cdebug
Print "Connect"
#endif
Result = Tcpwrite(idx , Connect) 'connect to the broker
Do
Tempw = Socketstat(idx , Sel_recv) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw) 'read
If S = &H220 Then
#if Cdebug
Print "Connect ACK"
#endif
Exit Do
End If
End If
Loop
#if Cdebug
Print "Publish"
#endif
Result = Tcpwrite(idx , Publish) 'publish the message
Wait 4
'For X = 1 To 10
' Result = Tcpwrite(idx , Pingreq) 'ping - keep alive
' Wait 10
'Next X
'Wait 4
#if Cdebug
Print "Disconnect"
#endif
Result = Tcpwrite(idx , Disconnect) 'disconnect
Wait 4
Socketdisconnect Idx 'disconnect socket
End |
If you remove the remarks at the PINGREQ line, you will see PINGREQuest at work. This is a keep-alive message to the MQTT-broker server.
And here a picture of a Android smartphone with a MQTT client and some messages that are published.
To do some tests you could install an Open Source MQTT v3.1/v3.1.1 Broker server like Mosquitto.
Have fun
Ben Zijlstra
Last edited by bzijlstra on Sat Jun 04, 2016 2:51 pm; edited 1 time in total |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Tue May 31, 2016 7:29 pm Post subject: |
|
|
wonderful Ben !
It is great you pointed this MQTT out to me. This is the way to go for IoT. The protocol is versatile and complete. It is also proven and ere to stay.
I did read the protocol but i find it simpler to read your bascom code.
Thanks for your work on this. _________________ Mark |
|
Back to top |
|
|
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Sat Jun 04, 2016 2:46 pm Post subject: MQTT - connect / subscribe / publish / ping |
|
|
Next step
Same program but added a subscribe and a keep-alive with pingrequest
If you check the connect string you will find a keep alive value. The client has to pingrequest the MQTT broker before the end of the keep alive time.
In this example the keep alive time in the connect string is 70 seconds, but the keep alives are every 60 seconds.
If you don't send a keep alive in time, the MQTT broker will disconnect the client.
Every time something is received or send, the keep alive timer can be set to 0.
Subscribe is to the topic mcselec
The first message Bascom-MQTT-client online is send by the client (our Arduino Mega 2560 with Ethernet shield)
and the second message has been typed on a SmartPhone with a MQTT client. Publishing Hello Bascom World! to the topic mcselec.
It still is a light client, there is a lot more to configure in the MQTT client.
Updated code!!
Code: | 'Light Bascom MQTT client
'connect / publish / subscribe / pingreq / (disconnect)
'publish and subscribe to Topic mcselec
'Hardware: Arduino Mega 2560 with W5100 Ethernet shield
'Ben Zijlstra - 2016
$regfile = "m2560def.dat" ' specify the used micro
$crystal = 16000000 ' used crystal frequency
$baud = 56700 ' use baud rate
$hwstack = 200
$swstack = 220
$framesize = 250
Config Portb.4 = Output
Wiz5100_cs Alias Portb.4
Wiz5100_cs = 1
Waitms 500
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 0
Spiinit
Config Tcpip = Noint , Mac = 12.128.12.33.46.74 , Ip = 192.168.0.221 , Submask = 255.255.255.0 , Gateway = 192.168.0.1 , _
Localport = 1000 , Tx = $55 , Rx = $55 , Chip = W5100 , Spi = 1 , Cs = Portb.4
Dim Idx As Byte
Dim Bclient As Byte
Dim Result As Word
Dim X As Byte
Dim S As Long
Dim I As Byte
Dim Tempw As Word
Dim Helpw As Word
Dim Status As Long
Dim Teller As Word
Dim Z (200) As Byte
Dim B As Byte
Dim Y As Byte
Dim Messagelen As Byte
Dim Message2 As String * 200
Dim Minteller As Word
Teller = 0
Const Cdebug = 0
Const C2dbug = 1 'for debug purpose
'Connect is {016}(&H10) MQTT Control Packet type
' {025} Length message
' {000} Length protocol name MSB
' {004} Length protocol name LSB
' MQTT Protocol name
' {004} Protocol level
' {002} Connect flags (002 = Clean Session)
' {000} Keep alive MSB
' {070} Keep alive LSB (70 seconds)
' {000}
' {013} Length client-ID
' Bascom-client (Client-ID)
Const Connect = "{016}{025}{000}{004}MQTT{004}{002}{000}{070}{000}{013}Bascom-Client"
'Publish is {048}(&H30) MQTT Control Packet type
' {034} Length message
' {000}
' {007} Length topic
' mcselec Topic
' Bascom-MQTT-client online (message)
Const Publish = "{048}{034}{000}{007}mcselecBascom-MQTT-client online"
'Subscribe is {130}(&H82) MQTT Control Packet type
' {012} Length message
' {000}
' {002}
' {000}
' {007} Length of topic
' mcselec Subscribe to topic mcselec
' {000}
Const Confirm = "{048}{030}{000}{007}mcselecReceived MQTT-message"
Const Subscribe = "{130}{012}{000}{002}{000}{007}mcselec{000}"
Const Pingreq = "{192}{000}" '&HC0 &H00 - ping request - keep alive
Const Disconnect = "{224}{000}" '&HE0 &H00
Print "Programm start"
Print
Idx = 0
Bclient = Getsocket(idx , Sock_stream , 7000 , 0) 'Open socket TCP (sock_stream), local port 7000
Result = Socketconnect(idx , xxx.xxx.xxx.xxx , 1883) 'the IP-address of the MQTT broker and the port
Do
Tempw = Socketstat(idx , 0) 'get status
If Tempw = Sock_established Then
#if C2dbug
Print "Socket established with MQTT broker"
#endif
Exit Do
End If
Loop
#if Cdebug
Print "Connect"
#endif
Result = Tcpwrite(idx , Connect ) 'connect to the broker
Do
Tempw = Socketstat(idx , Sel_recv ) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw ) 'read
Status = S And &H0000FFFF 'two bytes
If Status = &H00000220 Then
#if C2dbug
Print "Connect ACK"
#endif
Exit Do
End If
End If
Loop
#if C2dbug
Print "Subscribe"
#endif
Result = Tcpwrite(idx , Subscribe ) 'subscribe to topic
Do
Tempw = Socketstat(idx , Sel_recv ) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw ) 'read
Status = S And &H00FFFFFF 'three bytes
If Status = &H00000390 Then
#if C2dbug
Print "Subscribe ACK"
#endif
Teller = 0 'reset the keep alive
Exit Do
End If
End If
Loop
Wait 4
#if C2dbug
Print "Publish"
#endif
Result = Tcpwrite(idx , Publish ) 'publish the message
Teller = 0 'reset the keep alive
'is something published in the subscribed topic?
Do
Tempw = Socketstat(idx , Sel_recv ) 'get received bytes
If Tempw = 2 Then '2 bytes, a reaction of a pingrequest
Helpw = Tcpread(idx , B , 2) 'read and ignore them
End If
If Tempw > 2 Then 'if there is something received
#if Cdebug
Print "something arrives"
Print "Tempw = " ; Tempw
#endif
For B = 1 To Tempw
Helpw = Tcpread(idx , Z (b ) , 1)
Next B
#if Cdebug
'Print Hex(z(1)) '&H30 type of MQTT packet
Print "Total length message including Topic " ; Z (2)
'Print Hex(z(3))
Print "Length of Topic " ; Z (4)
#endif
Messagelen = Z (2) - Z (4)
#if Cdebug
Print "Message length " ; Messagelen
#endif
Z (4) = Z (4) + 4
Print
Print "Topic: ";
For Y = 5 To Z (4)
Print Chr(z (y ));
Next Y
Print
Message2 = ""
Z (4) = Z (4) + 1
Print "Message: ";
For Y = Z (4) To Messagelen + 9
Print Chr(z (y ));
Message2 = Message2 + Chr(z (y ))
Next Y
Teller = 0 'reset the keep alive counter
Print
Print
'don't confirm the Bascom-MQTT-client online message
'and don't confirm the confirm message
If Message2 <> "Bascom-MQTT-client online" Then
If Message2 <> "Received MQTT-message" Then
#if C2dbug
Print "Confirm"
#endif
Result = Tcpwrite(idx , Confirm ) 'publish the message
Teller = 0
End If
End If
End If
If Teller > 60 Then 'keep alive is 70 seconds (see connect header), 10 less than keep alive
#if C2dbug
Print "Pingreq"
#endif
Result = Tcpwrite(idx , Pingreq ) 'pingrequest - keep alive
Teller = 0 'start interrupt counter all over again
End If
Minteller = Minteller + 1
If Minteller = 15000 Then
Teller = Teller + 1
Minteller = 0
End If
Loop
'you will never reach these lines at the moment
#if Cdebug
Print "Disconnect"
#endif
Result = Tcpwrite(idx , Disconnect ) 'disconnect
Wait 4
Socketdisconnect Idx 'disconnect socket
End
|
Have fun
Ben Zijlstra |
|
Back to top |
|
|
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Mon Jun 20, 2016 1:45 pm Post subject: Bascom Light MQTT client as TFT-display |
|
|
Made a light Bascom MQTT client as a display. Using a Raspberry as a MQTT broker in my own network.
Two universal routines, Publish(topic,message) and Subscribe(topic).
If you want you can test the MQTT functionality with MQTT.fx - a JAVA MQTT client
Arduino Mega with W5100 ethernetshield and a HX8357C display is used. The TFT-routines are from HKipnik.
The only call to a display is
Code: | Call display_message(msg2) |
Display of text is only handled in that routine so you could use your own display, LCD 16x2, I2C display etc.
Arrays are used to fill Publish and Subscribe, so these routines can be used in other clients.
A keep alive time is 70 seconds. Before the end of the keep alive time a PINGREQuest is send. A PINGRESponse clears the keep alive and ping timers.
Code: | 'Light Bascom MQTT client - TFT with HX8357c
'HX8357C routines from HKipnik
'connect / subscribe / publish / pingreq / (disconnect)
'publish and subscribe to Topic home/lcd
'Hardware: Arduino Mega 2560 with W5100 Ethernet shield
'Connecting to a Raspberry Mosquitto MQTT Broker - 192.168.0.98
'Ben Zijlstra - 2016
$regfile = "m2560def.dat" ' specify the used micro
$crystal = 16000000 ' used crystal frequency
$baud = 56700 ' use baud rate
$hwstack = 200
$swstack = 220
$framesize = 250
Config Portb.4 = Output
Wiz5100_cs Alias Portb.4
Wiz5100_cs = 1
Waitms 500
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 0
Spiinit
Config Tcpip = Noint , Mac = 12.128.12.33.46.74 , Ip = 192.168.0.221 , Submask = 255.255.255.0 , Gateway = 192.168.0.1 , _
Localport = 1000 , Tx = $55 , Rx = $55 , Chip = W5100 , Spi = 1 , Cs = Portb.4
Dim Idx As Byte
Dim Bclient As Byte
Dim Result As Word
Dim S As Long
Dim Tempw As Word
Dim Helpw As Word
Dim Status As Long
Dim Z(255) As Byte
Dim B As Byte
Dim Y As Byte
Dim Messagelen As Byte
Dim Msg2 As String * 200
Dim Emptyline As String * 40
Dim Dsp_txt(11) As String * 40
Dim Line_counter As Byte
'keep alive
Dim Keepalive_counter As Long
Dim Pingresponse_counter As Long
Dim Pub_ar(255) As Byte
Dim Sub_ar(100) As Byte
Dim Msg As String * 150
Dim Topic As String * 100
Keepalive_counter = 0
Pingresponse_counter = 0
Line_counter = 1
Emptyline = Space(40)
Dim Lcd_textt As String * 200
Const Cdebug = 1 'for debug purpose
Const C2dbug = 1
Const Keepalive = 60
Const Keepalive_ticks = Keepalive * 15000 'keep alive * second
Const Keepalive_ticks_pingresponse = Keepalive_ticks + 30000
Const Client_id = "Bascom-Client"
'Connect is {016}(&H10) MQTT Control Packet type
' {025} Length message
' {000} Length protocol name MSB
' {004} Length protocol name LSB
' MQTT Protocol name
' {004} Protocol level
' {002} Connect flags (002 = Clean Session)
' {000} Keep alive MSB
' {070} Keep alive LSB (70 seconds)
' {000}
' {013} Length client-ID
' Bascom-client (Client-ID)
Const Connect = "{016}{025}{000}{004}MQTT{004}{002}{000}{070}{000}{013}Bascom-Client"
Const Confirm = "{048}{031}{000}{008}home/lcdReceived MQTT-message"
Const Pingreq = "{192}{000}" '&HC0 &H00 - ping request - keep alive
Const Disconnect = "{224}{000}" '&HE0 &H00
Declare Sub Display_message(byval Msg2 As String)
Declare Sub Publish(byval Topic As String , Byval Msg As String)
Declare Sub Subscribe(byval Topic As String)
'*******************************************************************************
'Display Mode
'*******************************************************************************
Const Lcd_mode = 4 '1=Portrait 2=Portrait 180° 3=landscape 4=landscape 180°
Const Lcd_driver = 2 '1=HX8357B 2=HX8357C
Const Sd_card = 0
'*******************************************************************************
$include "TFTDriver\HX8357_declarations.inc"
'*******************************************************************************
'Init the Display
'*******************************************************************************
Call Lcd_init()
Call Lcd_clear(black)
'*******************************************************************************
' Display landscape
'*******************************************************************************
Call Lcd_clear(black)
Call Lcd_text( "BASCOM-AVR MQTT-example" , 5 , 1 , 2 , Dodgerblue , Black , 1)
Call Lcd_line(5 , 23 , 475 , 23 , 1 , Yellow)
Call Lcd_text( "home/lcd" , 5 , 30 , 2 , Floralwhite , Black , 1)
Call Lcd_text( " " , 460 , 1 , 2 , Black , Red , 1)
Print "Programm start"
Print
Idx = 0
Bclient = Getsocket(idx , Sock_stream , 7000 , 0) 'Open socket TCP (sock_stream), local port 7000
Result = Socketconnect(idx , 192.168.0.98 , 1883) 'the IP-address of the MQTT broker and the port
Call Lcd_text( " " , 460 , 1 , 2 , Black , Red , 1)
Do
Tempw = Socketstat(idx , 0) 'get status
If Tempw = Sock_established Then
#if C2dbug
Print "Socket established with MQTT broker"
#endif
Call Lcd_text( "Socket established with MQTT broker " , 5 , 300 , 2 , Floralwhite , Black , 1)
Exit Do
End If
Loop
#if Cdebug
Print "Connect"
#endif
Call Lcd_text( "Connect" , 5 , 300 , 2 , Floralwhite , Black , 1)
Result = Tcpwrite(idx , Connect) 'connect to the broker
Do
Tempw = Socketstat(idx , Sel_recv) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw) 'read
Status = S And &H0000FFFF 'two bytes
If Status = &H00000220 Then
#if C2dbug
Print "Connect ACK"
#endif
Call Lcd_text( "Connect ACK " , 5 , 300 , 2 , Floralwhite , Black , 1)
Exit Do
End If
End If
Loop
Call Lcd_text( "Subscribe to home/lcd " , 5 , 300 , 2 , Floralwhite , Black , 1)
Call Subscribe( "home/lcd")
Call Lcd_text( " " , 460 , 1 , 2 , Black , Green , 1)
Wait 4
#if C2dbug
Print "Publish"
#endif
Call Publish( "home/lcd" , "TFT-screen online")
Call Lcd_text( " " , 5 , 300 , 2 , Floralwhite , Black , 1)
'reset the keep alive
'is something published in the subscribed topic?
Do
Tempw = Socketstat(idx , Sel_recv) 'get received bytes
If Tempw = 2 Then '2 bytes, a reaction of a pingrequest
Helpw = Tcpread(idx , S , 2)
Status = S And &H0000FFFF 'two bytes
If Status = &H000000D0 Then
#if Cdebug
Print "Pingresponse received"
#endif
Call Lcd_text( " " , 460 , 1 , 2 , Black , Green , 1)
Pingresponse_counter = 0 'start pingresponse time again
End If
End If
If Tempw > 2 Then 'if there is something received
#if Cdebug
Print "something arrives"
Print "Tempw = " ; Tempw
#endif
For B = 1 To Tempw
Helpw = Tcpread(idx , Z(b) , 1)
Next B
#if Cdebug
'Print Hex(z(1)) '&H30 type of MQTT packet
Print "Total length message including Topic " ; Z(2)
'Print Hex(z(3))
Print "Length of Topic " ; Z(4)
#endif
Messagelen = Z(2) - Z(4)
Decr Messagelen
Decr Messagelen
#if Cdebug
Print "Message length " ; Messagelen
#endif
Z(4) = Z(4) + 4
Print
Print "Topic: ";
For Y = 5 To Z(4)
Print Chr(z(y));
Next Y
Print
Msg2 = ""
Z(4) = Z(4) + 1
Print "Message: ";
For Y = Z(4) To Messagelen + 12
Print Chr(z(y));
Msg2 = Msg2 + Chr(z(y))
Next Y
Print
Print
'don't confirm the Bascom-MQTT-client online message
'and don't confirm the confirm message Wink
If Msg2 <> "Bascom-MQTT-client online" Then
If Msg2 <> "Received MQTT-message" Then
Call Display_message(msg2)
#if C2dbug
Print "Confirm"
#endif
Result = Tcpwrite(idx , Confirm) 'publish the message
Keepalive_counter = 0
Pingresponse_counter = 0
End If
End If
End If
'keep alive pingrequest
If Keepalive_counter > Keepalive_ticks Then 'keep alive is 70 seconds (see connect header)
#if C2dbug
Print "Pingreq"
#endif
Call Lcd_text( " " , 460 , 1 , 2 , Black , Red , 1)
Result = Tcpwrite(idx , Pingreq) 'pingrequest
Keepalive_counter = 0
End If
If Pingresponse_counter > Keepalive_ticks_pingresponse Then
Print "No pingresponses! - Reboot"
Goto 0 'reboot
End If
'Keep alive counter
Incr Keepalive_counter
'pingresponse counter
Incr Pingresponse_counter
Loop
'you will never reach these lines at the moment
#if Cdebug
Print "Disconnect"
#endif
Result = Tcpwrite(idx , Disconnect) 'disconnect
Wait 4
Socketdisconnect Idx 'disconnect socket
End
Sub Publish(byval Topic , Byval Msg)
Local Topic_len As Byte
Local Message_len As Byte
Local Temp As Byte
Local Temp2 As Byte
Local Temps As String * 1
Local Temp3 As Byte
Topic_len = Len(topic)
Message_len = Len(msg)
Temp = Topic_len + Message_len
Temp3 = Temp + 4 'length for tcpwrite
Incr Temp
Incr Temp
'Const Publish = "{048}{028}{000}{008}home/lcdTFT-screen online"
Pub_ar(1) = "{048}"
Pub_ar(2) = Temp
Pub_ar(3) = "{000}"
Pub_ar(4) = Topic_len
'topic
For Temp = 1 To Topic_len
Temp2 = Temp + 4
Temps = Mid(topic , Temp , 1)
Pub_ar(temp2) = Asc(temps)
Next Temp
'message
For Temp = 1 To Message_len
Incr Temp2
Temps = Mid(msg , Temp , 1)
Pub_ar(temp2) = Asc(temps)
Next Temp
#if C2dbug
Print "Publish"
#endif
Result = Tcpwrite(idx , Pub_ar(1) , Temp3) 'publish the message
Keepalive_counter = 0 : Pingresponse_counter = 0 'reset the keep alive
End Sub
Sub Subscribe(byval Topic)
Local Topic_len As Byte
Local Temp As Byte
Local Temp2 As Byte
Local Temps As String * 1
Local Temp3 As Byte
Topic_len = Len(topic)
Temp3 = Topic_len + 7
Temp = Temp3 - 2
'Const Subscribe = "{130}{013}{000}{002}{000}{008}home/lcd{000}"
Sub_ar(1) = "{130}"
Sub_ar(2) = Temp
Sub_ar(3) = "{000}"
Sub_ar(4) = "{002}"
Sub_ar(5) = "{000}"
Sub_ar(6) = Topic_len
'topic
For Temp = 1 To Topic_len
Temp2 = Temp + 6
Temps = Mid(topic , Temp , 1)
Sub_ar(temp2) = Asc(temps)
Next Temp
Print "Temp2 = " ; Temp2
Incr Temp2
Sub_ar(temp2) = "{000}"
#if C2dbug
Print "Subscribe"
#endif
Result = Tcpwrite(idx , Sub_ar(1) , Temp3) 'subscribe to topic
Do
Tempw = Socketstat(idx , Sel_recv) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw) 'read
Status = S And &H00FFFFFF 'three bytes
If Status = &H00000390 Then
#if C2dbug
Print "Subscribe ACK"
#endif
Keepalive_counter = 0
Pingresponse_counter = 0 'reset the keep alive
Exit Do
End If
End If
Loop
End Sub
Sub Display_message(byval Msg2 As String)
Local Verticalpos As Word
Local Dsp_help As Byte
Verticalpos = 60
Lcd_textt = Left(msg2 , 39)
Emptyline = Space(40)
Mid(emptyline , 1) = Lcd_textt
Dsp_txt(line_counter) = Emptyline
Line_counter = Line_counter + 1
If Line_counter = 11 Then
For Dsp_help = 1 To 10
Dsp_txt(dsp_help) = Dsp_txt(dsp_help + 1)
Next Dsp_help
Line_counter = 10
End If
'display all lines
For Dsp_help = 1 To 10
Call Lcd_text(dsp_txt(dsp_help) , 5 , Verticalpos , 2 , Floralwhite , Black , 1) '10 lines x 39 characters
Verticalpos = Verticalpos + 24
Next Dsp_help
End Sub
$include "TFTDriver\HX8357_functions.inc"
$include "Font\Digital20x32.font" '7 segments
$include "Font\font12x16.font"
$include "Font\font25x32.font"
$include "Font\Arial11x14.font"
|
Have fun
Ben Zijlstra |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Mon Jun 20, 2016 10:51 pm Post subject: |
|
|
excellent Ben. I got the thin client going.
Thank you for your research and sharing. This saves me a lot of work. _________________ Mark |
|
Back to top |
|
|
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Wed Jun 22, 2016 5:26 pm Post subject: Some remarks... |
|
|
Got some remarks about the Bascom program
In the program I am using
Code: | 'topic
For Temp = 1 To Topic_len
Temp2 = Temp + 6
Temps = Mid(topic , Temp , 1)
Sub_ar(temp2) = Asc(temps)
Next Temp
|
In this case, I want a single byte of a string, instead of using a MID it is easier to use an ASC(string,index)
Code: | 'topic
For Temp = 1 To Topic_len
Temp2 = Temp + 6
Temp4 = Asc(topic , Temp)
Sub_ar(temp2) = Temp4
Next Temp
|
===
If you go over the MQTT documentation you will find things like Retain and Last Will and Testament
Quote: | A retained message is a normal MQTT message with the retained flag set to true. The broker will store the last retained message and the corresponding QoS for that topic. Each client that subscribes to a topic pattern, which matches the topic of the retained message, will receive the message immediately after subscribing. For each topic only one retained message will be stored by the broker. |
Quote: | The Last Will and Testament (LWT) feature is used in MQTT to notify other clients about an ungracefully disconnected client. Each client can specify its last will message (a normal MQTT message with topic, retained flag, QoS and payload) when connecting to a broker. The broker will store the message until it detects that the client has disconnected ungracefully. If the client disconnect abruptly, the broker sends the message to all subscribed clients on the topic, which was specified in the last will message. The stored LWT message will be discarded if a client disconnects gracefully by sending a DISCONNECT message. |
*From HiveMQ MQTT Essentials
If you would like to check, the const for these commands are
Connect with Last Will and Testament
Code: | Const Connect_lwt = "{016}{045}{000}{004}MQTT{004}{038}{000}{070}{000}{013}Bascom-Client{000}{008}home/lcd{000}{007}Offline{000}"
|
===
Creating a retain message
Code: | Const Retain = "{049}{022}{000}{008}home/lcdBascom Rules" |
===
Deleting a retain message
Code: | Const Delete_retain = "{049}{010}{000}{008}home/lcd" |
===
These examples are Ultra Light MQTT clients
In the specs of MQTT something about topic and message length
Quote: | The length of the actual topic string is at most 65535 bytes. This is a limit imposed by the mqtt spec, you can't change it. It is also worth noting that the topic is encoded with utf-8, so you may have less than 65535 characters available.
The payload of the message is limited to 268,435,456 bytes. Again, this is defined by the spec.
If you are routinely approaching either of these limits you should be thinking about whether what you are doing is sensible. |
On the Internet you can find installation instructions how to turn your Raspberry Pi into a Mosquitto Broker.
Have fun
Ben Zijlstra
Last edited by bzijlstra on Tue Jul 05, 2016 2:09 am; edited 2 times in total |
|
Back to top |
|
|
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Tue Jul 05, 2016 1:27 am Post subject: Some MQTT-routines |
|
|
Made some MQTT-routines
Code: | Declare Sub Mqtt_connect()
Declare Sub Mqtt_connect_lastwill(byval Topic As String , Byval Lwt_msg As String)
Declare Sub Mqtt_disconnect()
Declare Sub Mqtt_publish(byval Topic As String , Byval Msg As String)
Declare Sub Mqtt_publish_retain(byval Topic As String , Byval Retain_msg As String)
Declare Sub Mqtt_publish_delete_retain(byval Topic As String)
Declare Sub Mqtt_subscribe(byval Topic As String)
Declare Sub Mqtt_unsubscribe(byval Topic As String) |
MQTT-Connect command with keep alive time and client-id
The MQTT connection itself is always between one client and the broker, no client is connected to another client directly. The connection is initiated through a client sending a CONNECT message to the broker.
Code: | Call Mqtt_connect() |
Code: |
Sub Mqtt_connect
Local Client_id_len As Byte
Client_id_len = Len(client_id)
Local Temp As Byte
Local Keepalivew As Word
Keepalivew = Keepalive
Local Ar_counter As Byte
Temp = 12 + Client_id_len '12 fixed connect bytes + len client_id
Pubsub_ar(1) = "{016}" 'MQTT connect
Pubsub_ar(2) = Temp 'Length message
Pubsub_ar(3) = "{000}" 'Length protocol name MSB
Pubsub_ar(4) = "{004}" 'Length protocol name LSB
Pubsub_ar(5) = Asc( "M") 'protocol name MQTT
Pubsub_ar(6) = Asc( "Q")
Pubsub_ar(7) = Asc( "T")
Pubsub_ar(8) = Asc( "T")
Pubsub_ar(9) = "{004}" 'protocol-level
Pubsub_ar(10) = "{002}" 'connect flags Clean Session
Pubsub_ar(11) = High(keepalivew) 'keep alive MSB
Pubsub_ar(12) = Low(keepalivew) 'keep alive LSB
Pubsub_ar(13) = "{000}"
Pubsub_ar(14) = Client_id_len 'client_id_length
Ar_counter = 15
For Temp = 1 To Client_id_len
Pubsub_ar(ar_counter) = Asc(client_id , Temp)
Incr Ar_counter
Next Temp
Result = Tcpwrite(idx , Pubsub_ar(1) , Ar_counter) 'connect to the broker
Do
Tempw = Socketstat(idx , Sel_recv) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw) 'read
Status = S And &H0000FFFF 'two bytes
If Status = &H00000220 Then
#if C2dbug
Print "Connect ACK"
#endif
Exit Do
End If
End If
Loop
End Sub |
MQTT-Connect command with Last Will and Testament (LWT), keep alive time and client-id
The Last Will and Testament (LWT) feature is used in MQTT to notify other clients about an ungracefully disconnected client. Each client can specify its last will message (a normal MQTT message with topic, retained flag, QoS and payload) when connecting to a broker. The broker will store the message until it detects that the client has disconnected ungracefully. If the client disconnect abruptly, the broker sends the message to all subscribed clients on the topic, which was specified in the last will message. The stored LWT message will be discarded if a client disconnects gracefully by sending a DISCONNECT message.
Example of a Last Will and Testament message. If you disconnect the power of the MQTT-client, the MQTT-broker will not receive PINGREQuest, and after 1.5 times the keep alive time, the broker will disconnect the client and send the Last Will and Testament message to the clients that have subscribed to the topics of this client.
Code: | Call Mqtt_connect_lastwill( "home/lcd/log" , "TFT-screen Offline") 'send a empty lwt-message to delete lwt message |
Code: | Sub Mqtt_connect_lastwill(byval Topic , Byval Lwt_msg)
Local Client_id_len As Byte
Client_id_len = Len(client_id)
Local Temp As Byte
Local Keepalivew As Word
Keepalivew = Keepalive
Local Ar_counter As Byte
Local Topic_len As Word
Topic_len = Len(topic)
Local Lwt_msg_len As Word
Lwt_msg_len = Len(lwt_msg)
Temp = 17 + Client_id_len '17 fixed connect bytes + len client_id
Temp = Temp + Topic_len '+ topic
Temp = Temp + Lwt_msg_len '+ lwt_msg
Pubsub_ar(1) = "{016}" 'MQTT connect
Pubsub_ar(2) = Temp 'Length message
Pubsub_ar(3) = "{000}" 'Length protocol name MSB
Pubsub_ar(4) = "{004}" 'Length protocol name LSB
Pubsub_ar(5) = Asc( "M") 'protocol name MQTT
Pubsub_ar(6) = Asc( "Q")
Pubsub_ar(7) = Asc( "T")
Pubsub_ar(8) = Asc( "T")
Pubsub_ar(9) = "{004}" 'protocol-level
Pubsub_ar(10) = "{038}" 'connect flags Clean Session
Pubsub_ar(11) = High(keepalivew) 'keep alive MSB
Pubsub_ar(12) = Low(keepalivew) 'keep alive LSB
Pubsub_ar(13) = "{000}"
Pubsub_ar(14) = Client_id_len 'client_id_length
Ar_counter = 15
For Temp = 1 To Client_id_len
Pubsub_ar(ar_counter) = Asc(client_id , Temp)
Incr Ar_counter
Next Temp
Pubsub_ar(ar_counter) = High(topic_len)
Incr Ar_counter
Pubsub_ar(ar_counter) = Low(topic_len)
Incr Ar_counter
For Temp = 1 To Topic_len
Pubsub_ar(ar_counter) = Asc(topic , Temp)
Incr Ar_counter
Next Temp
Pubsub_ar(ar_counter) = High(lwt_msg_len)
Incr Ar_counter
Pubsub_ar(ar_counter) = Low(lwt_msg_len)
Incr Ar_counter
For Temp = 1 To Lwt_msg_len
Pubsub_ar(ar_counter) = Asc(lwt_msg , Temp)
Incr Ar_counter
Next Temp
Pubsub_ar(ar_counter) = "{000}"
Result = Tcpwrite(idx , Pubsub_ar(1) , Ar_counter) 'connect to the broker
Do
Tempw = Socketstat(idx , Sel_recv) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw) 'read
Status = S And &H0000FFFF 'two bytes
If Status = &H00000220 Then
#if C2dbug
Print "Connect ACK"
#endif
Exit Do
End If
End If
Loop
End Sub |
MQTT-Disconnect command
Code: | Call Mqtt_disconnect() 'disconnect socket |
Code: | Sub Mqtt_disconnect()
#if Cdebug
Print "Disconnect"
#endif
Result = Tcpwrite(idx , Disconnect) 'disconnect
Wait 4
Socketdisconnect Idx
End Sub |
MQTT-Publish
Code: | Call Mqtt_publish( "home/lcd/log" , "TFT-screen Online") |
After a MQTT client is connected to a broker, it can publish messages. MQTT has a topic-based filtering of the messages on the broker, so each message must contain a topic, which will be used by the broker to forward the message to interested clients. Each message typically has a payload which contains the actual data to transmit in byte format.
Code: | Sub Mqtt_publish(byval Topic , Byval Msg)
Local Topic_len As Byte
Local Message_len As Byte
Local Temp As Byte
Local Temp2 As Byte
Local Temp3 As Byte
Local Temp4 As Byte
Topic_len = Len(topic)
Message_len = Len(msg)
Temp = Topic_len + Message_len
If Temp > 249 Then
Temp = 249
End If
Temp3 = Temp + 4 'length for tcpwrite
Incr Temp
Incr Temp
Startmsgcounter = 3
'calculate remaining length bytes
If Temp > 127 Then
Pubsub_ar(2) = Temp - 128
Pubsub_ar(3) = "{001}"
Incr Startmsgcounter
Else
Pubsub_ar(2) = Temp
End If
Pubsub_ar(1) = "{048}"
Pubsub_ar(startmsgcounter) = "{000}"
Incr Startmsgcounter
Pubsub_ar(startmsgcounter) = Topic_len
'topic
For Temp = 1 To Topic_len
Temp2 = Temp + Startmsgcounter
Pubsub_ar(temp2) = Asc(topic , Temp)
Next Temp
'message
For Temp = 1 To Message_len
Incr Temp2
Pubsub_ar(temp2) = Asc(msg , Temp)
Next Temp
#if C2dbug
Print "Publish"
#endif
Result = Tcpwrite(idx , Pubsub_ar(1) , Temp3) 'publish the message
End Sub |
MQTT-Publish with retain
A retained message is a normal MQTT message with the retained flag set to true. The broker will store the last retained message and the corresponding QoS for that topic Each client that subscribes to a topic pattern, which matches the topic of the retained message, will receive the message immediately after subscribing. For each topic only one retained message will be stored by the broker.
Everytime a new client does a subscribe to a certain topic, the client can have it receive a retained message. The retained message is stored on the broker. This can be the last good know temperature etc.
Code: | Call Mqtt_publish_retain( "home/lcd" , "Bascom rules") |
Code: | Sub Mqtt_publish_retain(byval Topic , Byval Retain_msg)
Local Topic_len As Byte
Topic_len = Len(topic)
Local Retain_msg_len As Byte
Retain_msg_len = Len(retain_msg)
Local Startmsgcounter As Byte
Local Temp As Byte
Local Temp2 As Byte
Local Temp3 As Byte
Temp = Topic_len
Temp = Temp + Retain_msg_len
Temp = Temp + 2
Temp3 = Temp + 2 'length total packet
Startmsgcounter = 3
'calculate remaining length bytes
If Temp > 127 Then
Pubsub_ar(2) = Temp - 128
Pubsub_ar(3) = "{001}"
Incr Startmsgcounter
Else
Pubsub_ar(2) = Temp
End If
Pubsub_ar(1) = "{049}" 'MQTT packet
Pubsub_ar(startmsgcounter) = "{000}"
Incr Startmsgcounter
Pubsub_ar(startmsgcounter) = Topic_len
'topic
For Temp = 1 To Topic_len
Temp2 = Temp + Startmsgcounter
Pubsub_ar(temp2) = Asc(topic , Temp)
Next Temp
'retain message
For Temp = 1 To Retain_msg_len
Incr Temp2
Pubsub_ar(temp2) = Asc(retain_msg , Temp)
Next Temp
Incr Temp2
Incr Temp3
#if C2dbug
Print "Publish retain message"
#endif
Pubsub_ar(temp2) = "{000}"
Result = Tcpwrite(idx , Pubsub_ar(1) , Temp3) 'publish the message
End Sub |
Delete retain message
Code: | Mqtt_publish_delete_retain( "home/lcd") |
Code: | Sub Mqtt_publish_delete_retain(byval Topic)
Local Topic_len As Byte
Topic_len = Len(topic)
Local Startmsgcounter As Byte
Local Temp As Byte
Local Temp2 As Byte
Local Temp3 As Byte
Temp = Topic_len
Temp = Temp + 2
Temp3 = Temp + 2 'length total packet
Startmsgcounter = 3
'calculate remaining length bytes
If Temp > 127 Then
Pubsub_ar(2) = Temp - 128
Pubsub_ar(3) = "{001}"
Incr Startmsgcounter
Else
Pubsub_ar(2) = Temp
End If
Pubsub_ar(1) = "{049}" 'MQTT packet
Pubsub_ar(startmsgcounter) = "{000}"
Incr Startmsgcounter
Pubsub_ar(startmsgcounter) = Topic_len
'topic
For Temp = 1 To Topic_len
Temp2 = Temp + Startmsgcounter
Pubsub_ar(temp2) = Asc(topic , Temp)
Next Temp
Incr Temp2
Incr Temp3
#if C2dbug
Print "Publish delete retain message"
#endif
Pubsub_ar(temp2) = "{000}"
Result = Tcpwrite(idx , Pubsub_ar(1) , Temp3) 'publish the message
End Sub |
MQTT-Subscribe
A client needs to send a SUBSCRIBE message to the MQTT broker in order to receive relevant messages
Code: | Call Mqtt_subscribe( "home/lcd/log") |
Code: | Sub Mqtt_subscribe(byval Topic)
Local Topic_len As Byte
Local Temp As Byte
Local Temp2 As Byte
Local Temp3 As Byte
Local Temp4 As Byte
Topic_len = Len(topic)
Temp3 = Topic_len + 7
Temp = Temp3 - 2
'Const Subscribe = "{130}{013}{000}{002}{000}{008}home/lcd{000}"
Startmsgcounter = 3
If Temp > 127 Then
Pubsub_ar(2) = Temp - 128
Pubsub_ar(3) = "{001}"
Incr Startmsgcounter
Else
Pubsub_ar(2) = Temp
End If
Pubsub_ar(1) = "{130}"
Pubsub_ar(startmsgcounter) = "{000}"
Incr Startmsgcounter
Pubsub_ar(startmsgcounter) = "{005}"
Incr Startmsgcounter
Pubsub_ar(startmsgcounter) = "{000}"
Incr Startmsgcounter
Pubsub_ar(startmsgcounter) = Topic_len
'topic
For Temp = 1 To Topic_len
Temp2 = Temp + Startmsgcounter
Pubsub_ar(temp2) = Asc(topic , Temp)
Next Temp
Incr Temp2
Pubsub_ar(temp2) = "{000}" 'finishing byte of the subscribe string
#if C2dbug
Print "Subscribe"
#endif
Result = Tcpwrite(idx , Pubsub_ar(1) , Temp3) 'subscribe to topic
Do
Tempw = Socketstat(idx , Sel_recv) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw) 'read
Status = S And &H00FFFFFF 'three bytes
If Status = &H00000390 Then
#if C2dbug
Print "Subscribe ACK"
#endif
Keepalive_counter = 0
Pingresponse_counter = 0 'reset the keep alive
Exit Do
End If
End If
Loop
End Sub |
MQTT-Unsubscribe
The counterpart of the SUBSCRIBE message is the UNSUBSCRIBE message which deletes existing subscriptions of a client on the broker.
Code: | Call Mqtt_unsubscribe( "home/lcd/log") |
Code: | Sub Mqtt_unsubscribe(byval Topic)
Local Topic_len As Byte
Topic_len = Len(topic)
Local Temp As Byte
Local Temp2 As Byte
Temp2 = Topic_len + 6
Pubsub_ar(1) = "{162}"
Pubsub_ar(2) = Temp2 'mits onder de 128 karakters....
Pubsub_ar(3) = "{000}"
Pubsub_ar(4) = "{005}"
Pubsub_ar(5) = "{000}"
Pubsub_ar(6) = Topic_len
Startmsgcounter = 6
For Temp = 1 To Topic_len
Incr Startmsgcounter
Pubsub_ar(startmsgcounter) = Asc(topic , Temp)
Next Temp
Result = Tcpwrite(idx , Pubsub_ar(1) , Temp2)
Do
Tempw = Socketstat(idx , Sel_recv) 'get received bytes
If Tempw > 0 Then 'if there is something received
Helpw = Tcpread(idx , S , Tempw) 'read
Print Helpw
Print S
Print Hex(s)
Status = S And &H00FFFFFF 'three bytes
If Status = &HB0020005 Then
#if C2dbug
Print "unsubscribe ACK"
#endif
Keepalive_counter = 0
Pingresponse_counter = 0 'reset the keep alive
Exit Do
End If
End If
Loop
End Sub |
Will put the main MQTT program online later on. Here some pictures of the TFT-screen home/lcd
It is all experimental. QoS 0. Max length topic/message 255 bytes. But client can handle megabytes of MQTT-info.
Have fun
Ben Zijlstra |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Tue Jul 05, 2016 9:12 am Post subject: |
|
|
thank you for this update Ben. MQTT is really a great standard for handling automation messages.
your code works well on my mqtt broker too. _________________ Mark |
|
Back to top |
|
|
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Wed Jul 06, 2016 12:16 am Post subject: MQTT Led on/off example |
|
|
A small example of MQTT - Putting the D13 testled on the Arduino Mega on and off with MQTT
You have to put the two include files in the attached ZIP file in a MQTT directory below your working directory.
(Or in the source remove the mqtt\ before the include...)
Code: | 'Light Bascom MQTT client - Led on/off example
'connect / subscribe / publish / pingreq / (disconnect)
'publish to home/hobbycorner/arduino1/log
'subscribe to home/hobbycorner/arduino1/ledD13
'Hardware: Arduino Mega 2560 with W5100 Ethernet shield
'Connecting to a Raspberry Mosquitto MQTT Broker - 192.168.0.98
'Ben Zijlstra - 2016
'Monkey proof. Accepts huge amount of bytes but stores only 511 bytes
'mqtt_client_ID = Bascom<MAC-address>
$regfile = "m2560def.dat" ' specify the used micro
$crystal = 16000000 ' used crystal frequency
$baud = 115200 ' use baud rate
$hwstack = 300
$swstack = 300
$framesize = 300
Config Portb.4 = Output
Wiz5100_cs Alias Portb.4
Wiz5100_cs = 1
Waitms 500
Config Portb.7 = Output
Ledd13 Alias Portb.7
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 0
Spiinit
Config Tcpip = Noint , Mac = 12.128.12.33.46.84 , Ip = 192.168.0.222 , Submask = 255.255.255.0 , Gateway = 192.168.0.1 , _
Localport = 7000 , Tx = $55 , Rx = $55 , Chip = W5100 , Spi = 1 , Cs = Portb.4
Config Submode = New
'debug-options
Const Cdebug = 1 'for debug purpose
Const C2dbug = 1 'if you are using debug, the main loop will take more time
$include "mqtt\mqtt_functions.inc"
$include "Mqtt\Mqtt_declares.inc"
'declares for add-on routine
Dim Templed As Byte
'constants 'and perhaps you get problems with your keep-alives
Const Mqtt_keepalive = 60
Const Mqtt_keepalive_ticks = Mqtt_keepalive * 14000 'depends on the length of the main loop - keep alive * second
Const Mqtt_ka_ticks_pr = Mqtt_keepalive_ticks + 30000
Mqtt_client_id = "Bascom1212812334684" 'same as MAC address
#if C2dbug
Print "Programm start"
Print
#endif
Mqtt_idx = 0
Do
Mqtt_bclient = Getsocket(mqtt_idx , Sock_stream , 0 , 0) 'Open socket TCP (sock_stream), local port 7000
Mqtt_result = Socketconnect(mqtt_idx , 192.168.0.98 , 1883) 'the IP-address of the MQTT broker and the port
Mqtt_tempw = Socketstat(mqtt_idx , 0) 'get status
If Mqtt_tempw = Sock_established Then
#if C2dbug
Print "Socket established with MQTT broker"
#endif
Exit Do
End If
Loop
#if Cdebug
Print "Connect"
#endif
'Call Mqtt_connect()
'Wait 2
Call Mqtt_connect_lastwill( "home/hobbycorner/arduino1/log" , "arduino1 Offline") 'send a empty lwt-message to delete lwt message
Wait 2
Call Mqtt_subscribe( "home/hobbycorner/arduino1/ledD13")
Wait 2
Wait 2
'Call Mqtt_publish_retain( "home/lcd" , "Bascom rules")
'wait 2
'Call Mqtt_publish_delete_retain( "home/lcd")
'Wait 2
'Call Mqtt_subscribe( "home/lcd/log")
'Wait 2
'Call Mqtt_publish( "home/lcd/log" , "status")
'Wait 2
'Call Mqtt_unsubscribe( "home/lcd/log")
'Wait 2
'Call Mqtt_unsubscribe( "home/lcd")
#if Cdebug
Print
Print "Check your Arduino Mega D13"
Print "testled for location - blinking"
#endif
For Templed = 1 To 20 'to check the D13 test led on the Arduino Mega.
Toggle Ledd13
Waitms 500
Next Templed
Print
Print "You can now publish LED_ON or LED_OFF"
Print "to home/hobbycorner/arduino1/ledD13"
Print
Print "Publish LED-status to "
Print "home/hobbycorner/arduino1/log"
Print
Wait 4
Call Mqtt_publish( "home/hobbycorner/arduino1/log" , "led D13 OFF after blinktest")
'is something published in the subscribed topic?
Do
Mqtt_tempw = Socketstat(mqtt_idx , Sel_recv) 'get received bytes
If Mqtt_tempw = 2 Then '2 bytes, a reaction of a pingrequest
Mqtt_helpw = Tcpread(mqtt_idx , Mqtt_s , 2)
Mqtt_status = Mqtt_s And &H0000FFFF 'two bytes
If Mqtt_status = &H000000D0 Then
#if Cdebug
Print "Pingresponse received"
#endif
Mqtt_pingresponse_counter = 0 'start pingresponse time again
End If
End If
If Mqtt_tempw > 2 Then 'if there is something received
#if Cdebug
Print "something arrives"
Print
'Print "Tempw = " ; Tempw
#endif
'here we read all bytes but we only store 511 bytes in array mqtt_ar()
For Mqtt_b = 1 To Mqtt_tempw
Mqtt_bb = Mqtt_b
If Mqtt_bb > 511 Then Mqtt_bb = 511
Mqtt_helpw = Tcpread(mqtt_idx , Mqtt_ar(mqtt_bb) , 1)
Next Mqtt_b
'you can expect here in mqtt_ar(1) a 48 or 49
If Mqtt_ar(1) = 48 Or Mqtt_ar(1) = 49 Then
'length of topic/message combination will be in mqtt_ar(2)
'here we check how many bytes are used for Remaining Length..
'if topic/message < 128 bytes, the length of topic is in mqtt_ar(4)
'if topic/message larger you get extra remaining length bytes, up to 4 bytes
Mqtt_startmsgcounter = 4 'length of topic in mqtt_ar(4)
If Mqtt_ar(2) > 127 Then 'MSB-bit, so a second byte is used for the length
Incr Mqtt_startmsgcounter
End If
If Mqtt_ar(3) > 127 Then 'MSB-bit, so a third byte is used for the length
Incr Mqtt_startmsgcounter
End If
If Mqtt_ar(4) > 127 Then 'MSB-bit, so a fourth byte is used for the length
Incr Mqtt_startmsgcounter
End If
Mqtt_pakketlength = Mqtt_bb - 4
#if Cdebug
Print "Total length message including Topic " ; Mqtt_pakketlength
Print "Length of Topic " ; Mqtt_ar(mqtt_startmsgcounter)
#endif
Mqtt_pakkethlp = Mqtt_startmsgcounter + 1
Mqtt_pakkethlp2 = Mqtt_startmsgcounter + Mqtt_ar(mqtt_startmsgcounter)
Mqtt_topic = ""
For Mqtt_pakkethelp = Mqtt_pakkethlp To Mqtt_pakkethlp2
Mqtt_topic = Mqtt_topic + Chr(mqtt_ar(mqtt_pakkethelp))
Next Mqtt_pakkethelp
Print
Print "Topic: " ; Mqtt_topic
Mqtt_msg2 = ""
For Mqtt_pakkethlp = Mqtt_pakkethelp To Mqtt_pakketlength + 4
Mqtt_msg2 = Mqtt_msg2 + Chr(mqtt_ar(mqtt_pakkethlp))
Next Mqtt_pakkethlp
Print
Print "Message: " ; Mqtt_msg2
Print
'here you put the routine that will act on incoming (topic/)message
'in this case a cool MQTT D13-Led on/off
'****************************************************************
If Mqtt_msg2 = "LED_ON" Then
Set Ledd13
End If
If Mqtt_msg2 = "LED_OFF" Then
Reset Ledd13
End If
'****************************************************************
End If
End If
'keep alive pingrequest
If Mqtt_keepalive_counter > Mqtt_keepalive_ticks Then 'keep alive is 70 seconds (see connect header)
'#if C2dbug
Print "Pingreq"
'#endif
Mqtt_result = Tcpwrite(mqtt_idx , Mqtt_pingreq) 'pingrequest
Mqtt_keepalive_counter = 0
End If
If Mqtt_pingresponse_counter > Mqtt_ka_ticks_pr Then 'keepalive ticks pingresponse
Print "No pingresponses! - Reboot"
Goto 0 'reboot
End If
'Keep alive counter
Incr Mqtt_keepalive_counter
'pingresponse counter
Incr Mqtt_pingresponse_counter
Loop
'you will never reach these lines at the moment
Call Mqtt_disconnect()
'disconnect socket
End
|
With a publish to home/hobbycorner/arduino1/ledD13 of the message LED_ON or LED_OFF put a led on or off.
This client is subscribed to home/hobbycorner/arduino1/ledD13 and checks what messages are send.
You can see I have waited a few minutes, so you can see the PINGREQuests at work.
To help you locate the D13 testled on the Arduino Mega, this is put in the home/hobbycorner/arduino1/log
Because we have also a subscribe to home/hobbycorner/arduino1/ledD13 on the Arduino MQTT Dashboard, we can see what has been sent to the Bascom-MQTT client.
At the connect we made a Last Will and Testament message when the client goes offline without a mqtt_disconnect.
I am happy
Ben Zijlstra
BTW, this is a small trick to get the complete MQTT message read, but only store the first 511 bytes in an array... The Wiznet W5100 ethernetcontroller readbuffer pointer will stay at the right location, reading 10 bytes or reading 10.000 bytes
Code: | 'here we read all bytes but we only store 511 bytes in array mqtt_ar()
For Mqtt_b = 1 To Mqtt_tempw
Mqtt_bb = Mqtt_b
If Mqtt_bb > 511 Then Mqtt_bb = 511
Mqtt_helpw = Tcpread(mqtt_idx , Mqtt_ar(mqtt_bb) , 1)
Next Mqtt_b |
Last edited by bzijlstra on Sat Jul 16, 2016 11:46 pm; edited 4 times in total |
|
Back to top |
|
|
albertsm
Joined: 09 Apr 2004 Posts: 5913 Location: Holland
|
Posted: Wed Jul 06, 2016 8:06 pm Post subject: |
|
|
thanks Ben for this sample ,code , info and screens. I did not used the last will yet but it is useful indeed. _________________ Mark |
|
Back to top |
|
|
Evert :-)
Joined: 18 Feb 2005 Posts: 2156
|
|
Back to top |
|
|
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Thu Jul 07, 2016 1:33 pm Post subject: Thanks!! |
|
|
Evert. Thanks for the compliments.
Have fun
Ben Zijlstra |
|
Back to top |
|
|
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Tue Aug 02, 2016 6:04 pm Post subject: MQTT-SMS |
|
|
Here the code to send a SMS-message from your MQTT network
Used a M590 GPRS module connected through a level converter to COM2 of an Arduino Mega
The Arduino Mega is acting as a MQTT-client waiting for a message in home/gateway/sms/outgoing
And leaving a succesfull or non-successfull message in home/gateway/sms/log
The M590 module from Chinese Electronics (CE)
The Arduino Mega, a power supply, levelconverter for serial and the M590 module
Later on I will make a case for it. Why the power supply? In the datasheet of the M590, the module can have peaks of 2 Amps. That will be to much for the Arduino Mega with an USB power supply.
A nice case:
Code: |
'Light Bascom MQTT client - MQTT-SMS gateway
'connect / subscribe / publish / pingreq / (disconnect)
'subscribe to home/gateway/sms/outgoing
'publish to home/gateway/sms/log
'Hardware: Arduino Mega 2560 with W5100 Ethernet shield
'M590 GPRS module
'Connecting to a Raspberry Mosquitto MQTT Broker - 192.168.0.98
'Ben Zijlstra - 2016
'Monkey proof.
'mqtt_client_ID = Bascom<MAC-address>
'Publish a message to topic: home/gateway/sms/outgoing and it will be send
'format message: [<number phone>]message
'succesfull or not succesfull as a message in the topic: home/gateway/sms/log
$regfile = "m2560def.dat" ' specify the used micro
$crystal = 16000000 ' used crystal frequency
$baud = 115200 ' use baud rate
$hwstack = 300
$swstack = 300
$framesize = 300
Config Portb.4 = Output
Wiz5100_cs Alias Portb.4
Wiz5100_cs = 1
Waitms 500
'serial connection to the nodemcu
Config Com1 = 115200 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'serial connection to a debug PC
Config Com2 = 115200 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
'create a buffered serial connection to the M590 module
Config Serialin1 = Buffered , Size = 254
'Open both com-ports
Open "com1:" For Binary As #1
Open "com2:" For Binary As #2
Config Portb.7 = Output
Ledd13 Alias Portb.7
Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 0
Spiinit
Config Tcpip = Noint , Mac = 222.237.186.254.254.237 , Ip = 192.168.0.223 , Submask = 255.255.255.0 , Gateway = 192.168.0.1 , _
Localport = 7000 , Tx = $55 , Rx = $55 , Chip = W5100 , Spi = 1 , Cs = Portb.4
Config Submode = New
'debug-options
Const Cdebug = 1 'for debug purpose
Const C2dbug = 1 'if you are using debug, the main loop will take more time
$include "mqtt\mqtt_functions.inc" 'see previous items in this forum
$include "Mqtt\Mqtt_declares.inc" 'see previous items in this forum
'declares for add-on routine
Dim Templed As Byte
Dim Buffer As String * 80
Dim A As Byte
Dim C As Byte
Dim Count As Byte
Dim Sms(2) As String * 100
Dim Status As String * 7
Dim Error_counter As Byte
Dim Timeout As Word
Enable Interrupts
'constants 'and perhaps you get problems with your keep-alives
Const Mqtt_keepalive = 60
Const Mqtt_keepalive_ticks = Mqtt_keepalive * 14000 'depends on the length of the main loop - keep alive * second
Const Mqtt_ka_ticks_pr = Mqtt_keepalive_ticks + 30000
Mqtt_client_id = "Bascomdeedbafefeed" 'same as MAC address
Sub Wait_for_ok_error()
Buffer = ""
Timeout = 0
Do
Incr Timeout
A = Inkey(#2)
If A > 0 Then
Print #1 , Chr(a);
Buffer = Buffer + Chr(a)
C = Instr(buffer , "OK" )
If C > 0 Then
Print #1 , ""
Status = "OK"
Exit Do
End If
C = Instr(buffer , "ERROR" )
If C > 0 Then
Print #1 , ""
Status = "ERROR"
Exit Do
End If
End If
Loop Until Timeout = 25000
If Timeout = 25000 Then
Status = "ERROR"
Wait 4
End If
If Status = "ERROR" Then
Print #1 , "Error count " ; Error_counter
Goto Process
End If
End Sub
#if C2dbug
Print "Programm start"
Print
#endif
Mqtt_idx = 0
Do
Mqtt_bclient = Getsocket(mqtt_idx , Sock_stream , 0 , 0) 'Open socket TCP (sock_stream)
Mqtt_result = Socketconnect(mqtt_idx , 192.168.0.98 , 1883) 'the IP-address of the MQTT broker and the port 1883
Mqtt_tempw = Socketstat(mqtt_idx , 0) 'get status
If Mqtt_tempw = Sock_established Then
#if C2dbug
Print "Socket established with MQTT broker"
#endif
Exit Do
End If
Loop
#if Cdebug
Print "Connect"
#endif
Call Mqtt_connect()
Wait 2
Call Mqtt_subscribe( "home/gateway/sms/outgoing")
Wait 4
Call Mqtt_publish( "home/gateway/sms/log" , "Device MQTT-SMS Online")
'is something published in the subscribed topic?
Do
Mqtt_tempw = Socketstat(mqtt_idx , Sel_recv) 'get received bytes
If Mqtt_tempw = 2 Then '2 bytes, a reaction of a pingrequest
Mqtt_helpw = Tcpread(mqtt_idx , Mqtt_s , 2)
Mqtt_status = Mqtt_s And &H0000FFFF 'two bytes
If Mqtt_status = &H000000D0 Then
#if Cdebug
Print "Pingresponse received"
#endif
Mqtt_pingresponse_counter = 0 'start pingresponse time again
End If
End If
If Mqtt_tempw > 2 Then 'if there is something received
#if Cdebug
Print "something arrives"
Print
'Print "Tempw = " ; Tempw
#endif
'here we read all bytes but we only store 511 bytes in array mqtt_ar()
For Mqtt_b = 1 To Mqtt_tempw
Mqtt_bb = Mqtt_b
If Mqtt_bb > 511 Then Mqtt_bb = 511
Mqtt_helpw = Tcpread(mqtt_idx , Mqtt_ar(mqtt_bb) , 1)
Next Mqtt_b
'you can expect here in mqtt_ar(1) a 48 or 49
If Mqtt_ar(1) = 48 Or Mqtt_ar(1) = 49 Then
'length of topic/message combination will be in mqtt_ar(2)
'here we check how many bytes are used for Remaining Length..
'if topic/message < 128 bytes, the length of topic is in mqtt_ar(4)
'if topic/message larger you get extra remaining length bytes, up to 4 bytes
Mqtt_startmsgcounter = 4 'length of topic in mqtt_ar(4)
If Mqtt_ar(2) > 127 Then 'MSB-bit, so a second byte is used for the length
Incr Mqtt_startmsgcounter
End If
If Mqtt_ar(3) > 127 Then 'MSB-bit, so a third byte is used for the length
Incr Mqtt_startmsgcounter
End If
If Mqtt_ar(4) > 127 Then 'MSB-bit, so a fourth byte is used for the length
Incr Mqtt_startmsgcounter
End If
Mqtt_pakketlength = Mqtt_bb - 4
#if Cdebug
Print "Total length message including Topic " ; Mqtt_pakketlength
Print "Length of Topic " ; Mqtt_ar(mqtt_startmsgcounter)
#endif
Mqtt_pakkethlp = Mqtt_startmsgcounter + 1
Mqtt_pakkethlp2 = Mqtt_startmsgcounter + Mqtt_ar(mqtt_startmsgcounter)
Mqtt_topic = ""
For Mqtt_pakkethelp = Mqtt_pakkethlp To Mqtt_pakkethlp2
Mqtt_topic = Mqtt_topic + Chr(mqtt_ar(mqtt_pakkethelp))
Next Mqtt_pakkethelp
'Print
'Print "Topic: " ; Mqtt_topic
Mqtt_msg2 = ""
For Mqtt_pakkethlp = Mqtt_pakkethelp To Mqtt_pakketlength + 4
Mqtt_msg2 = Mqtt_msg2 + Chr(mqtt_ar(mqtt_pakkethlp))
Next Mqtt_pakkethlp
'Print
'Print "Message: " ; Mqtt_msg2
'Print
'here you put the routine that will act on incoming (topic/)message
'****************************************************************
'format: [<mobile number>]message to be send
Error_counter = 0
Timeout = 0
Count = Split(mqtt_msg2 , Sms(1) , "]")
Sms(1) = Mid(sms(1) , 2)
Sms(1) = "{034}" + Sms(1)
Sms(1) = Sms(1) + "{034}{013}{010}"
Print #1 , "Phonenumber TO " ; Sms(1)
Print #1 , "Message " ; Sms(2)
Set Ledd13 'active led
Process:
Incr Error_counter
If Error_counter = 10 Then
Buffer = "Error sending SMS to " + Sms(1)
Call Mqtt_publish( "home/gateway/sms/log" , Buffer)
Goto Quit_process
End If
Timeout = 0
Print #2 , "ATZ{013}{010}" 'reset GSM-module
Print #1 , "ATZ{013}{010}"
Call Wait_for_ok_error
Wait 1
Print #2 , "ATE0{013}{010}" 'echo off
Print #1 , "ATE0{013}{010}"
Call Wait_for_ok_error
Wait 1
Print #2 , "AT+CREG=0{013}{010}" 'disconnect from network
Print #1 , "AT+CREG=0{013}{010}"
Call Wait_for_ok_error
Wait 1
Print #2 , "AT+CREG=1{013}{010}" 'connect to network
Print #1 , "AT+CREG=1{013}{010}"
Call Wait_for_ok_error
Wait 1
Print #2 , "AT+CREG?{013}{010}" 'check network connection
Print #1 , "AT+CREG?{013}{010}"
Buffer = ""
Do
Incr Timeout
A = Inkey(#2)
If A > 0 Then
Print #1 , Chr(a);
Buffer = Buffer + Chr(a)
C = Instr(buffer , "+CREG: 1,1" ) 'connected to the network
If C > 0 Then
Print #1 , ""
Status = "OK"
Exit Do
End If
End If
Loop Until Timeout = 25000
If Timeout = 25000 Then Goto Process
Wait 1
Print #2 , "AT+CMGF=1{013}{010}" 'text mode
Print #1 , "AT+CMGF=1{013}{010}"
Call Wait_for_ok_error
Wait 1
Print #2 , "AT+CSCS={034}GSM{034}{013}{010}" 'default alphabet
Print #1 , "AT+CSCS={034}GSM{034}{013}{010}"
Call Wait_for_ok_error
Wait 1
Print #2 , "AT+CMGS=" ; Sms(1) 'SMS message
Wait 1 'first phone number with quotes
Print #1 , "ÄT+CMGS=" ; Sms(1)
Wait 1
Print #2 , Sms(2) 'SMS message
Print #1 , Sms(2)
Wait 1
Print #2 , ""
Print #1 , ""
Wait 1
Print #2 , ""
Print #1 , ""
Wait 1
Print #2 , "mqtt-sms" 'footer
Print #1 , "mqtt-sms"
Wait 1
Print #2 , "{026}" 'end of SMS message
Print #1 , "<Ctrl-Z>"
Call Wait_for_ok_error
Wait 1
Buffer = "SMS sent to " + Sms(1) 'put an entry in the log
Call Mqtt_publish( "home/gateway/sms/log" , Buffer)
Quit_process:
Reset Ledd13 'non active led
'****************************************************************
End If
End If
'keep alive pingrequest
If Mqtt_keepalive_counter > Mqtt_keepalive_ticks Then 'keep alive is 70 seconds (see connect header)
'#if C2dbug
Print "Pingreq"
'#endif
Mqtt_result = Tcpwrite(mqtt_idx , Mqtt_pingreq) 'pingrequest
Mqtt_keepalive_counter = 0
End If
If Mqtt_pingresponse_counter > Mqtt_ka_ticks_pr Then 'keepalive ticks pingresponse
Print "No pingresponses! - Reboot"
Goto 0 'reboot
End If
'Keep alive counter
Incr Mqtt_keepalive_counter
'pingresponse counter
Incr Mqtt_pingresponse_counter
Loop
'you will never reach these lines at the moment
Call Mqtt_disconnect()
'disconnect socket
End
|
Device on line, message in outgoing and SMS sent.
Last edited by bzijlstra on Sun Jan 08, 2017 3:05 pm; edited 1 time in total |
|
Back to top |
|
|
Evert :-)
Joined: 18 Feb 2005 Posts: 2156
|
Posted: Thu Aug 04, 2016 10:23 pm Post subject: |
|
|
Hi Ben,
Thanks for the update.
If you have Mqtt running on you own raspberry then you also must have a look at Node Red
Very interesting to do (a lot) more with the Iot and Mqtt.
You can install and run Node Red on the same raspberry and connect everything with everything with some simple wires.
Have a look at this video for example https://www.youtube.com/watch?v=f5o4tIz2Zzc
Hope that you are now just as enthusiast as me. _________________ www.evertdekker.com Bascom code vault |
|
Back to top |
|
|
bzijlstra
Joined: 30 Dec 2004 Posts: 1179 Location: Tilburg - Netherlands
|
Posted: Fri Aug 05, 2016 12:30 am Post subject: Node Red |
|
|
Thanks for the tip. The YouTube video looks very promising...
Have fun
Ben Zijlstra |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
|