本文记录在 Unity 中通过 MQTT 与真实设备通信 的完整过程。目标是在不涉及游戏开发的前提下,用 Unity 快速实现环境传感器数据的可视化。
适合 会 MQTT / 做嵌入式,但从未使用过 Unity 的工程人员参考。关于Unity的安装,这里不再赘述。
一、工程创建
Unity工程类型选择(3D Core)建立一个基本的工程,我这里工程名字叫做MQTT: 
二、Unity快速上手
工程创建好后,建立一个 Canvas :

如图,Hierarchy 里可以看到 Canvas 和 EventSystem :

在这个Canvas下新建按键( UI-->Button (TextMeshPro)):

如果弹窗提示导入 TMP,点 Import。
切换到 Game 视图,屏幕中间有一个按钮,可以选择按键修改文字

接下来为按键编写对应的脚本代码,在 Project(下面)窗口,展开 Assets,右键空白处选择创建MonoBehaviour Script,命名为TestButton

双击 TestButton.cs,打开内容如下:
using UnityEngine;
public class TestButton : MonoBehaviour
{
void Start()
{
}
void Update()
{
}
}修改为:
using UnityEngine;
public class TestButton : MonoBehaviour
{
public void OnButtonClick()
{
Debug.Log("Button clicked");
}
}保存(Ctrl + S),回到 Unity。接下来把脚本拖到 Button 上,在 Button 的 On Click() 里绑定 OnButtonClick:

点击画面上的 Play ▶ ,用鼠标点按钮,Console 窗口出现了Clicked的日志:

说明 UI → 脚本 → 事件链条已经完全打通,我们已经完成了Unity的快速上手。
三、接入MQTT
3.1 引入MQTT库
这里使用M2MqttUnity这个库。虽然这个库快两年没更新了,但是没有更好的替代品,MQTTnet 对Unity的支持也实在一般。
进入 https://github.com/gpvigano/M2MqttUnity 下载源码,把仓库Assets里的内容粘贴到项目Assets目录下:

为了目录简洁整齐,也可以在Assets 里新建ThirdParty--> M2Mqtt目录,把仓库Assets里的内容粘贴到 M2Mqtt目录下,也OK,如下图

3.2 编写MQTT脚本
新建脚本:Assets/Scripts/M2MqttClient.cs
using UnityEngine;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
using System.Text;
public class M2MqttClient : MonoBehaviour
{
public string broker = "www.duruofu.top";
public int port = 1883;
public string topic = "env_sense/data";
private MqttClient client;
void Start()
{
// 最稳妥的构造方式
client = new MqttClient(broker);
client.MqttMsgPublishReceived += OnMessageReceived;
string clientId = System.Guid.NewGuid().ToString();
client.Connect(clientId);
if (client.IsConnected)
{
Debug.Log("[MQTT] Connected");
client.Subscribe(
new string[] { topic },
new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE }
);
Debug.Log("[MQTT] Subscribed: " + topic);
}
else
{
Debug.LogError("[MQTT] Connect failed");
}
}
void OnMessageReceived(object sender, MqttMsgPublishEventArgs e)
{
string msg = Encoding.UTF8.GetString(e.Message);
Debug.Log("[MQTT RX] " + msg);
HandleMessage(msg);
}
void HandleMessage(string json)
{
SensorData data = JsonUtility.FromJson<SensorData>(json);
Debug.Log(
$"Temp:{data.temperature} " +
$"Humi:{data.humidity} " +
$"Press:{data.pressure} " +
$"Light:{data.light_intensity} " +
$"CO2:{data.co2_concentration}"
);
}
void OnDestroy()
{
if (client != null && client.IsConnected)
{
client.Disconnect();
}
}
}
[System.Serializable]
public class SensorData
{
public float temperature;
public float humidity;
public float pressure;
public float bmp_temperature;
public float light_intensity;
public float co2_concentration;
}这里使用我自己的服务器连接信息:
- Broker:www.duruofu.top
- Port:1883
- Topic:env_sense/data
- Payload:JSON(已解析)
理论上这个脚本运行后会打印:
[MQTT] Connected
[MQTT] Subscribed: env_sense/data
[MQTT RX] {"temperature":26.53,...}
Temp: 26.53 °C | Humi: 21.14 % | Press: 805.16 | ...3.3 挂载并运行脚本
在 Hierarchy 新建一个物体,在 Hierarchy 面板 空白处右键,Create Empty,重命名为MQTTManager,然后把脚本挂上去。

