;tiny example MQTT Client
XIncludeFile "MQTT_Client.pbi"
EnableExplicit
CompilerIf #PB_Compiler_Version >= 620
UseNetworkTLS()
CompilerEndIf
Enumeration #PB_Event_FirstCustomValue
#MQTT_EventIncoming
EndEnumeration
Runtime Enumeration Gadgets
#frame_settings
#text_broker_url
#string_broker_url
#text_broker_port
#string_broker_port
#checkbox_TLS
#text_username
#string_username
#text_password
#string_password
#button_connect
#frame_subscriptions
#editor_subscriptions
#frame_publish
#text_publish
#string_topic
#text_publish_content
#string_publish_content
#button_publish
#frame_log
#editor_log
EndEnumeration
Enumeration
#Dialog_Main
EndEnumeration
;not really needed, but the reply from a broker to a subscription request doesn't contain the topic we tried to subscribe to.
;therefore it might make sense to store our topics we requested
;in this case I only used it to create log messages, like "successfully subscribed to Topic"
Structure _MySubscriptions_
PacketIdentifier.u
List Topics.MQTT_Common::Filter() ;<- needed to store the topics we subscribed to
EndStructure
Global ClientID.i
Global ClientConf.MQTT_CLIENT::CLIENT_INIT
Global NewList MySubscriptions._MySubscriptions_()
Procedure.s GetXMLString()
Protected XML$
XML$ + "<?xml version='1.0' encoding='UTF-16'?>"
XML$ + ""
XML$ + "<dialogs><!--Created by Dialog Design0R V1.87 => get it from: https://hex0rs.coderbu.de/en/sdm_downloads/dialogdesign0r/-->"
XML$ + " <window flags='#PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget' text='MQTT tinyClient' minwidth='450' minheight='450' name='window_main' xpos='834' ypos='342'>"
XML$ + " <vbox expand='item:4'>"
XML$ + " <frame text='Connection Setup' id='#frame_settings'>"
XML$ + " <hbox>"
XML$ + " <gridbox columns='2' colexpand='item:2'>"
XML$ + " <text text='Broker URL/IP:' id='#text_broker_url'/>"
XML$ + " <string width='120' text='127.0.0.1' id='#string_broker_url'/>"
XML$ + " <text text='Broker port:' id='#text_broker_port'/>"
XML$ + " <string flags='#PB_String_Numeric' text='1883' id='#string_broker_port'/>"
XML$ + " <checkbox text='Use TLS' colspan='2' id='#checkbox_TLS' onevent='OnClick_UseTLS()'/>"
XML$ + " </gridbox>"
XML$ + " <gridbox columns='2' colexpand='item:2'>"
XML$ + " <text text='[Username]:' id='#text_username'/>"
XML$ + " <string width='100' id='#string_username'/>"
XML$ + " <text text='[Password]:' id='#text_password'/>"
XML$ + " <string flags='#PB_String_Password' id='#string_password'/>"
XML$ + " <button text='Connect' flags='#PB_Button_Default' id='#button_connect' onevent='OnClick_Connect()'/>"
XML$ + " </gridbox>"
XML$ + " </hbox>"
XML$ + " </frame>"
XML$ + " <frame text='Subscriptions (each line a topic to subscribe):' id='#frame_subscriptions'>"
XML$ + " <editor height='80' id='#editor_subscriptions'/>"
XML$ + " </frame>"
XML$ + " <frame text='Publish:' id='#frame_publish'>"
XML$ + " <hbox>"
XML$ + " <gridbox columns='2' colexpand='item:2'>"
XML$ + " <text text='to Topic:' id='#text_publish'/>"
XML$ + " <string width='100' id='#string_topic'/>"
XML$ + " </gridbox>"
XML$ + " <gridbox columns='3' colexpand='item:2'>"
XML$ + " <text text='Content:' id='#text_publish_content'/>"
XML$ + " <string width='100' id='#string_publish_content'/>"
XML$ + " <button text='Publish' id='#button_publish' onevent='OnClick_Publish()'/>"
XML$ + " </gridbox>"
XML$ + " </hbox>"
XML$ + " </frame>"
XML$ + " <frame text='Log:' id='#frame_log'>"
XML$ + " <editor flags='#PB_Editor_ReadOnly' height='100' id='#editor_log'/>"
XML$ + " </frame>"
XML$ + " </vbox>"
XML$ + " </window>"
XML$ + "</dialogs><!--DDesign0R Definition: PureBasic|1|1|1|___|example_with_declares|1-->"
XML$ + ""
ProcedureReturn XML$
EndProcedure
Procedure LogIT(Text.s)
If Text
Text = FormatDate("%hh:%ii:%ss", Date()) + " " + Text
EndIf
AddGadgetItem(#editor_log, - 1, Text)
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
Select GadgetType(#editor_log)
Case #PB_GadgetType_ListView
SendMessage_(GadgetID(#editor_log), #LB_SETTOPINDEX, CountGadgetItems(#editor_log) - 1, #Null)
Case #PB_GadgetType_ListIcon
SendMessage_(GadgetID(#editor_log), #LVM_ENSUREVISIBLE, CountGadgetItems(#editor_log) - 1, #False)
Case #PB_GadgetType_Editor
SendMessage_(GadgetID(#editor_log), #EM_SCROLLCARET, #SB_BOTTOM, 0)
EndSelect
CompilerCase #PB_OS_Linux
Protected *Adjustment.GtkAdjustment
*Adjustment = gtk_scrolled_window_get_vadjustment_(gtk_widget_get_parent_(GadgetID(#editor_log)))
*Adjustment\value = *Adjustment\upper
gtk_adjustment_value_changed_(*Adjustment)
CompilerEndSelect
EndProcedure
Runtime Procedure OnClick_UseTLS()
If GetGadgetState(#checkbox_TLS)
SetGadgetText(#string_broker_port, "8883")
Else
SetGadgetText(#string_broker_port, "1883")
EndIf
EndProcedure
Runtime Procedure OnClick_Connect()
If ClientID
MQTT_CLIENT::DeInitClient(ClientID)
ClientID = #Null
SetGadgetText(#button_connect, "Connect")
ProcedureReturn
EndIf
;Config Client
ClientConf\BrokerURL = GetGadgetText(#string_broker_url)
ClientConf\Port = Val(GetGadgetText(#string_broker_port))
ClientConf\Username = GetGadgetText(#string_username)
ClientConf\Password = GetGadgetText(#string_password)
ClientConf\ClientIdentifier = "PBClient_{" + RSet(Str(Random(999999, 101)), 6, "0") + "}"
ClientConf\Window = DialogWindow(#Dialog_Main)
ClientConf\WindowEvent = #MQTT_EventIncoming
ClientConf\Will\Topic = "Booom/We/are/Dead"
ClientConf\Will\Message = "disconnected!"
CompilerIf #PB_Compiler_Version
If GetGadgetState(#checkbox_TLS)
ClientConf\ExtraConnectFlags = #PB_Network_TLSv1_2
Else
ClientConf\ExtraConnectFlags = 0
EndIf
CompilerEndIf
ClientID = MQTT_CLIENT::InitClient(@ClientConf, #True)
If ClientID
SetGadgetText(#button_connect, "Disconnect")
EndIf
ProcedureReturn ClientID
EndProcedure
Runtime Procedure OnClick_Publish()
Protected Topic$, Content$
Topic$ = GetGadgetText(#string_topic)
Content$ = GetGadgetText(#string_publish_content)
If Topic$ And Content$ And ClientID
MQTT_CLIENT::PublishTopic(ClientID, Topic$, @Content$, StringByteLength(Content$))
EndIf
EndProcedure
Procedure MQTT_EventIncoming()
Protected *Values.MQTT_Common::MQTT_EVENTDATA, a$
Protected *Buffer, i, no, Type, Payload.s, Topic.s, PacketIdentifier.i, ErrorText.s, Error
Protected QoS, DUP, Retain
*Values = EventData()
If *Values
a$ = PeekS(*Values + OffsetOf(MQTT_Common::MQTT_EVENTDATA\D), - 1, #PB_UTF8)
Topic = StringField(a$, 1, #ESC$)
ErrorText = ReplaceString(StringField(a$, 2, #ESC$), "{CLIENT}", "BROKER")
Type = *Values\Type
PacketIdentifier = *Values\PacketIdentifier
Error = *Values\Error
QoS = *Values\QoS
DUP = *Values\DUP
Retain = *Values\Retain
If *Values\PayLoad
Payload = PeekS(*Values\PayLoad, *Values\PayLoadLength, #PB_UTF8 | #PB_ByteLength)
FreeMemory(*Values\PayLoad)
EndIf
FreeMemory(*Values)
;handle it...
Select Type
Case MQTT_Common::#MQTTEvent_SuccessfullyConnected
LogIT("connection o.k.!")
;subscribe now to topics which have been set before
If ListSize(MySubscriptions()) > 0
ForEach MySubscriptions()
ClearList(MySubscriptions()\Topics())
Next
ClearList(MySubscriptions())
EndIf
AddElement(MySubscriptions())
For i = 0 To CountGadgetItems(#editor_subscriptions) - 1
AddElement(MySubscriptions()\Topics())
MySubscriptions()\Topics()\Topic = GetGadgetItemText(#editor_subscriptions, i)
MySubscriptions()\Topics()\QoS = 0
Next i
MySubscriptions()\PacketIdentifier = MQTT_CLIENT::SubscribeToTopics(ClientID, MySubscriptions()\Topics())
Case MQTT_Common::#MQTTEvent_SubscriptionSuccessfull
ForEach MySubscriptions()
If MySubscriptions()\PacketIdentifier = PacketIdentifier
i = 1
ForEach MySubscriptions()\Topics()
If Val(StringField(Payload, i, ",")) <> $80
LogIT("Subscribed successfully to '" + MySubscriptions()\Topics()\Topic + "'")
Else
LogIT("Unable to subscribe to '" + MySubscriptions()\Topics()\Topic + "'!")
EndIf
i + 1
Next
ClearList(MySubscriptions()\Topics())
DeleteElement(MySubscriptions())
EndIf
Next
Case MQTT_Common::#MQTTEvent_PublishIncoming
LogIT("Published Topic: '" + Topic + "'->" + Payload + " (Q=" + Str(Qos) + ", D=" + Str(DUP) + ", R=" + Str(Retain) + ", M=" + Str(PacketIdentifier) + ")")
Case MQTT_Common::#MQTTEvent_PublishingSuccessfull
LogIT("Published successfully to topic '" + Topic + "'!")
Case MQTT_Common::#MQTTEvent_Error
LogIT(ErrorText)
ClientID = #Null
SetGadgetText(#button_connect, "Connect")
EndSelect
EndIf
EndProcedure
Procedure main()
Protected a$
a$ = GetXMLString()
ParseXML(0, a$)
CreateDialog(0)
OpenXMLDialog(0, 0, "window_main")
BindEvent(#MQTT_EventIncoming, @MQTT_EventIncoming(), DialogWindow(#Dialog_Main))
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
MQTT_CLIENT::DeInitClient(ClientID)
EndProcedure
main()