资讯详情

快速部署一个简易的环温监测网络(BLE+MQTT+HTTP)

在新公司工作了几个月后,我发现货架上的机器对环境温度仍然很敏感,然后机器本身的散热也很严重,导致货架上的一些机器受到高温的干扰,无法正常运行。

因为我在第二次测试中主要做温度测量,所以我提出了一个想法,我想在货架上部署温度传感器,然后通过物联网网关集成数据,我们可以随时监控当前机器的温度。领导者积极行动,觉得有助于研发,直接决定。

有了想法,我去找了一下,发现了很多特殊的物联网服务器,比如mosquitto等等。再加上蓝牙网关,初步思路基本形成。

最终技术框架:根据需求密度部署货架BLE温度传感器,传感器与特定位置一一绑定,然后不断广播该区域的温度数据。然后根据场地地形和实际测试部署BLE网关设备,网关会定期扫描周围BLE集成后上传到后端的物联网服务器。服务器本身也提供了一个简单的服务器http显示数据并提供查询服务的服务。

大概这样的结构(BLE MQTT HTTP):

479284eb708c42489188532eeaac5610.png

该网络的一个优点是,无论哪个环节、各种设备、实现方法等,都可以灵活更换。

毫无疑问,使用传感器BLE无线温度计,功耗超低,传输距离适合室内部署。在这里,我直接选择了老东家秒测的产品。秒测的产品做得很好,然后我非常信任和熟悉它们,因为我参与了。~。几乎所有具有温度测量功能的产品都有秒测量功能BLE,所以理论上可以选择任何一个。综合使用场景,无线冷链标签和米家蓝牙温湿度计2。

然后BLE网关,我自己找到了一个更好的功能非常强大的网关,但第二次测试同事帮助推荐4月兄弟的产品,简单但便宜得多,出于信任选择了后者。在收到网关后,我发现4月份的兄弟提供了一个测试mqtt服务器,现在,前期不用自己部署服务器。

当我收到网关时,我碰巧在家工作,所以我在家里做了一个测试。我手头还保留了一些家用温湿度计,还有几个研发用的冷链标签(属于离职未归还的公司财产,有罪…)。按说明配置网关后,可以直接在工具中看到网关扫描的广播数据,非常棒。

然后开始研究如何部署自己的服务器,毕竟四月兄弟的测试服务器不受控制。网络上有很多企业级的,腾讯和阿里云都有提供此类服务,比较有名的,EMQX,功能非常强大。另一个是轻量级mosquitto,可部署在低功耗单板计算机上。

我在这里说的是,在一个特殊的网络环境中,并发量不会太大。考虑到我可能不得不准备自己的机器部署,我选择了一个正在吃灰的覆盆子派mosquitto。

可直接安装在这里eclipse-mosquitto,也可以自己下载源码编译。我试过两个,都比较了easy。配置端口号启动服务后,修改网关报告地址和topic可以等待信息mosquitto的log看到稳定的数据流。

接下来,我们需要提供一个简单的http显示数据并提供查询接口的服务。

由于传感器应与货架一一对应,因此应提前准备好相应的关系。传感器放置在哪个位置,机器对应的位置ip段是多少,这样你就可以通过绑定关系了解后续查询中的某一段ip相应的货架温度是多少?

我在这里用一个json例如,文件描述了这种关系,A22这个货架,对应的ip分段是 10.77.两个传感器部署在货架上。

[  {   "position":"A22",   "ip_start":"10.77.22.0",   "ip_end":"10.77.22.254",     "sensor":["FE9738011038","FE9738011096"]    },  {   "position":"A41",   "ip_start":"10.77.41.0",   "ip_end":"10.77.41.254",     "sensor":["FE9738011025","A4C138F18B7F"]    }  ]  

代码如下。由于并发数量很低,编写的代码也很懒惰。直接暴力需要什么数据(下次我必须从良2333)。然后这里分析了两个传感器。只要有广播,您将首先识别哪个设备,然后根据相应的格式分析数据。然后我真的不熟悉它python,找了个web.py提供简单的模块http服务。

