MQTT 在 OpenWRT 上的開發

建立 cross-compile 環境,撰寫一隻簡單的 MQTT 程式發表/訂閱資訊

撰寫一隻簡單的 MQTT 程式

在 OpenWRT 上進行開發之前,我們可以先寫一隻簡單的程式,來測試 MQTT 的功能,考慮到對 OpenWRT 的支援,我們使用 mosquitto API 來進行開發。

所撰寫的程式主要參考: https://mosquitto.org/man/libmosquitto-3.html。不過,在原本程式中 publish 的功能,我們做了一些修改,把 subscribe 的目標指到 info,並新增一個 publish 指到 report。考慮到原有的程式架構會不斷在迴圈中等候 subscribe 的資訊,我們先在 subscribe 之前進行一次 publish,程式如下:

#include <stdio.h>
#include <mosquitto.h>

void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
	if(message->payloadlen){
		printf("%s %s\n", message->topic, message->payload);
	}else{
		printf("%s (null)\n", message->topic);
	}

	fflush(stdout);
}

void my_connect_callback(struct mosquitto *mosq, void *userdata, int result)
{
	int i;
	if(!result){
		/* Subscribe to broker information topics on successful connect. */
		mosquitto_subscribe(mosq, NULL, "info/#", 2);
	}else{
		fprintf(stderr, "Connect failed\n");
	}
}

void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos)
{
	int i;

	printf("Subscribed (mid: %d): %d", mid, granted_qos[0]);
	for(i=1; i<qos_count; i++){
		printf(", %d", granted_qos[i]);
	}
	printf("\n");
}


int main(int argc, char *argv[])
{
	int i;
	char *host = "localhost";
	int port = 1883;
	int keepalive = 60;
	bool clean_session = true;
	struct mosquitto *mosq = NULL;

	mosquitto_lib_init();
	mosq = mosquitto_new(NULL, clean_session, NULL);
	if(!mosq){
		fprintf(stderr, "Error: Out of memory.\n");
		return 1;
	}

	mosquitto_connect_callback_set(mosq, my_connect_callback);
	mosquitto_message_callback_set(mosq, my_message_callback);
	mosquitto_subscribe_callback_set(mosq, my_subscribe_callback);

	if(mosquitto_connect(mosq, host, port, keepalive)){
		fprintf(stderr, "Unable to connect.\n");
		return 1;
	}

	mosquitto_publish(mosq, NULL, "report", sizeof("hello"), "hello", 2, false);
	mosquitto_loop_forever(mosq, -1, 1);

	mosquitto_destroy(mosq);
	mosquitto_lib_cleanup();
	return 0;
}

接著,我們進行程式的編譯,這裡要記得指定所使用的 library,才不會出現函式缺少的狀況。

$gcc main.c -lmosquitto -o mqtt_test
$./mqtt_test

執行後,實測可以 publish 訊息至 broker 上的report,並持續更新info上的資訊。

若是要開發較複雜的程式,可以使用 pthread 將 MQTT 的 subscribe 包起來,確保 main thread 不會被 MQTT 所占滿。

建立 cross-compile 環境

為了要建立在 OpenWRT 上的 MQTT 開發環境,我們首先要建立一個含有 mosquitto library 的 cross compiler。相同的,我們先到menuconfig中,將 libmosquitto-nossl 勾選,如下圖所示:

在進行 make 之後,我們可以在build_dir資料夾下,找到 libmosquitto-nossl 的資料夾,如下所示:

ofwrt@ofwrt-18:~/openwrt/build_dir/target-mips_24kc_musl$ ls
busybox-1.28.3                  mosquitto-nossl
c-ares-1.14.0                   ncurses-6.1
[...]

為了方便程式的開發,我們把相關的 header 檔移到程式所在的位置,如下指令所示:

cp -R ~/openwrt/build_dir/target-mips_24kc_musl/mosquitto-nossl/mosquitto-1.5.1/lib/*.h  ~/mqtt/include

另外,make 產生的.so檔則在staging_dir/target-mips_24kc_musl/usr/lib資料夾中,我們把相關的檔案也移到資料夾下:

ofwrt@ofwrt-18:~/openwrt/staging_dir/target-mips_24kc_musl/usr/lib$ cp libmosquitto* ~/mqtt/lib/

接著,進行程式的編譯:

mips-openwrt-linux-gcc main_ofwrt.c -I ~/mqtt/include/ -L ~/mqtt/lib/ -lmosquitto -o mqtt_ofwrt

考慮到 mosquitto 已有對 OpenWRT 的支援,在/usr/lib底下已有 mosquitto 的 linker 檔,因此,不需要額外把 linker 檔加入 OpenWRT 的環境中,就可直接執行程式,如下所示:

root@GL-AR750S:/usr/lib# ls libmosquitto*
libmosquitto.so    libmosquitto.so.1

因此,編譯完後的檔案,只需要把權限設定正確,就可以在 OpenWRT 的 WiFi AP 上執行。

Last updated