一、項目功能介紹
當前基于MQTT協議設計了一個實時圖傳系統,通過這個項目來演示,兩個MQTT設備如何互相訂閱,進行消息流轉。 在阿里云服務器上創建2個設備,分為為設備A和設備B;設備A負責采集本地攝像頭畫面上傳,設備B負責接收設備A上傳的數據然后解析顯示出來。在阿里云服務器上需要配置云產品流轉,讓設備A的數據上傳后自動發送給設備B。這樣就完成了視頻畫面數據的流轉。不過因為阿里云的最大數據限制,每次最大發送10240字節的數據。
當前的項目是采用MQTT協議實現,那么先來了解一下什么是MQTT協議。
軟件采用Qt設計,QT版本是5.12.6
設備A的功能:獲取攝像頭的數據---》縮放成240*320---》編碼成JPEG格式---》轉碼成base64---》組合成MQTT報文---》上傳到服務器。
設備B的功能:訂閱設備A上傳的數據,得到數據后解析出源格式數據---》將圖像畫面渲染顯示出來。
軟件運行效果:
總結軟件運行的體驗效果:
(1) 非常流暢。兩個窗口肉眼感覺不到延遲。
(2)服務器不要錢。
這個方案驗證之后,可以衍生出很多實際的例子了: 比如, 單片機+攝像頭+MQTT協議 也可以做為圖傳發送端。 聯網可以使用:WIFI或者4G模塊、5G模塊。
1.1 MQTT協議
MQTT (Message Queuing Telemetry Transport)是一種輕量級的、基于發布/訂閱的消息傳輸協議,它可以在客戶端和服務器之間進行雙向通信。MQTT被設計為適用于低帶寬、不穩定網絡連接的物聯網設備通信。
MQTT具有以下主要特點:
(1)發布/訂閱模型:客戶端可以選擇訂閱一個或多個主題(topic),并接收與這些主題相關的消息;同時,客戶端也可以發布消息到一個或多個主題上。
(2)輕量級:MQTT的協議頭非常小,最小只有2字節,這使得它非常適合于傳輸數據量較小的IoT設備。
(3)QoS(服務質量)支持:MQTT支持三種不同的QoS級別,分別是“至多一次”、“至少一次”和“恰好一次”,可以根據應用場景的需要進行選擇。
(4)保留消息:MQTT服務器可以將最新的消息保留在主題中,并讓新的訂閱者能夠讀取先前發布的消息。
(5)遺囑消息:當客戶端與服務器連接異常斷開時,服務器可以向其他訂閱了該主題的客戶端發送遺囑消息,以實現更可靠的消息傳輸。
總之,MQTT是一種非常適合物聯網設備通信的協議,它具有輕量級、靈活性高、易于實現、可靠性強等優點,已經被廣泛地應用于各種物聯網場景中。
1.2 MQTT協議載體
MQTT協議是基于TCP協議傳輸報文的。MQTT使用TCP/IP協議棧來實現通信,因此它具有TCP協議的一些特性,如可靠性、流控制和建立持久連接等特點。
在MQTT連接建立時,客戶端需要通過TCP連接到MQTT服務器,并進行握手協商,包括協議版本、客戶端標識符、遺囑消息、QoS級別等信息,以確保雙方能夠正確地交換數據。一旦握手成功,客戶端和服務器之間就建立了一個持久化的TCP連接,可以隨時進行消息傳輸。
由于TCP協議本身已經提供了一定程度的可靠性保證,因此MQTT協議只需要在TCP的基礎上實現發布/訂閱機制、QoS級別控制、保留消息等特性即可,從而使得它成為一種輕量級且高效的物聯網通信協議。
1.3 JSON里如何保存圖片數據?
在JSON中保存圖片數據通常需要將圖片轉換為二進制數據,并將其編碼成Base64字符串,然后將該字符串作為JSON對象的屬性值進行傳輸。
Base64編碼是一種將二進制數據轉換為ASCII字符的方法,它使用64個字符來表示任意序列的二進制數據。Base64編碼后的數據長度會比原始二進制數據略長,但可以方便地被轉換為文本格式并在網絡上進行傳輸。
以下是一個示例JSON對象,其中包含了一個Base64編碼后的圖片數據:
{
"imageData": "/9j/4AAQSkZJRgABAQEAYABgAAD/2wBD...",
"imageName": "my_image.png"
}
在這個示例中,imageData
屬性表示圖片數據的Base64編碼字符串,imageName
屬性表示圖片文件名。在接收到JSON對象后,可以通過解碼Base64字符串并將其保存為二進制數據,再將其寫入磁盤或者顯示在應用程序中。
需要注意的是,由于Base64編碼后的數據量相對較大,因此在實際應用中,如果需要傳輸大量的圖片數據,建議使用其他更適合的數據傳輸方式,如MQTT協議、WebSocket等。
1.4 MQTT協議最大能傳多少有效字節的數據?
MQTT協議本身沒有限制數據包的大小,但是它需要遵循底層傳輸協議(TCP/IP)的限制和約束。在實際應用中,MQTT協議能夠傳輸的有效數據量是受多種因素影響的,如網絡帶寬、QoS級別、MQTT消息頭部信息等。
一般來說,在默認情況下,MQTT協議對于單個消息的有效載荷有一個限制,即不超過256MB。這個限制主要由MQTT協議的消息長度字段決定,該字段的最大值是4字節,因此最大能表示2^32-1個字節的消息長度,即約為4GB。然而,在實際應用中,由于網絡帶寬和設備性能等方面的限制,很難實現傳輸如此巨大的消息。
另外,需要注意的是,如果使用較高級別的QoS,如“至少一次”或“恰好一次”,則MQTT協議會對每條消息進行確認和重傳,這可能會導致更多的網絡流量和延遲。因此,在選擇QoS級別時,需要根據應用場景和網絡環境的實際情況進行優化和調整,以充分利用MQTT協議的特點和優勢。
三、阿里云服務器創建
官網地址: https://iot.console.aliyun.com/lk/summary/new
3.1 創建產品
3.2 添加設備
{
"ProductKey": "a12qAqNZg3i",
"DeviceName": "video_de1",
"DeviceSecret": "206a4bc03642930542a9bcb8925b9a0f"
}
創建完成。
3.3 創建自定義屬性
在產品頁面的,找到功能定義。
最大一次只能傳遞10KB。
3.4 MQTT服務器地址和端口
關于MQTT協議登錄所需要的參數官方說明文檔: https://help.aliyun.com/document_detail/140507.html?spm=a2c4g.11186623.6.571.1e417544OGPj2y
阿里云物聯網服務器的域名規則如下:
物聯網平臺的域名格式為:productKey.iot-as-mqtt.cn-shanghai.aliyuncs.com,其中productKey是您在物聯網平臺上創建的產品的標識符,cn-shanghai表示物聯網服務器所在的地區。
?
MQTT協議的域名格式為:productKey.iot-as-mqtt.cn-shanghai.aliyuncs.com,其中productKey是您在物聯網平臺上創建的產品的標識符,cn-shanghai表示物聯網服務器所在的地區。
?
HTTPS協議的域名格式為:productKey.iot-as-http.cn-shanghai.aliyuncs.com,其中productKey是您在物聯網平臺上創建的產品的標識符,cn-shanghai表示物聯網服務器所在的地區。
?
需要注意的是,以上的域名規則中,productKey需要替換成你在物聯網平臺上創建產品時生成的實際productKey。
下面是阿里云國內的服務器地域和可用區詳情:
地域名稱 所在城市 Region ID 可用區數量
華北 1 青島 cn-qingdao 2
華北 2 北京 cn-beijing 10
華北 3 張家口 cn-zhangjiakou 3
華北 5 呼和浩特 cn-huhehaote 2
華北 6 烏蘭察布 cn-wulanchabu 3
華東 1 杭州 cn-hangzhou 8
華東 2 上海 cn-shanghai 8
華南 1 深圳 cn-shenzhen 6
華南 2 河源 cn-heyuan 2
華南 3 廣州 cn-guangzhou 2
西南 1 成都 cn-chengdu 2
?
端口號是:1883
?
我的設備參數:
{
"ProductKey": "a12qAqNZg3i",
"DeviceName": "video_de1",
"DeviceSecret": "206a4bc03642930542a9bcb8925b9a0f"
}
?
經過上面的格式解釋,我的阿里云服務器登錄的域名就是(選擇的是上海服務器):
a12qAqNZg3i.iot-as-mqtt.cn-shanghai.aliyuncs.com
?
解析域名對應的IP地址:
Microsoft Windows [版本 10.0.19044.2604]
(c) Microsoft Corporation。保留所有權利。
?
C:Users11266>ping a12qAqNZg3i.iot-as-mqtt.cn-shanghai.aliyuncs.com
?
正在 Ping vpc-sh-prod.mqtt.iotgds.aliyuncs.com.gds.alibabadns.com [47.103.191.238] 具有 32 字節的數據:
來自 47.103.191.238 的回復: 字節=32 時間=40ms TTL=88
來自 47.103.191.238 的回復: 字節=32 時間=40ms TTL=88
來自 47.103.191.238 的回復: 字節=32 時間=40ms TTL=88
來自 47.103.191.238 的回復: 字節=32 時間=40ms TTL=88
?
47.103.191.238 的 Ping 統計信息:
數據包: 已發送 = 4,已接收 = 4,丟失 = 0 (0% 丟失),
往返行程的估計時間(以毫秒為單位):
最短 = 40ms,最長 = 40ms,平均 = 40ms
?
C:Users11266>
3.5 MQTT三元組格式
下載密碼生成小工具:https://help.aliyun.com/document_detail/292635.htm?spm=a2c4g.11186623.0.0.5aaf635b3zgveM#section-jx3-u57-pmm
打開密碼生成工具:
生成MQTT登錄的密匙: 填入的參數就是前面創建設備得到信息。
mqttClientId:
video_de1|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
?
username:
video_de1&a12qAqNZg3i
?
password:
02F7190BE8C33C1A8009EDBAF824BFDC6784FC67
?
3.6 主題發布與訂閱的格式
在產品頁面可以看到主題格式: https://iot.console.aliyun.com/product/productDetail/a1cMlEwEwjg/func?current=2
總結:
發布主題:
/sys/a12qAqNZg3i/video_de1/thing/event/property/post
上報屬性消息的格式:
{"method":"thing.event.property.post","params":{"image":"1234567890"}}
?
訂閱主題:
/sys/a12qAqNZg3i/video_de1/thing/service/property/set
3.7 MQTT設備登錄
利用MQTT客戶端完成設備登錄測試。
IP地址:47.103.191.238
?
端口號:1883
?
mqttClientId: video_de1|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
?
username: video_de1&a12qAqNZg3i
?
password: 02F7190BE8C33C1A8009EDBAF824BFDC6784FC67
?
?
發布主題:
/sys/a12qAqNZg3i/video_de1/thing/event/property/post
上報屬性消息的格式:
{"method":"thing.event.property.post","params":{"image":"1234567890"}}
?
訂閱主題:
/sys/a12qAqNZg3i/video_de1/thing/service/property/set
對號入座填入參數,測試主題訂閱,主題發布:
數據接收成功:
到此服務器創建成功。
3.8 繼續創建設備2
監控設備有兩個,1個設備為攝像頭圖片發送端,一個設備是圖片接收顯示端。
{
"ProductKey": "a12qAqNZg3i",
"DeviceName": "video_dev2",
"DeviceSecret": "30ebb8ffc4316fbe957fcfb13bdaec01"
}
創建成功。
接下來生成設備2的MQTT三元組密匙,和前面一樣的方法。
mqttClientId:
video_dev2|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
username:
video_dev2&a12qAqNZg3i
password:
15D2C020586E165E6A35BB2FA4DEB9DD59F3E73E
參數總結:
IP地址:47.103.191.238
端口號:1883
mqttClientId: video_dev2|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
username: video_dev2&a12qAqNZg3i
password: 15D2C020586E165E6A35BB2FA4DEB9DD59F3E73E
發布主題:
/sys/a12qAqNZg3i/video_dev2/thing/event/property/post
上報屬性消息的格式:
{"method":"thing.event.property.post","params":{"image":"abcdefg"}}
訂閱主題:
/sys/a12qAqNZg3i/video_dev2/thing/service/property/set
四、云產品流轉
4.1 創建解析器
創建完成。
4.2 創建規則
添加主題:
設置數據目的:
編寫解析器腳本:
幫助文檔地址:https://help.aliyun.com/document_detail/270937.html
下面編寫代碼,獲取設備1上傳的數據,轉發給設備2。
//通過payload函數,獲取設備上報的消息內容,并按照JSON格式轉換。
var data = payload("json");
//直接流轉物模型上報數據。
writeIotTopic(1000, "/a12qAqNZg3i/video_dev2/user/get", data)
寫好解析器就發布。
在云產品流轉的首頁啟動解析器。
4.3 測試兩個設備的訂閱
設備1的參數:
IP地址:47.103.191.238
端口號:1883
mqttClientId: video_de1|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
username: video_de1&a12qAqNZg3i
password: 02F7190BE8C33C1A8009EDBAF824BFDC6784FC67
設備1發布主題:
主題格式:/a12qAqNZg3i/video_de1/user/update
數據內容:{"method":"thing.event.property.post","params":{"image":"1234567890"}}
設備2的參數:
IP地址:47.103.191.238
端口號:1883
mqttClientId: video_dev2|securemode=2,signmethod=hmacsha1,timestamp=1678078910527|
username: video_dev2&a12qAqNZg3i
password: 15D2C020586E165E6A35BB2FA4DEB9DD59F3E73E
設備2訂閱主題:
主題格式:/a12qAqNZg3i/video_dev2/user/get
五、項目開發
5.1 base64編碼和解碼實現
攝像頭采集圖像數據之后會編碼 成base64格式的字符串,再通過MQTT協議上傳到物聯網服務器。 下面就是base64編碼和解碼的實現代碼。
const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//進行base64編碼
//bindata:進行編碼的圖片數據
//base64:轉換后的base64編碼
//binlength:圖片大小
char * base64_encode( u8 * bindata, char * base64, u32 binlength )
{
u32 i, j;
u8 current;
for ( i = 0, j = 0 ; i < binlength ; i += 3 )
{
current = (bindata[i] >> 2) ;
current &= (u8)0x3F;
base64[j++] = base64char[(int)current];
current = ( (u8)(bindata[i] << 4 ) ) & ( (u8)0x30 ) ;
if ( i + 1 >= binlength )
{
base64[j++] = base64char[(int)current];
base64[j++] = '=';
base64[j++] = '=';
break;
}
current |= ( (u8)(bindata[i+1] >> 4) ) & ( (u8) 0x0F );
base64[j++] = base64char[(int)current];
current = ( (u8)(bindata[i+1] << 2) ) & ( (u8)0x3C ) ;
if ( i + 2 >= binlength )
{
base64[j++] = base64char[(int)current];
base64[j++] = '=';
break;
}
current |= ( (u8)(bindata[i+2] >> 6) ) & ( (u8) 0x03 );
base64[j++] = base64char[(int)current];
current = ( (u8)bindata[i+2] ) & ( (u8)0x3F ) ;
base64[j++] = base64char[(int)current];
}
base64[j] = '?';
return base64;
}
//解碼base64
//base64:base64編碼
//bindata:圖片數據
int base64_decode( const char * base64, u8 * bindata )
{
u32 i, j;
u8 k;
u8 temp[4];
for ( i = 0, j = 0; base64[i] != '?' ; i += 4 )
{
memset( temp, 0xFF, sizeof(temp) );
for ( k = 0 ; k < 64 ; k ++ )
{
if ( base64char[k] == base64[i] )
temp[0]= k;
}
for ( k = 0 ; k < 64 ; k ++ )
{
if ( base64char[k] == base64[i+1] )
temp[1]= k;
}
for ( k = 0 ; k < 64 ; k ++ )
{
if ( base64char[k] == base64[i+2] )
temp[2]= k;
}
for ( k = 0 ; k < 64 ; k ++ )
{
if ( base64char[k] == base64[i+3] )
temp[3]= k;
}
bindata[j++] = ((u8)(((u8)(temp[0] << 2))&0xFC)) |
((u8)((u8)(temp[1]>>4)&0x03));
if ( base64[i+2] == '=' )
break;
bindata[j++] = ((u8)(((u8)(temp[1] << 4))&0xF0)) |
((u8)((u8)(temp[2]>>2)&0x0F));
if ( base64[i+3] == '=' )
break;
bindata[j++] = ((u8)(((u8)(temp[2] << 6))&0xF0)) |
((u8)(temp[3]&0x3F));
}
return j;
}
5.3 軟件設計
5.4 運行效果
-
物聯網
+關注
關注
2909文章
44557瀏覽量
372779 -
服務器
+關注
關注
12文章
9123瀏覽量
85324 -
攝像頭
+關注
關注
59文章
4836瀏覽量
95599 -
阿里云
+關注
關注
3文章
952瀏覽量
43007 -
MQTT
+關注
關注
5文章
650瀏覽量
22487
發布評論請先 登錄
相關推薦
評論