#! /usr/bin/env python3 # -- coding:utf-8--  import os import sys  sys.path.append('/home/min.hu/.local/lib/python3.9') sys.path.append('/home/min.hu/.local/lib/python3.9/site-packages') sys.path.append(os.path.abspath(os.path.dirname(__file__)   '/'   '..')) sys.path.append("..")  import time import paho.mqtt.client as mqtt import msgpack import json import web  #HOST= "mqtt.bconimg.com" HOST= "xx.xx.xx.xx" PORT=1884 TOPIC ="hm/test" USER ="hm" PWD="hm"  NIOT_NAME = "MOT-U202"      #冷链标签 MINI_NAME = "LYWSD03MMC"    #米家蓝牙温湿度计2  niot_list=set() mini_list=set() maps={} lists=[]  #@json file:labs_more_2.json  def read_lists(folder):     filelist =os.listdir(folder)     for i in range(0,len(filelist)):         path = os.path.join(folder,filelist[i])         print("file:{}".format(filelist[i]))         if os.path.isfile(path) and path.endswith('.json'):             with open(path,'r') as jfile:                 mlist = json.load(jfile)                   lists.extend(mlist)                 for k in range(0,len(mlist)):                     print(mlist[k])          def get_mac_info_by_band_ip(band_ip):     for key,value in maps.items():         iplist=value['ip']         for ip in iplist:             if(band_ip == ip):                 return key                   return None def get_map_info_by_ip(band_ip):    ip_section= band_ip.rsplit('.',1)  
    for item in lists:
        if item['ip_start'].startswith(ip_section[0]):
            #直接返回
            return item
    return None    
    
def get_map_info_by_mac(band_mac):
    for item in lists:        
        if band_mac in item['sensor']:
            return item
    return None    


def print_map_info(map):
    print(map) 

#niot    
# 02 01 06 03 02 09 18 17 16 CF CF FE 97 38 01 10 38 D4 0C 21 05 00 00 00 00  01  C4   66 0B    00 0A
#                                 |-------mac-------|-max-|-min-|--counter--|sta|batt|cur_temp|itv(0.5min)|
#mini
# 02 01 06 11 16 95 FE 30 58 5B 05 0C 7F 8B F1 38 C1 A4 28 01 00 05 38 01 F6 01 64 ...
#                                    |------mac--------|           |temp |-hum-|batt|      

      
def read_temp(mac,advdata,device):
    cur_temp =float(0)
    if device ==NIOT_NAME:
        cur_temp = float(advdata[27]|(advdata[28]<<8))/100
    elif device ==MINI_NAME:          
        cur_temp = float(advdata[22]|(advdata[23]<<8))/10    

    for item in lists:        
        if mac in item['sensor']:
            index =item['sensor'].index(mac)
            if not 'temp' in item:
                item['temp']=['' for i in range(len(item['sensor']))]
            item['temp'][index]=cur_temp
            print(item)
            break

def check_name_from_ltv_data(mac,advdata):
    i=0
    while(i < len(advdata)):
        length =advdata[i]
        sec_type=advdata[i+1]        
        if sec_type ==9:#通过设备名称筛选
            name = ''.join(chr(advdata[i+2+x]) for x in range(length-1))
            if(MINI_NAME == name):
                mini_list.add(mac)
            elif(NIOT_NAME == name):
                niot_list.add(mac)
            else:
                None        
        i+=(length+1)

def check_temp_from_lvt_data(mac,advdata):
    if mac in niot_list:
        read_temp(mac,advdata,NIOT_NAME)    
    elif mac in mini_list:
        read_temp(mac,advdata,MINI_NAME) 

def print_hex(bytes):
    # l=[hex(int(i)) for i in bytes]
    l=["%02X"%(int(i)) for i in bytes] 
    print(" ".join(l))

def on_subscribe(mosq, obj, mid, granted_qos):
    print("Subscribed: " + str(mid))

def on_message(mosq, obj, msg):
    for d in msgpack.unpackb(msg.payload, raw = True)[b'devices']:
        #parse iBeacon data        
        advData = d[8:]
        mac = "{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}".format((d[1]), (d[2]), (d[3]), (d[4]), (d[5]), (d[6]))
        # print("mac:%s"%mac)
        map=get_map_info_by_mac(mac)
        if map!=None:
            if(d[0]==4):            
                check_name_from_ltv_data(mac,advData)
            else:    
                check_temp_from_lvt_data(mac,advData)             


def on_connect(mosq, obj,flags, rc):
    mqttTopic = TOPIC
    print("Connected with result code "+str(rc))
    mqttc.subscribe(mqttTopic, 0)
    print("Connected")

read_lists("./")
mqttHost    = HOST
mqttPort    = PORT
mqttc = mqtt.Client()
mqttc.on_connect = on_connect
mqttc.on_subscribe = on_subscribe
mqttc.on_message = on_message
mqttc.username_pw_set(USER,PWD)
mqttc.connect(mqttHost, mqttPort, 60)
# mqttc.loop_forever()
mqttc.loop_start()

#query page.

class sensor:
    def GET(self,ip):
        if not ip:            
            return temp_page(lists)  
        else:
            map =get_map_info_by_ip(ip)
            if(map):
                print(map)  
                return map

    
urls = ('/(.*)', 'sensor')
app = web.application(urls, globals())
temp_page =web.template.frender('templates/temp.html')

if __name__ == "__main__":
    print("app.run...")
    app.run()
    

        发现可以使用模板文件:

$def with(lists)

<!DOCTYPE html>
<html>
    <head>        
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>温度详情</title>           

    </head>
    <body>
        <h1>设备温度列表:</h1>
<table border ='1' >        
        