然后点击运行,查看日志:

可以看到已经接收到MQTT的数据了。
四、数据可视化
接下来完成一个简单的UI的数据可视化面板,我们在一开始快速上手部分建立的Canvas 创建一个可视化面板:
Canvas
└── DataPanel
├── TemperatureSlider
├── HumiditySlider
├── PressureSlider
├── LightSlider
└── CO2Slider- 每个 Slider 的 Min / Max 对应该传感器的合理范围,例如:
| 传感器 | Min | Max |
|---|---|---|
| Temperature | 0 ℃ | 50 ℃ |
| Humidity | 0 % | 100 % |
| Pressure | 900 hPa | 1100 hPa |
| Light | 0 Lux | 1000 Lux |
| CO2 | 300 ppm | 2000 ppm |
- 在 Slider 下可以加一个 TextMeshPro 文本显示数值。

在你现有的 M2MqttClient 脚本里添加引用:
using TMPro;
using UnityEngine.UI;
public class M2MqttClient : MonoBehaviour
{
// 数字文本显示
public TMP_Text temperatureText;
public TMP_Text humidityText;
public TMP_Text pressureText;
public TMP_Text lightText;
public TMP_Text co2Text;
// 滑动条显示
public Slider temperatureSlider;
public Slider humiditySlider;
public Slider pressureSlider;
public Slider lightSlider;
public Slider co2Slider;
void HandleMessage(string json)
{
SensorData data = JsonUtility.FromJson<SensorData>(json);
// 更新数字显示
if (temperatureText) temperatureText.text = $"{data.temperature:F1} ℃";
if (humidityText) humidityText.text = $"{data.humidity:F1} %";
if (pressureText) pressureText.text = $"{data.pressure:F1} hPa";
if (lightText) lightText.text = $"{data.light_intensity:F1} Lux";
if (co2Text) co2Text.text = $"{data.co2_concentration:F0} ppm";
// 更新滑动条
if (temperatureSlider) temperatureSlider.value = data.temperature;
if (humiditySlider) humiditySlider.value = data.humidity;
if (pressureSlider) pressureSlider.value = data.pressure;
if (lightSlider) lightSlider.value = data.light_intensity;
if (co2Slider) co2Slider.value = data.co2_concentration;
}
}最终代码为:
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
using System.Text;
[System.Serializable]
public class SensorData
{
public float temperature;
public float humidity;
public float pressure;
public float bmp_temperature;
public float light_intensity;
public float co2_concentration;
}
public class M2MqttClient : MonoBehaviour
{
[Header("MQTT 设置")]
public string broker = "www.duruofu.top";
public int port = 1883;
public string topic = "env_sense/data";
private MqttClient client;
[Header("数字文本显示")]
public TMP_Text temperatureText;
public TMP_Text humidityText;
public TMP_Text pressureText;
public TMP_Text lightText;
public TMP_Text co2Text;
[Header("滑动条显示")]
public Slider temperatureSlider;
public Slider humiditySlider;
public Slider pressureSlider;
public Slider lightSlider;
public Slider co2Slider;
void Start()
{
// 连接 MQTT Broker
client = new MqttClient(broker);
client.MqttMsgPublishReceived += OnMessageReceived;
string clientId = System.Guid.NewGuid().ToString();
client.Connect(clientId);
if (client.IsConnected)
{
Debug.Log("[MQTT] Connected");
client.Subscribe(
new string[] { topic },
new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE }
);
Debug.Log("[MQTT] Subscribed: " + topic);
}
else
{
Debug.LogError("[MQTT] Connect failed");
}
}
void OnMessageReceived(object sender, MqttMsgPublishEventArgs e)
{
string msg = Encoding.UTF8.GetString(e.Message);
Debug.Log("[MQTT RX] " + msg);
HandleMessage(msg);
}
void HandleMessage(string json)
{
SensorData data = JsonUtility.FromJson<SensorData>(json);
// 更新数字显示
if (temperatureText) temperatureText.text = $"{data.temperature:F1} ℃";
if (humidityText) humidityText.text = $"{data.humidity:F1} %";
if (pressureText) pressureText.text = $"{data.pressure:F1} hPa";
if (lightText) lightText.text = $"{data.light_intensity:F1} Lux";
if (co2Text) co2Text.text = $"{data.co2_concentration:F0} ppm";
// 更新滑动条显示
if (temperatureSlider) temperatureSlider.value = data.temperature;
if (humiditySlider) humiditySlider.value = data.humidity;
if (pressureSlider) pressureSlider.value = data.pressure;
if (lightSlider) lightSlider.value = data.light_intensity;
if (co2Slider) co2Slider.value = data.co2_concentration;
}
void OnDestroy()
{
if (client != null && client.IsConnected)
{
client.Disconnect();
Debug.Log("[MQTT] Disconnected");
}
}
}最后,把控件拖到脚本的数据上,运行就可以了:

