Filter results by

ARTIK 053 as MQTT Subscriber

The ARTIK 053 module makes great use of MQTT as a lightweight IoT messaging protocol. MQTT follows a publish-subscribe ("pub/sub") model; the ARTIK 053 device acts as a sensor that publishes its findings to the central broker, and also as an actuator that subscribes to messages from the broker and carries out actions.

In this tutorial, we use the ARTIK IDE to set up your ARTIK 053 module as a simple MQTT subscriber. It waits for messages with a topic of 'color' and then turns on the appropriate LED when it sees the right color message.

You will need an MQTT broker and an MQTT publisher to test out the subscriber code we provide here.

  • If you have an ARTIK 5/7/10 module available, follow the introductory MQTT tutorial. For the moment, all you really need to do is connect to Wi-Fi® and then enter
    mosquitto -v &
    which will start the broker and make it ready for an ARTIK 053 connect request.

  • If not, you'll need to set up Mosquitto as an MQTT broker on your PC. You can then install and use MQTT.fx to publish MQTT messages.

There are many other options, so choose the one you are most comfortable with.

Prerequisites

You'll need the following resources, and about a half hour of your time.

  • Any system set up as MQTT broker
  • ARTIK 053 module
  • Wi-Fi® access point

You'll be using the ARTIK IDE to compile the code for ARTIK 053 modules, so you'll probably want to try out an example project before tackling this one.

Set Up Subscriber Edge Device