$for item in lists:
    $if 'temp' in item:
        <tr>
            <td>货架:</td>
            <td>$item['position']</td>
            <td>Mac:</td>
            <td>$item['sensor']</td>
            <td>温度:</td>
            <td>$item['temp']</td>
        </tr>        
</table> 
</body>
</html>

        效果(这里是在服务器上跑,然后本地访问的,localhost是vscode自动转发的端口):

         假如在访问地址后添加一个ip参数,则会直接返回这样一组数据:

{'position': 'A22', 'ip_start': '10.77.22.0', 'ip_end': '10.77.22.254', 'sensor': ['FE9738011038', 'FE9738011096'], 'temp': [31.27, 30.02]}

        更进一步的扩展能力,比如需要查看某个货架的历史温度,有两种实现方式。一种是,服务器端集成数据仓库服务,持久化接收到的温度数据,物联网环境推荐使用同样小巧轻便的sqlite3;另外传感器本身是有存储历史数据的,可以通过直接读取某个传感器的数据来展示,这中方式需要网关支持,然后BLE的数据吞吐量限制,传输数据需要一定的时间。

然后几个主要的问题点。

        树莓派的优点是,轻巧的很,部署也很方便,哪里需要就往哪里搬。如果没有专用服务器的话,一个树莓派几百元就能搞定。使用树莓派存在的一个问题是,只能在局域网中访问。如果需要在外部网络访问,需要花生壳之类的内网穿透软件。一套下来,成本可能比直接部署在云上高…

        由于公司本身有研发专用的服务器,我想了想就省点钱,把mosquitto转移到研发服务器上。本身是个linux小白,又没有root权限,折腾起来有点麻烦,最后是在docker上安装的。

        网上有一大堆如何在docker上部署mosquitto的文章,基本上都说明白了。有一个细节的地方是,mosquitto.conf文件的配置,各种路径要对应docker中的环境而不是本机。mosquitto.conf文件配置(docker):

persistence true
persistence_location /mosquitto/data
allow_anonymous false
password_file /mosquitto/config/pwfile.conf
log_dest file /mosquitto/log/mqtt.log
log_type error
log_type warning
log_type debug
listener 1884
#注意在docker中生成的文件不会同步到当前主机中,比如pwfile.conf文件,这里是手动复制过来的

Docker启动脚本:

docker run -itd \
 --name=mosquitto\
 --privileged=true \
 -p 1884:1884 -p 9001:9001 \
 -v /home/min.hu/mqtt/config/mosquitto.conf:/mosquitto/config/mosquitto.conf \
 -v /home/min.hu/mqtt/config/pwfile.conf:/mosquitto/config/pwfile.conf \
 -v /home/min.hu/mqtt/data:/mosquitto/data \
 -v /home/min.hu/mqtt/log:/mosquitto/log \
  eclipse-mosquitto 

另一个比较麻烦的问题是,对于一些专用的vpn网络,部署起来相对麻烦。我们这边,要找运维开端口开防火墙,然后坑爹的网络环境跑起来还各种丢数据,ssh都登录不上,要反复的测试。

实际部署

        一般基于BLE5.0以上的网关,其传输距离在50米左右,也就是说,一台网关可以覆盖方圆100米的范围。然后实际部署的时候,要考虑到墙壁以及各种物体阻碍信号传输,具体要部署多少个网关可以实际测试下。

        然后传感器的部署数量,这里可以分为中高低三种精度。中等精度,每个货架放两台,一边一个;对于一个高精度的监测网络而言,可以每个货架每层放两台,或者更高精度每台机器旁边都放置一个传感器;低精度的话,每个货架一个就可以。

        MQTT服务器的架构本身决定了,可以有多个sub client 和pub client。所以扩充起来非常方便,适合一步一步将整个网络从小到大逐渐扩展。

        然后部署成本上,不计算其他任务的情况下,整体实际研发和部署时间:1-2天;

附,成本清单:

        四月兄弟IOT网关(不带电源):265元/台 +电源12元/台;

        米家蓝牙温湿度计2:29元/台。寿命一年,可换电池。     优点:带液晶显示屏,带湿度数据,本机可存储三个月数据;     缺点:0℃以下可能无法正常工作;此产品为米家定制,未绑定米家账号的时候,不广播温湿度数据,可行性需要与秒测验证;         秒秒测独角兽:69元/台:

    寿命:一年半以上,若调整广播频率和数据记录间隔,估计最低可达两年以上。     优点:超长寿命可免于维护,设备本身可连续记录10万组温度数据,对于后续拓展有一定的想象空间;     特点:防水塑封包装,适用于长期监测稳定运行,带塑封的情况下温度反应较缓慢,当前场景可拆掉塑封。   

标签: 无线传感器网络中path湿度传感器hm1520pw传感器8b型高稳定性传感器传感器pwd12无线传感器模块sys

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台