日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

斐讯M1的报文

發布時間:2023/12/15 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 斐讯M1的报文 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

家里有個斐訊M1的空氣檢測儀,原來可以發送數據到服務器,再從手機app查看的。后來廠家倒閉了,服務器也關了,,,因為聯系不到服務器,wifi信號燈就會一直一閃一閃的。這幾天嘗試模擬搭建服務器,獲得成功,記錄一下。

一、首先原服務器的域名是aircat.phicomm.com ,這個是改不了的,但是可以通過在路由器的dns上做設置,把它解析為自己局域網內的服務器IP,修改完ping一下域名,能成功的解析為本地地址就對了。

二、服務器通信的端口是tcp 9000 。

最簡單是在模擬的服務器上執行

netcat -l -p 9000 ,

防火墻也要開放9000端口

sudo ufw allow 9000

此時M1能訪問到aircat.phicomm.com:9000 , 信號燈就不會閃了。而且可以看到netcat不斷收到M1發送的數據。

三、如果要進一步,拿到發送的數據,就需要再做些開發了。嘗試用python做了個簡單實現

# coding: utf-8 import select import socket import queue from time import sleepresponseMsg = b'\x00\x18\x00\x00\x02{"type":5,"status":1}\xff#END#'# Create a TCP/IP server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setblocking(False)# Bind the socket to the port server_address = ('192.168.88.17', 9000) print ('starting up on %s port %s' % server_address) server.bind(server_address)# Listen for incoming connections server.listen(5)# Sockets from which we expect to read inputs = [server]# Sockets to which we expect to write # 處理要發送的消息 outputs = []# Outgoing message queues (socket: Queue) message_queues = {}while inputs:# Wait for at least one of the sockets to be ready for processingprint ('waiting for the next event')# 開始select 監聽, 對input_list 中的服務器端server 進行監聽# 一旦調用socket的send, recv函數,將會再次調用此模塊readable, writable, exceptional = select.select(inputs, outputs, inputs)# Handle inputs# 循環判斷是否有客戶端連接進來, 當有客戶端連接進來時select 將觸發for s in readable:# 判斷當前觸發的是不是服務端對象, 當觸發的對象是服務端對象時,說明有新客戶端連接進來了# 表示有新用戶來連接if s is server:# A "readable" socket is ready to accept a connectionconnection, client_address = s.accept()print ('connection from', client_address)# this is connection not serverconnection.setblocking(0)# 將客戶端對象也加入到監聽的列表中, 當客戶端發送消息時 select 將觸發inputs.append(connection)# Give the connection a queue for data we want to send# 為連接的客戶端單獨創建一個消息隊列,用來保存客戶端發送的消息message_queues[connection] = queue.Queue()else:# 有老用戶發消息, 處理接受# 由于客戶端連接進來時服務端接收客戶端連接請求,將客戶端加入到了監聽列表中(input_list), 客戶端發送消息將觸發# 所以判斷是否是客戶端對象觸發data = s.recv(1024)# 客戶端未斷開if len(data)>0:# A readable client socket has dataprint ('received [%s %s] from %s' % (data[:23].hex(), data[23:], s.getpeername()))# 將收到的消息放入到相對應的socket客戶端的消息隊列中responsedata=data[:23] + responseMsgmessage_queues[s].put(responsedata)# Add output channel for response# 將需要進行回復操作socket放到output 列表中, 讓select監聽if s not in outputs:outputs.append(s)else:# 客戶端斷開了連接, 將客戶端的監聽從input列表中移除# Interpret empty result as closed connectionprint ('closing', client_address)# Stop listening for input on the connectionif s in outputs:outputs.remove(s)inputs.remove(s)s.close()# Remove message queue# 移除對應socket客戶端對象的消息隊列del message_queues[s]# Handle outputs# 如果現在沒有客戶端請求, 也沒有客戶端發送消息時, 開始對發送消息列表進行處理, 是否需要發送消息# 存儲哪個客戶端發送過消息for s in writable:try:# 如果消息隊列中有消息,從消息隊列中獲取要發送的消息message_queue = message_queues.get(s)send_data = ''if message_queue:send_data = message_queue.get_nowait()else:# 客戶端連接斷開了print ("has closed")except queue.Empty:# 客戶端連接斷開了errinfo=s.getpeername()print ( errinfo )outputs.remove(s)else:if message_queue :if len(send_data)>0:print ("send %s " % send_data)s.send(send_data)else:print ("has closed ")# writable.remove(s)# print "Client %s disconnected" % (client_address)# # Handle "exceptional conditions"# 處理異常的情況for s in exceptional:print ('exception condition on', s.getpeername())# Stop listening for input on the connectioninputs.remove(s)if s in outputs:outputs.remove(s)s.close()# Remove message queuedel message_queues[s]sleep(1)#start #[aa0f01350742398f0b0000000000000000b0f89324705300 b'\x00\x00\x04{ "humidity": "47.29", "temperature": "23.66", "value": "1", "hcho": "10" }\xff#END#'] from ('192.168.130.40', 23741)#[aa0f01350742398f0b0000000000000000b0f89324705300 b'\x00\x00\x01\xff#END#'] #[aa0f01350742398f0b0000000000000000b0f8932470 b'\x00\x03\x00\x00\x01\xff#END#'