We will use an ARTIK 053 module as our edge device.

  1. In the ARTIK IDE, open a new ARTIK 053 C Project. Name the project anything you like. Click Next.
  2. Select the Hello World example, which we'll just use as a placeholder for our code. Click Next.
  3. On the next screen, Configuration, where you would normally just hit Next, you need to set "Pre-build configuration" to extra. Doing so brings in the MQTT functions we'll need for this project. Hit Next and Finish


  4. Delete the hello_main.c file; we'll be creating our own.
  5. Start with MQTT subscriber code, which we've provided here.

    main.c code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    #include "wifi.h"
    #include <tinyara/gpio.h>
    #include <apps/netutils/mqtt_api.h>
    #include <apps/netutils/dhcpc.h>
    
    #define DEFAULT_CLIENT_ID "123456789"
    #define SERVER_ADDR "10.0.1.98"
    #define RED "RED"
    #define BLUE "BLUE"
    #define GREEN "GREEN"
    #define RED_LED 45
    #define GREEN_LED 60
    #define BLUE_LED 49
    #define RED_ON_BOARD_LED 45
    #define NET_DEVNAME "wl1"
    
    // mqtt client handle
    mqtt_client_t* pClientHandle = NULL;
    
    // mqtt client parameters
    mqtt_client_config_t clientConfig;
    
    //int blinkerValue = 0;
    int currentLED = 0;
    
    // mqtt client on connect callback
    void onConnect(void* client, int result) {
        printf("mqtt client connected to the server\n");
    }
    
    // mqtt client on disconnect callback
    void onDisconnect(void* client, int result) {
        printf("mqtt client disconnected from the server\n");
    }
    
    // Write the value of given gpio port.
    void gpio_write(int port, int value) {
        char str[4];
        static char devpath[16];
        snprintf(devpath, 16, "/dev/gpio%d", port);
        int fd = open(devpath, O_RDWR);
    
        ioctl(fd, GPIOIOC_SET_DIRECTION, GPIO_DIRECTION_OUT);
        write(fd, str, snprintf(str, 4, "%d", value != 0) + 1);
    
        close(fd);
    }
    
    void ledSignal(void) {
        switch (currentLED) {
        case RED_LED: {
            gpio_write(GREEN_LED,0);
            gpio_write(BLUE_LED, 0);
            gpio_write(RED_LED, 1);
        }
        break;
        case GREEN_LED: {
            gpio_write(BLUE_LED,0);
            gpio_write(RED_LED, 0);
            gpio_write(GREEN_LED, 1);
        }
        break;
        case BLUE_LED: {
            gpio_write(RED_LED,0);
            gpio_write(GREEN_LED, 0);
            gpio_write(BLUE_LED, 1);
        }
        break;
        default: {
            gpio_write(RED_LED, 0);
            gpio_write(BLUE_LED, 0);
            gpio_write(GREEN_LED, 0);
        }
        break;
        }
        return;
    }
    
    // mqtt client on message callback
    void onMessage(void *client, mqtt_msg_t *msg) {
        printf("Received message\n");
        printf("Topic: %s\n", msg->topic);
        printf("Message: %s\n", msg->payload);
    
        // Check if the message received is RED
        int result = strcmp(msg->payload, RED);
        if (result == 0) {
            if (currentLED != RED_LED) {
                currentLED = RED_LED;
                ledSignal();
            }
            printf("Red LED\n");
            return;
        }
    
        // Check if the message received is GREEN
        result = strcmp(msg->payload, GREEN);
        if (result == 0) {
            if (currentLED != GREEN_LED) {
                currentLED = GREEN_LED;
                ledSignal();
            }
            printf("Green LED\n");
            return;
        }
    
        // Check if the message received is BLUE
        result = strcmp(msg->payload, BLUE);
        if (result == 0) {
            if (currentLED != BLUE_LED) {
                currentLED = BLUE_LED;
                ledSignal();
            }
            printf("Blue LED\n");
            return;
        }
    
        currentLED = 0;
        ledSignal();    // Turn off all LEDs
    }
    
    // Utility function to configure mqtt client
    void initializeConfigUtil(void) {
        uint8_t macId[IFHWADDRLEN];
        int result = netlib_getmacaddr("wl1", macId);
        if (result < 0) {
            printf("Get MAC Address failed. Assigning \
                    Client ID as 123456789");
            clientConfig.client_id =
                    DEFAULT_CLIENT_ID; // MAC id Artik 053
        } else {
        printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
                ((uint8_t *) macId)[0],
                ((uint8_t *) macId)[1], ((uint8_t *) macId)[2],
                ((uint8_t *) macId)[3], ((uint8_t *) macId)[4],
                ((uint8_t *) macId)[5]);
        char buf[12];
        sprintf(buf, "%02x%02x%02x%02x%02x%02x",
                ((uint8_t *) macId)[0],
                ((uint8_t *) macId)[1], ((uint8_t *) macId)[2],
                ((uint8_t *) macId)[3], ((uint8_t *) macId)[4],
                ((uint8_t *) macId)[5]);
        clientConfig.client_id = buf; // MAC id Artik 053
        printf("Registering mqtt client with id = %s\n", buf);
        }
        clientConfig.on_connect = (void*) onConnect;
        clientConfig.on_disconnect = (void*) onDisconnect;
        clientConfig.on_message = (void*) onMessage;
    }
    
    int main(int argc, char *argv[]) {
    
        bool wifiConnected = false;
        gpio_write(RED_ON_BOARD_LED, 1); // Turn on on board Red LED to indicate no WiFi connection is established
    
    #ifdef CONFIG_CTRL_IFACE_FIFO
        int ret;
    
        while(!wifiConnected) {
            ret = mkfifo(CONFIG_WPA_CTRL_FIFO_DEV_REQ,
                    CONFIG_WPA_CTRL_FIFO_MK_MODE);
            if (ret != 0 && ret != -EEXIST) {
                printf("mkfifo error for %s: %s",
                        CONFIG_WPA_CTRL_FIFO_DEV_REQ,
                        strerror(errno));
            }
            ret = mkfifo(CONFIG_WPA_CTRL_FIFO_DEV_CFM,
                    CONFIG_WPA_CTRL_FIFO_MK_MODE);
            if (ret != 0 && ret != -EEXIST) {
                printf("mkfifo error for %s: %s",
                        CONFIG_WPA_CTRL_FIFO_DEV_CFM,
                        strerror(errno));
            }
    
            ret = mkfifo(CONFIG_WPA_MONITOR_FIFO_DEV,
                    CONFIG_WPA_CTRL_FIFO_MK_MODE);
            if (ret != 0 && ret != -EEXIST) {
                printf("mkfifo error for %s: %s",
                        CONFIG_WPA_MONITOR_FIFO_DEV,
                        strerror(errno));
            }
        #endif
    
            if (start_wifi_interface() == SLSI_STATUS_ERROR) {
                printf("Connect Wi-Fi failed. Try Again.\n");
            }
            else {
                wifiConnected = true;
                gpio_write(RED_ON_BOARD_LED, 0); // Turn off Red LED to indicate WiFi connection is established
            }
        }
    
        printf("Connect to Wi-Fi success\n");
    
        bool mqttConnected = false;
        bool ipObtained = false;
        printf("Get IP address\n");
    
        struct dhcpc_state state;
        void *dhcp_handle;
    
        while(!ipObtained) {
            dhcp_handle = dhcpc_open(NET_DEVNAME);
            ret = dhcpc_request(dhcp_handle, &state);
            dhcpc_close(dhcp_handle);
    
            if (ret != OK) {
                printf("Failed to get IP address\n");
                printf("Try again\n");
                sleep(1);
            }
            else {
                ipObtained = true;
            }
        }
        netlib_set_ipv4addr(NET_DEVNAME, &state.ipaddr);
        netlib_set_ipv4netmask(NET_DEVNAME, &state.netmask);
        netlib_set_dripv4addr(NET_DEVNAME, &state.default_router);
    
        printf("IP address  %s\n", inet_ntoa(state.ipaddr));
    
        sleep(5);
    
        // Connect to the WiFi network for Internet connectivity
        printf("mqtt client tutorial\n");
    
        // Initialize mqtt client
        initializeConfigUtil();
    
        pClientHandle = mqtt_init_client(&clientConfig);
        if (pClientHandle == NULL) {
            printf("mqtt client handle initialization fail\n");
            return 0;
        }
    
        while (mqttConnected == false ) {
            sleep(2);
            // Connect mqtt client to server
            int result = mqtt_connect(pClientHandle,
                    SERVER_ADDR, 1883, 60);
            if (result < 0) {
                printf("mqtt client connect to server fail\n");
                continue;
            }
            mqttConnected = true;
        }
    
        bool mqttSubscribe = false;
    
        // Subscribe to topic of interest
        while (mqttSubscribe == false ) {
            sleep(2);
            int result = mqtt_subscribe(pClientHandle,
                    "color", 0); //topic - color, QOS - 0
            if (result < 0) {
                printf("mqtt client subscribe to topic \
                        failed\n");
                continue;
            }
            mqttSubscribe = true;
            printf("mqtt client Subscribed to the topic successfully\n");
        }
    
        while(1) {
        }
    }
    To create the file:
    1. Right-click the project name you are working on.
    2. From the pop-up menu, select New >> Source file.
    3. Specify the name of the file as main.c and click Finish.
    4. Copy and paste in the main.c code we've provided.
    5. Enter the correct IP address of your MQTT broker at SERVER_ADDR.
    6. If you are trying this project with your own external LEDs, change the GPIO mappings as needed.
    7. Save the file (Ctrl-S or use pulldown).
  6. You'll also need to add a wifi.h header file with code we provide here.

    wifi.h code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    #include <net/if.h>
    #include <apps/netutils/wifi/slsi_wifi_api.h>
    
    // WIFi
    #define STATE_DISCONNECTED          0
    #define STATE_CONNECTED             1
    
    #define SLSI_WIFI_SECURITY_OPEN     "open"
    #define SLSI_WIFI_SECURITY_WPA2_AES "wpa2_aes"
    
    #define SSID "MyAP"
    #define PSK  "abcd1234"
    
    slsi_security_config_t *getSecurityConfig(char *sec_type,
            char *psk, WiFi_InterFace_ID_t mode);
    
    static int g_connection_state = STATE_DISCONNECTED;
    static uint8_t g_join_result  = 0;
    static sem_t g_sem_join;
    
    /**
     * Handler for network link up connection event
     *
     *   Sets the global connection state variable and the
     *   result of the network join request.
     */
    void networkLinkUpHandler(slsi_reason_t* reason) {
        g_connection_state = STATE_CONNECTED;
    
        g_join_result = reason->reason_code;
        sem_post(&g_sem_join);
    }
    
    /**
     * Handler for network link down connection event
     *
     *   Sets the global connection variable when the access
     *   point is disconnected from the network.
     */
    void networkLinkDownHandler(slsi_reason_t* reason) {
        g_connection_state = STATE_DISCONNECTED;
    
        if (reason) {
            printf("Disconnected from network %s "
                   "reason_code: %d %s\n", reason->bssid,
                    reason->reason_code,
                    reason->locally_generated ?
                            "(locally_generated)": "");
        } else {
            printf("Disconnected from network\n");
        }
    }
    
    /**
     * Starts the Wi-Fi interface and request connection to the
     * specified network
     *
     *   Return: Completed successfully or failed
     *
     *   Starts the Wi-Fi interface in Station mode and requests
     *   to join the specified network.
     */
    int8_t start_wifi_interface(void) {
    
        if ( WiFiRegisterLinkCallback(&networkLinkUpHandler,
                &networkLinkDownHandler) ) {
            return SLSI_STATUS_ERROR;
        }
    
        if ( WiFiStart(SLSI_WIFI_STATION_IF, NULL) ==
                SLSI_STATUS_ERROR ) {
            return SLSI_STATUS_ERROR;
        }
    
        sem_init(&g_sem_join, 0, 0);
    
        slsi_security_config_t *security_config =
                getSecurityConfig(SLSI_WIFI_SECURITY_WPA2_AES,
                    PSK, SLSI_WIFI_STATION_IF);
    
        if ( WiFiNetworkJoin((uint8_t*)SSID, strlen(SSID),
                NULL, security_config) == SLSI_STATUS_ERROR ) {
            return SLSI_STATUS_ERROR;
        }
    
        sem_wait(&g_sem_join);
    
        if( g_join_result ) {
           return SLSI_STATUS_ERROR;
        }
    
        free(security_config);
        sem_destroy(&g_sem_join);
    
        return SLSI_STATUS_SUCCESS;
    }
    To create the header file:
    1. Right-click the project name you are working on.
    2. From the pop-up menu, select New >> Header file.
    3. Specify the name of the file as wifi.h and click Finish.
    4. Delete the default file contents and paste in the wifi.h code.
    5. Change SSID, PSK, and if necessary the security type, to let ARTIK get to your Wi-Fi access point.
    6. Save the file.
  7. Build the code as usual.

