基于“樹莓派+騰訊云”的在線甲醛監(jiān)測系統(tǒng)

身邊朋友在裝修新房,順便來吐槽甲醛檢測麻煩,比如 有檢測無監(jiān)測(一次性),比如測試復雜(現(xiàn)場+人工)等等。剛好做為云產(chǎn)品經(jīng)理,經(jīng)常想的就是如何了解和驗證多云產(chǎn)品組合方案的可用性問題,索性結(jié)合一下,直接把這個需求上云,然后就有了這套系統(tǒng)。老規(guī)矩,先上結(jié)論。

系統(tǒng)概要

產(chǎn)品設(shè)計特性

  • 原型驗證:驗證產(chǎn)品聯(lián)動效果與開發(fā)成本。
  • 軟硬結(jié)合:擴展云端能力至線下物理環(huán)境。
  • 能力擴展:serverless分離云端與終端,獨立擴展云監(jiān)控、消息隊列等其它產(chǎn)品。
  • 通用架構(gòu):云端使用通用數(shù)據(jù)結(jié)構(gòu)及接口,免開發(fā)即對接各種監(jiān)測數(shù)據(jù)上報。
  • 弱環(huán)境要求:可PoE供電,5V/0.5A低功耗可長期運行。

系統(tǒng)組成

終端:終端組件

  • RaspberryPi 3B+(raspbian-stretch-lite/GPIO接口/python2.7)
  • UART-CH2O傳感器(UART接口)
  • 128X32 OLED屏 SSD1306芯片(I2C接口)

注:RaspberryPi后續(xù)簡寫為Rpi

云端:騰訊云產(chǎn)品

效果展示

騰訊云圖

本案例展示效果

終端組件

本案例終端示例

當前版本中,Rpi 使用wifi 連接互聯(lián)網(wǎng)(也可使用有線網(wǎng)),故此處上云有網(wǎng)絡(luò)依賴。

傳感器原理與功能定位

UART-CH2O傳感器

  • 原理:電化學傳感器。通過與被測氣體發(fā)生反應(yīng),并產(chǎn)生電信號來工作。
  • 優(yōu)點:簡單易操作。
  • 缺點:非定量分析法,受溫濕度、其它氣體干擾準確度,且需要較準。
  • 結(jié)論:以長期使用后的房間環(huán)境做為基準,進行0基準點參考。用于溫濕度差異不大的環(huán)境下,提供實時監(jiān)測(相對值),并附加長期趨勢分析。

設(shè)計與實現(xiàn)

產(chǎn)品設(shè)計與技術(shù)策略

設(shè)計過程中,也進行了產(chǎn)品生命周期的思考,嘗試進行了產(chǎn)品長短期設(shè)計的分析與定義(暫不展開,后續(xù)有時間寫一下)。

確認了形態(tài)目標后,遵循下面幾個基本原則,進行具體技術(shù)設(shè)計:

  • 分級可用:避免單環(huán)故障,系統(tǒng)全面崩潰
  • 讀寫分離:便于后續(xù)調(diào)試、優(yōu)化、更新版本
  • 遠程維護:避免出現(xiàn)場處理異常

概要架構(gòu)圖

架構(gòu)圖

從架構(gòu)看來

  • 云端部分:由于云產(chǎn)品的能力提供了各種便利,學習和搭建成本很低。
  • 終端部分:需要多考慮免維護與自動恢復,各項工作內(nèi)容稍多一些。

硬件接線與打開系統(tǒng)接口

Rpi GPIO

GPIO

(General-purpose input/output)即通用IO接口,是一種常見的端口擴展器,樹莓派使用的是40針的GPIO接口。

RPI GPIO圖示

GPIO示意圖

UART-CH2O

接線方式(UART協(xié)議)

傳感器 Rpi
5V Pin2(5V)
GND Pin6(GND)
UART-TxD Pin10(UART-RxD)

注:本次使用傳感器,硬件接口是1.25mm端子,Rpi是2.5mm端子,使用了 7P1.25轉(zhuǎn)2.5杜邦線,進行連接

硬件參數(shù)