代碼tcp通信的框架基本復制自網上,原作可能是在python2開發的,自己微調了一下,在python3可以跑。這里面關鍵是通信的報文解析,經過觀察是這樣的:

?1、M1往服務器送的報文

aa 0f 01 35 07 42 39 8f 0b 00 00 00 00 00 00 00 00 b0 f8 93 24 70 53?b'\x00\x00\x00\x00\x04{ "humidity": "47.29", "temperature": "23.66", "value": "1", "hcho": "10" }\xff#END#

(1)前23個字節(紅色部分,十六進制表示)一般是固定的,把它分為四組

aa 0f 01 35 07 42 39 8f 0b00 00 00 00 00 00 00 00 b0 f8 93 24 70 53
第一組第二組第三組第四組

第一組3個字節aa 0f 01是固定的,可以看為是報文標志符,可以用它來幫助判斷是否M1的報文;

第三組固定是8個全00字節;第四組是mac地址 ;

第二組經過觀察,其實是第四組(mac地址)的鏡像,可能是為了校驗或者迷惑?

(2)隨后是5個字節?+ Json數據?

5個字節定義不明,但目前只看到b'\x00\x00\x00\x00\x04?' ,這個不影響數據解析

Json數據就是發送的溫度、濕度、pm2.5等數據,稍作解析就可以利用。

(3)最后是結束標志:? ?b'\xff#END#?'? ,

跟開頭的報文標志聯合起來可以應該可以用正則提取報文了。

2、服務器往M1發的報文

服務器往M1發的報文有兩種

(1)心跳報文

aa 0f 01 35 07 42 39 8f 0b 00 00 00 00 00 00 00 00 b0 f8 93 24 70 53?b'\x00\x18\x00\x00\x02{"type":5,"status":1}\xff#END#'

這個報文紅色部分跟M1發過來的前23個字節是一樣的,可以從M1送來的報文截取后原封不動發回去。(調試時試過如果不一樣,會導致M1主動關閉連接,估計是m1判斷送來的報文mac地址跟自己mac地址不一樣,認為不是自己的數據。)后面的定義不明,不過也是固定的。

這個報文的作用好像是會激發M1上報數據,如果不發的話,M1在連接成功最初,會密集報送一定量的數據,之后如果沒有服務器反饋會明顯減慢發送頻率。在代碼里看見有人定義它為“心跳報文”。

(2)設置亮度

aa 0f 01 35 07 42 39 8f 0b 00 00 00 00 00 00 00 00 b0 f8 93 24 70 53?b'\x00\x18\x00\x00\x02{"brightness":"50.0","type":2}\xff#END#'

這個報文是設置屏幕亮度,brightness后面的數字一般是0、 25、 50、 75、 100,亮度逐漸增強

( 觀察發現發送了設置屏幕亮度的報文后,M1會暫停上報數據了,轉而發送

[aa0f01350742398f0b0000000000000000b0f893247053 b'\x00\x03\x00\x00\x01\xff#END#']

可能是對于設置亮度成功的一種應答。

此時需要服務器發一條心跳報文給M1,就會開始繼續上報數據)

總結

以上是生活随笔為你收集整理的斐讯M1的报文的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。