You're all ready to go now.

Run Subscriber Code

Flash-load the code to your ARTIK 053 board as always. When it finishes, and any time you apply power from now on (even without a terminal connection), it will be a standalone MQTT subscriber.

If all goes well:
– Red LED 703 on the ARTIK 053 board will turn on while trying to connect to Wi-Fi.
– The LED will go out once the connection is established.
– There will be a delay (up to a minute) while DHCP acquires an IP address.
– You will see new subscriber messages on your MQTT broker – your code works!

You can now proceed to send it a test message using either Node-RED or MQTT.fx.

Troubleshooting Tip. Not working? Remember that all parties must use the same network IP address as the broker.

You must be connected to the same Wi-Fi access point name on
– your PC running showing the Node-RED page in a Web browser
– the ARTIK Linux board, as set up in wpa_supplicant.conf or connman

The ipconfig wlan0 IP address from the ARTIK Linux board must match
SERVER_ADDR "xxx.xxx.xxx.xxx" for each ARTIK 053 module
– the Node-RED page URL in your Web browser – xxx.xxx.xxx.xxx:1880
– the Node-RED MQTT output node server address – xxx.xxx.xxx.xxx:1883

For a Windows MQTT broker, check with ifconfig -all in a command window.

Publish to Subscriber

You're set up to send a color message to your ARTIK 053 board by way of your Mosquitto broker. Use Node-RED if you are using Mosquitto on an ARTIK 5/7/10 board, or install and use MQTT.fx if you are using Mosquitto on a development PC.

