> For the complete documentation index, see [llms.txt](https://openwrt-nctu.gitbook.io/project/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://openwrt-nctu.gitbook.io/project/experiment-mqtt/openwrt-mqtt.md).

# MQTT 在 OpenWRT 上的開發

## 撰寫一隻簡單的 MQTT 程式

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

所撰寫的程式主要參考: <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`上的資訊。

{% hint style="info" %}
若是要開發較複雜的程式，可以使用 pthread 將 MQTT 的 subscribe 包起來，確保 main thread 不會被 MQTT 所占滿。
{% endhint %}

## 建立 cross-compile 環境

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

![](/files/-Lp2n6jEVSrUyNKUGMb6)

在進行 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
```

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


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://openwrt-nctu.gitbook.io/project/experiment-mqtt/openwrt-mqtt.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
