Jump to content
Andrew Spencer

Handling events for a dynamically created TIcsMQTTClient

Recommended Posts

I need to use TIcsMQTTClient in a console app (for use in Windows or Linux)

I'm battling with the event handling, which seems not to be passing parameters correctly.

My initialization code is 
 

  dynMQTTClient := TIcsMQTTClient.Create(nil);
  dynMQTTClient.Name := 'dynMQTTClient';

  enableMethod.pMethod := @MQTTClientEnableChange;
  enableMethod.pObject := nil;
  dynMQTTClient.OnEnableChange := TNotifyEvent(enableMethod);

  onlineMethod.pMethod := @MQTTClientOnline;
  onlineMethod.pObject := nil;
  dynMQTTClient.OnOnline := TNotifyEvent(onlineMethod);

  messageMethod.pMethod := @MQTTClientMsg;
  messageMethod.pObject := nil;
  dynMQTTClient.OnMsg := TMQTTMsgEvent(messageMethod);

where each of the xxxxxMethod records is
 

  TMethodPointer = packed record
    pMethod: Pointer;
    pObject: TObject;
  end;

My handlers are then
 

procedure MQTTClientOnline(Sender: TObject);
procedure MQTTClientMsg(Sender: TObject; aTopic: UTF8String;
  const aMessage: AnsiString; aQos: TMQTTQOSType; aRetained: Boolean);
procedure MQTTClientEnableChange(Sender: TObject);

But the parameters, when examined inside the routine, are "wrong". e.g. Sender is nil when these events are launched.

(I have successfully used the above code method with TTimer and TRESTRequest events)

Any ideas/suggestions as to what I might be doing incorrectly?
 

Share this post


Link to post

You are trying to use events in an unusual way, without any classes.  

 

For console applications, it is best to create a class in which you use and create ICS components, just as with a GUI.

 

Look at the sample OverbyteIcsConHttp;.dpr which creates TConApplication = class(TComponent)  with the REST component and it's event.  

 

Angus

 

Share this post


Link to post

Thank you. I have done that, with minor success, using Mosquitto under Docker.

On running my simple console application, the TIcsMQTTClient.OnEnableChange gets launched, when expected.

I'm unable to get any further events triggering in my console application (attached) although a GUI application (based on the ICS example) works fine.

If anyone could try out my source code, and find the problem, it would be very much appreciated!

MQTT_Subscriber_Console.zip

Share this post


Link to post
29 minutes ago, Andrew Spencer said:

If anyone could try out my source code, and find the problem

I looked at your source. I don't see any message loop. That is REQUIRED for ICS component to work. In a GUI application you have one automatically but in a console application you must create one. As Angus said, look at the sample  OverbyteIcsConHttp.dprwhich has a message loop. No message loop, no async event...

Share this post


Link to post

As François says, you missed the MessageLoop line in OverbyteIcsConHttp. 

 

It is commented out because the REST request is synchronous, which means it uses a message loop internally to wait for a response, 

 

Angus

 

Share this post


Link to post

Thanks, both of you. I think that I'm getting the idea of the differences between GUI and console.

I've added 

FMQTTCli.LinkSocket.MessageLoop;

To get through the async events, with a 

FMQTTCli.LinkSocket.PostQuitMessage;

to terminate the handling (in the OnOnline event).

Since I'm aiming to write an application with API handling and writing MQTT subscriptions into a database, I can see that threads are likely going to be needed sooner rather than later!

Share this post


Link to post

BTW, please make sure you are using the latest MQTT component from the overnight zip or SVN, there were major improvements a few months ago that are not yet released, but will be in a day or two.  

 

Angus

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×