本次使用的傳感器是UART協(xié)議,從國外的DART傳感器到國內(nèi)產(chǎn)品,均支持此協(xié)議。

由于后續(xù)代碼與接口有關(guān),此處列一下我使用的傳感器的數(shù)據(jù)格式.默認每秒主動上報。

Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8
起始位 氣體名稱 單位 小數(shù)位數(shù) 氣體濃度-高位 氣體濃度-低位 滿量程高位 滿量程低位 較驗值
0xFF 0x17 0x04 0x00 0x00 0x25 0x13 0x88 0x25

OLED

接線方式(I2C協(xié)議)

OLED Rpi
VCC Pin1(3.3V)
SDA Pin3(SDA)
SCL Pin5(SCL)
GND Pin9(GND)

打開I2C接口

raspi-config

按下圖打開I2C接口

openi2c_1.png

openi2c_2.png

openi2c_3.png

測試執(zhí)行

i2cdetect -y 1
i2cdetect_1.png

看到 3C 即識別硬件成功

終端開發(fā)與配置

本文暫僅放出關(guān)鍵代碼(硬件操作部分),便于大家擼硬件。
完整包(代碼+配置) 稍后放出,請關(guān)注 github/DemoOnTencentCloud

環(huán)境配置

  • 啟動對時:rc.local 增加 nptdate cn.ntp.org.cn。避免重啟后時間錯位,監(jiān)測錯位。
  • 啟動拉起:getdata.py oled.py 需持續(xù)在線。
  • 定時檢測:getdata.py oled.py cron每分鐘判斷活性,進程掛掉即拉起。
  • 定時同步:sync.py cron每分鐘執(zhí)行
  • 遠程維護:使用ssh tunnel 的 Remote Port Forwarding 模式,進行反向代理。

ssh tunnel

此處使用 autossh 進行連接,autossh可完成建立通道與監(jiān)控通道的工作,通道斷開后,可自主重連。遠端連接 騰訊云服務(wù)器,之后可以云服務(wù)器為跳板,反向代理訪問NAT環(huán)境Rpi設(shè)備。

autossh -M 監(jiān)控端口 -R 遠程通信端口:localhost:22 賬號名@遠程IP或域名 -p端口號 -i 賬號KEY -o serveraliveinterval=60 -N -f

連接時,在云服務(wù)器執(zhí)行

ssh -p 遠程通信端口 localhost

getdata.py