Using Node-RED as publisher

Use this approach with your ARTIK 5/7/10 board.

  1. Start Node-RED (node connection development tool) and run it as a background process.
    node-red &

  2. Follow the MQTT Tutorial to send a Topic of color with a payload of RED.

  3. Try again with a color of BLUE.

Using MQTT.fx as publisher

Use this approach with your development PC.

  1. Start MQTT.fx and bring up its configuration page by clicking on the "gear" symbol next to the grayed-out Connect button.

  2. Configure it as shown, replacing the IP address with the localhost address you determined previously.

  3. Set the topic to color and enter a message of RED or BLUE, then click Publish.

Adding GREEN LED

There are on-board RED and BLUE LED circuits, but you'll want to add a green one too.

Follow the Using External LED instructions to build a GREEN LED circuit, and use the header mapping to connect it to XGPIO22 (the GREEN assignment in the code matches, using gpio51 as shown in the mapping).

Now you can publish a value of GREEN to get that external circuit to illuminate the LED. The transistor gives you the current you need to drive LEDs brighter, or to drive relays, solenoids, motors, etc.

Summary

You've built a stand-alone MQTT subscriber, keyed to your own private Wi-Fi access point, that you can use to turn LEDs on and off, or if equipped with a relay, to control lamps and appliances.

