2

I am building an iOS application and I wanted to use MQTT to be able to subscribe/publish messages to an MQTT Server. Upon researching MQTT Libraries, I found this library which seemed to be adequate for my purposes. Kindly note that I already made an MQTT Server online using CloudMQTT. After figuring out how to make CocoaPods work, and how to add dependencies on my Podfile, I finally got it up and running. In the viewDidLoad function of my first view, I attempted to connect to my MQTT Server by adding this line to my .h file:

@interface VBViewController : UIViewController<MQTTSessionDelegate>

and in my .m file, in the viewDidLoad function, I did this:

MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];
transport.host = @"mPortNumber.cloudmqtt.com";
transport.port = portNumber;

session = [[MQTTSession alloc] init];
session.transport = transport;

session.delegate=self;

[session connectAndWaitTimeout:30];

[session subscribeToTopic:@"username/messagesFolder/#" atLevel:2 subscribeHandler:^(NSError *error, NSArray<NSNumber *> *gQoss){
    if (error) {
        NSLog(@"Subscription failed %@", error.localizedDescription);
    } else {
        NSLog(@"Subscription sucessfull! Granted Qos: %@", gQoss);
    }
}];

However, upon running it, neither the Subscription fail/success messages showed up. I thought that I might have used the wrong port number, so I used the all three ports provided, the simple Port, an SSL Port, and a Websockets Port. After none of those worked, I tried to change the folder directory by playing with the slashes but that didn't work either.

I also tried sending and receiving messages but that didn't work out too.

I am using the emulator for the mean time since I haven't renewed my iOS Developer License yet. I don't want to blow all my 10 deployments just to figure this simple thing out. Might that be the cause of the failure to connect to my MQTT Server? I would doubt that because the emulator can connect to the internet and browse using Safari just fine - so it's pretty much connected to the internet.

Am I missing something with how I initialized/imported the MQTT methods?

halfer
  • 19,824
  • 17
  • 99
  • 186
Razgriz
  • 7,179
  • 17
  • 78
  • 150

4 Answers4

1

You won't get any callbacks when using connectAndWaitTimeout.

Try using connectWithConnectHandler(connectHandler: MQTTConnectHandler!) as specified in a comment, you will get:

/**
@return nothing and returns immediately. To check the connect results, register as an MQTTSessionDelegate and
 - watch for events
 - watch for connect or connectionRefused messages
 - watch for error messages
 or use the connectHandler block
*/

Also make sure that you don't need encryption to connect successfully.

tetek
  • 11
  • 2
0

I finally made it work. Kindly use this project as reference. My MQTT broker was provided by CloudMQTT. You can sign up for a server for free with a maximum of 10 device connections. Kindly note that you'll have to create a user to be able to set a "rule" or a "message folder". Also, take note of the following details:

server : mPortNumber.cloudmqtt.com
port   : 1XXXX

As well as the username, password, and the folder you just created.

Now, in your iOS application, you'd need to update the mqtt.plist file:

host : mPortNumber.cloudmqtt.com / m14.cloudmqtt.com (whatever was provided)
port : 1XXXX / 13123 (use the ordinary one and NOT the SSL/Websocket Port)
tls : NO
base : yourFolderName

And then look for this block of code in the viewDidLoad function and update it as such:

NSURL *bundleURL = [[NSBundle mainBundle] bundleURL];
NSURL *mqttPlistUrl = [bundleURL URLByAppendingPathComponent:@"mqtt.plist"];
self.mqttSettings = [NSDictionary dictionaryWithContentsOfURL:mqttPlistUrl];
self.request = self.mqttSettings[@"request"];
self.response = self.mqttSettings[@"response"];

/*
 * MQTTClient: create an instance of MQTTSessionManager once and connect
 * will is set to let the broker indicate to other subscribers if the connection is lost
 */
if (!self.manager) {
    self.manager = [[MQTTSessionManager alloc] init];
    self.manager.delegate = self;
    self.manager.subscriptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:MQTTQosLevelExactlyOnce] forKey:[NSString stringWithFormat:@"%@/#", self.request]];
    [self.manager connectTo:self.mqttSettings[@"host"]
                       port:[self.mqttSettings[@"port"] intValue]
                        tls:[self.mqttSettings[@"tls"] boolValue]
                  keepalive:60
                      clean:true
                       auth:true
                       user:@"username"
                       pass:@"password"
                  willTopic:[NSString stringWithFormat:@"%@/",
                             self.request]
                       will:[@"offline" dataUsingEncoding:NSUTF8StringEncoding]
                    willQos:MQTTQosLevelExactlyOnce
             willRetainFlag:FALSE
               withClientId:nil];
        } else {
    [self.manager connectToLast];
}
/*
 * MQTTCLient: observe the MQTTSessionManager's state to display the connection status
 */
[self.manager addObserver:self
               forKeyPath:@"state"
                  options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                  context:nil];

You'll also need the observeValueForKeyPath function to figure out which state we are in.

Then just copy the message sending and message handling function to be able to publish messages and handle the received messages.

Razgriz
  • 7,179
  • 17
  • 78
  • 150
0

I had the same problem. I solved it by moving the subscribeToTopic call to

- (void)connected:(MQTTSession *)session

method (from MQTTSessionDelegate). It looks like subscription doesn't work when called right after connect call.

algrid
  • 5,600
  • 3
  • 34
  • 37
0

Same problem occurred here, because the session was not ready.

Solution: just implement subscribeToTopic: within the connectWithConnectHandler: block.

MQTTCFSocketTransport *transport = [[MQTTCFSocketTransport alloc] init];
transport.host = @"test.mosquitto.org";
transport.port = 1883;

self.session = [[MQTTSession alloc] init];
self.session.delegate = self;
self.session.transport = transport;

[self.session connectWithConnectHandler:^(NSError *error) {

    if(!error){
        // ########    MQTT subscribe to topic  ###########
        [self.session subscribeToTopic:@"example/#" atLevel:MQTTQosLevelExactlyOnce subscribeHandler:^(NSError *error, NSArray<NSNumber *> *gQoss) {
            if (error) {
                NSLog(@"Subscription failed %@", error.localizedDescription);
            } else {
                NSLog(@"Subscription sucessfull! Granted Qos: %@", gQoss);
            }
        }];
    }
}];
floki1
  • 106
  • 2
  • 5