獲取傳感器讀數(shù)代碼(完整代碼待放出 github/DemoOnTencentCloud

import serial
from time import sleep

ser=serial.Serial("/dev/serial0",9600)

while True :
    r_data = ser.read()
    sleep(0.3)
    data_left = ser.inWaiting()
    r_data += ser.read(data_left)
    if 9 != len(r_data):
        print 'error length: %d'%len(r_data)
        continue
    else:
        n=ord(r_data[4])*256+ord(r_data[5])
        updatedata(n/1000.0) # ppm = n/1000.0 

flusholed.py

依賴庫安裝(基于 https://github.com/adafruit/Adafruit_Python_SSD1306)

sudo python -m pip install --upgrade pip setuptools wheel
sudo pip install Adafruit-SSD1306

下為功能偽代碼。(完整代碼待放出 github/DemoOnTencentCloud

# 讀取 cachefile 緩存文件
# 刷新 OLED 顯示

sync.py

下為功能偽代碼。(完整代碼待放出 github/DemoOnTencentCloud

# 訪問 APIGW,獲取最新記錄時間戳
# 讀本地sqlite庫,獲取增量數(shù)據(jù)
# 訪問 APIGW,提交更新數(shù)據(jù)

Sqlite結(jié)構(gòu)

表結(jié)構(gòu)

CREATE TABLE "sensordata" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"utime" INTEGER NOT NULL,
"utype" INTEGER DEFAULT 0 NOT NULL,
"udata" REAL NOT NULL,
"sdata" TEXT
);
字段 說明
id 自增主鍵
stime 監(jiān)測時間戳
udata 監(jiān)測數(shù)據(jù)
utype (預(yù)留字段,擴展類別)
sdata (預(yù)留字段,擴展數(shù)據(jù)類型)

云端開發(fā)與配置

無服務(wù)器云函數(shù)

優(yōu)先配置 無服務(wù)器云函數(shù),參考 文檔 建立并保存“函數(shù)代碼”后,在管理頁面的“觸發(fā)方式”功能中,直接生成對應(yīng)API網(wǎng)關(guān)。

觸發(fā)方式選擇API網(wǎng)關(guān)

(完整代碼待放出 github/DemoOnTencentCloud)。

當前主要強調(diào)幾個注意事項:

  1. 自動提交:連接數(shù)據(jù)庫必須使用“autocommit = True,”參數(shù),否則由于事務(wù)隔離,DB鏈接重新連接前,查詢結(jié)果不變。(查不到新增記錄ID)
  2. 返回頭:API網(wǎng)關(guān)開啟“響應(yīng)集成”時,云函數(shù)返回值需結(jié)合返回信息,指定"Content-Type",否則出現(xiàn) "transfer closed with outstanding read data remaining" 錯誤。
  3. 驗證連接:云函數(shù)實例可長期存在,但一定時間未操作mysql鏈接時,mysql將釋放鏈接,所以代碼中需要進行驗證鏈路可用性。

API網(wǎng)關(guān)

配置服務(wù)

參考 文檔 ,以上文“觸發(fā)方式”中建立的API網(wǎng)關(guān)服務(wù),由API網(wǎng)關(guān)的 服務(wù) 頁面,點擊相應(yīng)服務(wù)名,選擇“API管理”分頁,點擊“編輯”,然后配置“請求方法-POST”、“鑒權(quán)類型-密鑰對”、“使用響應(yīng)集成”,其它余配置按默認即可。

下載與使用SDK

API網(wǎng)關(guān) 控制臺 -> 點擊 服務(wù)名 -> 點擊 API文檔/SDK -> 點擊 下載SDK

(完整配置待放出 github/DemoOnTencentCloud

云數(shù)據(jù)庫 Mysql

表結(jié)構(gòu)

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";

CREATE TABLE `sensordata` (
  `id` int(11) NOT NULL,
  `stime` timestamp NULL DEFAULT NULL,
  `utype` int(11) NOT NULL DEFAULT '0',
  `udata` float NOT NULL,
  `sdata` varchar(256) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `sensordata`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `sensordata`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
字段 說明
id 自增主鍵
stime 同sqlite utime
udata 同sqlite udata
utype 同sqlite utype
sdata 同sqlite sdata

云圖配置

簡要使用說明

拖選組件 -> 點擊數(shù)據(jù)欄 -> 選擇數(shù)據(jù)庫 -> 填寫SQL -> 開啟自動更新 -> 預(yù)覽 -> 發(fā)布

操作示例圖

騰訊云圖配置示意

組件配置信息

  • 最新同步時間 - 通用文本
select concat('最新同步時間 ',stime) as value from sensordata order by id desc limit 1
  • 國標系數(shù)比 - 水位圖
select round((udata)/0.08*100, 2) as value from sensordata order by id desc limit 1
  • 實時讀數(shù) - 基本條形圖
select round(udata, 3) as x, '' as y from sensordata order by id desc limit 1
  • 10分鐘數(shù)據(jù) - 基本折線圖
select * from (select id, round(udata, 3) as y, date_format(stime, '%H:%i:%S') as x, utype as s from sensordata order by id desc limit 360) as t1 order by id asc
  • 7天數(shù)據(jù) - 基本折線圖
select distinct (dt), round(AVG(udata),3) as y, dt as x, '0' as s from (select id, date_format(stime, '%Y-%m-%d %H') as dt, udata from sensordata order by id desc limit 604800) as t1 group by dt order by dt ASC

寫在最后

關(guān)于丟數(shù)據(jù)(非守護進程)、臟數(shù)據(jù)(未較驗數(shù)據(jù)唯一性)、缺乏系統(tǒng)監(jiān)控告警(未接入云監(jiān)控)等等待優(yōu)化點,由于時間關(guān)系暫未展開,后面可以再行探討。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容