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

I have my simple TIcsMQTTClient-based app working on Windows in a test console application, using the above advice.

Instead of using

FMQTTCli.LinkSocket.MessageLoop

which is blocking, I call the following procedure, which could allow future expansion and better control

procedure RunMessageLoop;
var
  Msg: TMsg;
begin
  while GetMessage(Msg, 0, 0, 0) do
  begin
    TranslateMessage(Msg);
    DispatchMessage(Msg);
  end;
end;

My main problem now is that I need to get this running on both Windows and Linux platforms, and I see that ICS does not (yet?) support Linux. (I thought that FMX meant Linux support, and did not read the fine print!)

Any suggestions?

Share this post


Link to post

No ICS has never been supported on Linux.  In practice, the functions that don't require messages do work now, there is a sample IcsPemTest that runs on Linux,

 

I did spend several weeks working on ICS v10 with a new cross platform message engine, but hit a compiler problem with derived components, and ICS has a lot of those.  So a lot of v10 needs rewriting, not had time.  I may get back to it this winter. 

 

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
×