基于MQTT做了一个小项目,记录一下完成过程,主要实现功能为用户可以在手机端和电脑远端:获取开发板的芯片温度、控制led灯的亮灭以及发光模式、播放想播放的音频。
水平有限,仅做自我学习记录。
一.主要内容
主要是编写一个基于mqtt协议的客户端程序,来实现相应的功能。
①搭建好连接mqtt服务器的环境(服务器用的是然也的公用服务器,网上可以查到)。
②连接好mqtt服务器后,订阅相关主题,比如led主题来接受远端的控制信号,playback主题来接受远端相应播放的音频等等。
③温度发布模块:每个一段时间发布一次开发板芯片的温度信息。
④led控制模块:接受远端数据,然后根据数据来控制led灯的发光模式或亮灭。
⑤音频播放模块:接受远端数据,然后根据数据信息来选择播放的音频文件,并且可以实时打断播放或者切换播放。
⑥这里还想加一个视频监控模块,具体功能实现是接收到消息后自动打开视频监控,并显示在显示设备上。后面摄像头到了再补上。
二.各个模块实现思路
1.搭建好连接服务器的环境
在mqtt协议中,客户端在连接服务器前需要创建一个客户端对象,还要设置好回调函数,这个回调函数很重要,因为在后面的模块中,需要接收别的客户端(手机、电脑等)通过服务器发布的消息,当接收到这些消息后,进程就会调用这个回调函数,我们可以在这个回调函数中设置好我们处理接收到消息后处理数据的方法,以及需要执行的代码。然后我们就可以连接服务器了,当然在这几步中我们还需要配置相关的设置,比如服务器IP地址、心跳间隔时间、cleansession标志、用户名以及密码(社区版)等等。
2.温度发布模块
linux下一切皆文件,只需要打开相应的设备文件即可,在我用的开发板中,芯片温度的文件路径为:/sys/class/thermal/thermal_zone0/temp,所以只要把该文件的打开然后循环的去读,然后再发布到temp主题中。
3.led控制模块
在这个功能模块中,需要接收led主题中的消息,然后根据消息的内容进行相应的操作。所以首先客户端在连接服务器后要订阅led主题,这样才能接受到消息。然后当接收到消息时,会自动调用回调函数,所以我们需要在回调函数中判断接受的消息是否是led主题,如果是,再根据消息内容操作相应的文件,led的设备文件路径为:/sys/class/leds/sys-led/trigger(发光模式)以及/sys/class/leds/sys-led/brightness(亮灭),有些led可以支持亮度大小,但我的只支持亮和灭,如果支持还可以根据数值大小调节亮度。
4.音频播放模块
这个模块的实现相对要难一些,难点在于要保证客户端再播放音频时还是可以接收到服务器的消息的,它不像led模块的操作执行在极短的时间内就能完成,所以需要在这个模块上需要进行多线程或者多进程编程,我一开始是进行的多线程编程,但在调试的时候发现多线程下客户端在播放音频时不能接收到服务器的消息,后面分析原因是因为尽管是多线程,但是在一个进程中只能同时存在一个回调函数在执行,所以当有别的消息从服务器端发过来时,客户端不能再调用回调函数执行相关操作。之后我就改用了多进程编程。
这个模块主要实现思路是:接收到消息后,执行回调函数判断是否为playback主题,如果是则判断音频设备是否正在播放,如果在播放就要结束播放进程,然后另外创建新进程播放新传来的消息对应的音频文件(这样设计是为了实现一个切歌、停止播放的功能)。然后就是一些进程回收上的细节处理。
整体思路框架搭建好之后,剩下的就是怎么播放音频了,其实和之前模块差不多,就是稍微复杂一点。在linux音频方面有一个库alsa-lib,它是一套 Linux 应用层的 C 语言函数库,为音频应用程序开发提供了一套统一、标准的接口,应用程序只需调用这一套 API 即可完成对底层声卡设备的操控。具体步骤是打开pcm设备,设置硬件参数(设置数据格式、采样率、声道数等等),应用配置的参数,然后就可以打开应用的音频文件进行读写操作了。读写音频文件时要注意的是wav格式的文件,先解析文件头是否正确,然后再定位到数据开始的地方进行读写。
三.代码实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sy