快速部署一个简易的环温监测网络(BLE+MQTT+HTTP)
时间:2022-11-26 08:30:00
本文不包括公司机密技术和信息。
在新公司工作了几个月后,我发现货架上的机器对环境温度仍然很敏感,然后机器本身的散热也很严重,导致货架上的一些机器受到高温的干扰,无法正常运行。
因为我在第二次测试中主要做温度测量,所以我提出了一个想法,我想在货架上部署温度传感器,然后通过物联网网关集成数据,我们可以随时监控当前机器的温度。领导者积极行动,觉得有助于研发,直接决定。
有了想法,我去找了一下,发现了很多特殊的物联网服务器,比如mosquitto等等。再加上蓝牙网关,初步思路基本形成。
最终技术框架:根据需求密度部署货架BLE温度传感器,传感器与特定位置一一绑定,然后不断广播该区域的温度数据。然后根据场地地形和实际测试部署BLE网关设备,网关会定期扫描周围BLE集成后上传到后端的物联网服务器。服务器本身也提供了一个简单的服务器http显示数据并提供查询服务的服务。
大概这样的结构(BLE MQTT HTTP):
该网络的一个优点是,无论哪个环节、各种设备、实现方法等,都可以灵活更换。
毫无疑问,使用传感器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)
温度详情
设备温度列表:
$for item in lists:
$if 'temp' in item:
货架:
$item['position']
Mac:
$item['sensor']
温度:
$item['temp']
效果(这里是在服务器上跑,然后本地访问的,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万组温度数据,对于后续拓展有一定的想象空间;
特点:防水塑封包装,适用于长期监测稳定运行,带塑封的情况下温度反应较缓慢,当前场景可拆掉塑封。