最终的运行效果是这样的:

这里℃符号显示有点小问题,不过无伤大雅,我们核心的目的是搞定MQTT到UI的通路
至此,我们就完成了MQTT接入到Unity里的基本流程。
五、补充
这里补充一个反向控制的逻辑,我们在面板上增加一个按键,按下后向设备发送信息,主题为 env_sense/control,消息内容随意,就发个 ON/OFF
在 DataPanel 下添加一个 Button,给按钮加上 TextMeshPro - Text 显示文字,例如 “Toggle Device”。如下:

在M2MqttClient 脚本里增加一个控制函数:
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
using System.Text;
public class M2MqttClient : MonoBehaviour
{
[Header("MQTT 设置")]
public string broker = "www.duruofu.top";
public int port = 1883;
public string topic = "env_sense/data";
public string controlTopic = "env_sense/control"; // 新增控制主题
private MqttClient client;
[Header("数字文本显示")]
public TMP_Text temperatureText;
public TMP_Text humidityText;
public TMP_Text pressureText;
public TMP_Text lightText;
public TMP_Text co2Text;
[Header("滑动条显示")]
public Slider temperatureSlider;
public Slider humiditySlider;
public Slider pressureSlider;
public Slider lightSlider;
public Slider co2Slider;
[Header("控制按钮")]
public Button controlButton;
private bool deviceOn = false; // 状态记录,可选
void Start()
{
// 连接 MQTT Broker
client = new MqttClient(broker, port, false, null, null, MqttSslProtocols.None);
client.MqttMsgPublishReceived += OnMessageReceived;
string clientId = System.Guid.NewGuid().ToString();
client.Connect(clientId);
if (client.IsConnected)
{
Debug.Log("[MQTT] Connected");
client.Subscribe(
new string[] { topic },
new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE }
);
Debug.Log("[MQTT] Subscribed: " + topic);
}
else
{
Debug.LogError("[MQTT] Connect failed");
}
// 绑定控制按钮点击事件
if (controlButton != null)
{
controlButton.onClick.AddListener(OnControlButtonClick);
}
}
void OnMessageReceived(object sender, MqttMsgPublishEventArgs e)
{
string msg = Encoding.UTF8.GetString(e.Message);
Debug.Log("[MQTT RX] " + msg);
HandleMessage(msg);
}
void HandleMessage(string json)
{
SensorData data = JsonUtility.FromJson<SensorData>(json);
if (temperatureText) temperatureText.text = $"{data.temperature:F1} ℃";
if (humidityText) humidityText.text = $"{data.humidity:F1} %";
if (pressureText) pressureText.text = $"{data.pressure:F1} hPa";
if (lightText) lightText.text = $"{data.light_intensity:F1} Lux";
if (co2Text) co2Text.text = $"{data.co2_concentration:F0} ppm";
if (temperatureSlider) temperatureSlider.value = data.temperature;
if (humiditySlider) humiditySlider.value = data.humidity;
if (pressureSlider) pressureSlider.value = data.pressure;
if (lightSlider) lightSlider.value = data.light_intensity;
if (co2Slider) co2Slider.value = data.co2_concentration;
}
// 发送控制消息
void OnControlButtonClick()
{
if (client != null && client.IsConnected)
{
deviceOn = !deviceOn; // 切换状态
string msg = deviceOn ? "ON" : "OFF";
client.Publish(controlTopic, Encoding.UTF8.GetBytes(msg), MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, false);
Debug.Log("[MQTT TX] " + msg);
}
else
{
Debug.LogWarning("[MQTT] Not connected, cannot send control message.");
}
}
void OnDestroy()
{
if (client != null && client.IsConnected)
{
client.Disconnect();
Debug.Log("[MQTT] Disconnected");
}
}
}将 Button 拖到脚本的 controlButton 字段上。

运行 Unity 场景。点击按钮即可发送 "ON" 或 "OFF" 消息到 env_sense/control 主题,设备端订阅此主题即可实现反向控制。