In the next article we'll focus on the "publish" side of the ARTIK 053 MQTT equation.

Extra Credit: Remote PWM Control

While we're on the topic of LEDs, let's talk about PWM pins – using them instead of GPIOs would give you the ability to vary the intensity of the LEDs. This exercise is optional for now, but will be referenced in the Web Window to MQTT tutorial, so we encourage you to try it.

Wiring the PWM pins

You can attach external RED, BLUE, and GREEN LED circuits to the PWM 0, 1, and 2 pins (respectively) to drive them. We've just shown the RED circuit for clarity.

Modifying the ARTIK 053 code

You want to be able to send a message that includes intensity information for each LED. We'll use this feature in an advanced MQTT article.

In the main.c code, add the following.

  1. Bring in the PWM headers (adjusting for the path if needed).
    #include <tinyara/pwm.h>
  2. Declare the variables for the PWM handles globally after the existing line:
    int currentLED = 0;
    int fd_red;
    int fd_blue;
    int fd_green;
  3. Open the PWM channels one time only, at the end of initializeConfigUtil.
    clientConfig.on_message = (void*) onMessage;
    fd_red = open("/dev/pwm0", O_RDWR);
    fd_blue = open("/dev/pwm1", O_RDWR);
    fd_green = open("/dev/pwm2", O_RDWR);
  4. Set the PWM channels from the incoming message. Under void onMessage... right before
    currentLED = 0;
    ledSignal();    // Turn off all LEDs

    add this code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // use 6 hex digits rr-gg-bb to set PWM outputs for external LED intensity
    long int i=strtol(msg->payload, NULL, 16); 
    int b = i & 0xFF;
    int g = (i >> 8) & 0xff;
    int r = (i >> 16) & 0xff;
    
    struct pwm_info_s pwm_info;
    
    pwm_info.frequency = 1000;
    
    pwm_info.duty = r * 255;
    ioctl(fd_red, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&pwm_info));
    ioctl(fd_red, PWMIOC_START);
    
    pwm_info.duty = b * 255;
    ioctl(fd_blue, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&pwm_info));
    ioctl(fd_blue, PWMIOC_START);
    
    pwm_info.duty = g * 255;
    ioctl(fd_green, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&pwm_info));
    ioctl(fd_green, PWMIOC_START);
    
    printf("r-g-b %d-%d-%d\n", r, g, b);

Whenever the message is not a recognized payload keyword, this routine will act on it.

Trying it out. When the ARTIK 053 module receives a message other than RED, BLUE, or GREEN, the new code will try to interpret it as a string of six hex digits corresponding to R-G-B, and use the values to modulate the PWM outputs.

To test it with R=FF, G=AA, and B=77, do the following.

  • MQTT.fx: Type in FFAA77 and click Publish.
  • Node-RED: Change your Inject node payload to FFAA77, click Deploy, and click the node to send.

You should see your external LEDs illuminate at the intensities you've sent, and the GPIO-controlled ones will turn off.

Last updated on: