【前言】
一個熱愛技術的人一定向往有一個科技感十足的環境吧,那何不親自實踐一下屬於技術人的座右銘:“技術改變世界”。
就讓我們一步步動手搭建一個屬於自己的“智能家居平台”吧(不要對這個名詞抬杠啦,技術在手,怎么設計實現因人而異),本文只做拋磚引玉,各路大神如果有更好的想法可以各顯神通,當然能在評論區留下更好的想法讓大家共同學習是再好不過啦。
在文章最后附有所有源代碼,有需要的可以自行下載,感謝Star~
【系列目錄】
- 樹莓派GPIO簡介(Python版)
- 溫濕度數據采集存儲(DHT11,MySql)
- 溫濕度數碼管展示(四位共陽數碼管)
- 構建App展示溫濕度報表(ApiCloud,Python Flask)
- 普通家用排插集成繼電器手工改造
- App遠程控制“自制智能”排插
- 使用花生棒內網穿透實現外網訪問
- App遠程監控(攝像頭模塊集成)
【本節概要】
上一節我們介紹了基於樹莓派基於DHT11采集溫濕度並將記錄存儲到mysql數據庫中,這一節我們將分享四位共陽數碼管的使用以及將我們的溫濕度數據在數碼管展示。
效果圖:
那么接下來我們就一步步講解這個"窮且益艱"的過程...
【硬件采購】
”某寶“購買一個四路共陽數碼管模塊,不貴,一兩瓶飲料的價格。下圖很明顯有四個顯示位,並且是公用陽極,而用陰極控制顯示與否,因此叫四路共陽。
說明書有一張圖就夠了:
1,2,3,4 高電平控制顯示的位置 ABCDEFG/DP 對應顯示右面各個部位(低電平)
【四路共陽數碼管的控制】
四路共陽數碼管的控制我沒有找到好用的現成包,因此我這里直接自行封裝了一個,涵蓋了能顯示的數字和字母小數點,類如下,可直接復制調用:
# coding=utf-8
import sys
sys.path.append('..')
import time
import RPi.GPIO as GPIO
# 共陽4位數字管
class Yang4():
# 顯示位數
p1 = 1
p2 = 2
p3 = 3
p4 = 4
# 顯示狀態
a = 5
b = 6
c = 7
d = 8
e = 9
f = 10
g = 11
dp = 12
positionPoints = []
numberPoints = []
# 初始化並設置控制針腳
# 針腳連接順序:位置1-4,數字a-dp
def __init__(self, p1, p2, p3, p4, a, b, c, d, e, f, g, dp):
self.p1 = p1
self.p2 = p2
self.p3 = p3
self.p4 = p4
self.a = a
self.b = b
self.c = c
self.d = d
self.e = e
self.f = f
self.g = g
self.dp = dp
self.positionPoints = [p1, p2, p3, p4]
self.numberPoints = [a, b, c, d, e, f, g, dp]
# Board模式
GPIO.setmode(GPIO.BOARD)
# 關閉提示
GPIO.setwarnings(False)
for item in self.positionPoints+self.numberPoints:
GPIO.setup(item, GPIO.OUT)
# 輸入一個字符串
def Display(self, str8bit):
self.__DisplayCode(str8bit)
# 篩選並控制顯示各位置
def __DisplayCode(self, str8bit):
# 當前位置
index = -1
for i in range(0, len(str8bit)):
if index > 8:
return
arg = str(str8bit[i])
if arg == '.' and index % 2 != 0:
index = index + 1
elif arg != '.' and index % 2 != 1:
index = index + 1
index = index + 1
self.__ResetPosition()
self.__ResetNumber()
self.__DisplayNumberSwitch(arg)
GPIO.output(self.positionPoints[index//2], 1)
time.sleep(0.002)
def __ResetPosition(self):
for item in self.positionPoints:
GPIO.output(item, 0)
def __ResetNumber(self):
for item in self.numberPoints:
GPIO.output(item, 1)
def __DisplayNumberSwitch(self, arg):
# print('arg='+str(arg))
if arg == '.':
self.__Display_DOT()
# 上方小圈用小o,下方小圈用中文句號
elif arg == 'o':
self.__Display_TopCircle()
elif arg == '。':
self.__Display_DownCircle()
# -----------------------------
elif arg == '0':
self.__Display_0()
elif arg == '1':
self.__Display_1()
elif arg == '2':
self.__Display_2()
elif arg == '3':
self.__Display_3()
elif arg == '4':
self.__Display_4()
elif arg == '5':
self.__Display_5()
elif arg == '6':
self.__Display_6()
elif arg == '7':
self.__Display_7()
elif arg == '8':
self.__Display_8()
elif arg == '9':
self.__Display_9()
# -----------------------------
elif arg == 'A':
self.__Display_A()
elif arg == 'B':
self.__Display_B()
elif arg == 'C':
self.__Display_C()
elif arg == 'D':
self.__Display_D()
elif arg == 'd':
self.__Display_d()
elif arg == 'E':
self.__Display_E()
elif arg == 'F':
self.__Display_F()
elif arg == 'G':
self.__Display_G()
elif arg == 'H':
self.__Display_H()
elif arg == 'I':
self.__Display_I()
elif arg == 'J':
self.__Display_J()
elif arg == 'L':
self.__Display_L()
elif arg == 'O':
self.__Display_O()
elif arg == 'P':
self.__Display_P()
elif arg == 'S':
self.__Display_S()
elif arg == 'U':
self.__Display_U()
elif arg == 'V':
self.__Display_V()
else:
None
def __Display_DOT(self):
GPIO.output(self.dp, 0)
def __Display_TopCircle(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.g, 0)
GPIO.output(self.f, 0)
def __Display_DownCircle(self):
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.g, 0)
# -----------------------------
def __Display_0(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
def __Display_1(self):
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
def __Display_2(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.g, 0)
def __Display_3(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.g, 0)
def __Display_4(self):
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_5(self):
GPIO.output(self.a, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_6(self):
GPIO.output(self.a, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_7(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
def __Display_8(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_9(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
# -----------------------------
def __Display_A(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_B(self):
self.__Display_8()
def __Display_C(self):
GPIO.output(self.a, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
def __Display_d(self):
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.g, 0)
def __Display_D(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
def __Display_E(self):
GPIO.output(self.a, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_F(self):
GPIO.output(self.a, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_G(self):
self.__Display_6()
def __Display_H(self):
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_I(self):
self.__Display_1()
def __Display_J(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
def __Display_L(self):
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
def __Display_O(self):
self.__Display_0()
def __Display_P(self):
GPIO.output(self.a, 0)
GPIO.output(self.b, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
GPIO.output(self.g, 0)
def __Display_S(self):
self.__Display_5()
def __Display_U(self):
GPIO.output(self.b, 0)
GPIO.output(self.c, 0)
GPIO.output(self.d, 0)
GPIO.output(self.e, 0)
GPIO.output(self.f, 0)
def __Display_V(self):
self.__Display_U()
當然使用的demo也得拱手獻上:
# coding=utf-8
from GPIO.NixieTube import
# 需要的針腳對應的樹莓派GPIO針腳
# 針腳連接順序:位置1-4,數字a-dp
# 可以參考參數順序,對應數碼管定義的各個引腳 __init__(self, p1, p2, p3, p4, a, b, c, d, e, f, g, dp):
y4 = Yang4(35, 16, 22, 32, 31, 36, 38, 33, 37, 12, 18, 40)
delay = 600
# 顯示時間
while(True):
# time
timenow = datetime.datetime.now()
for i in range(0, delay):
y4.Display(str(timenow.year))
time.sleep(0.005)
for i in range(0, delay):
y4.Display(str(timenow.month).zfill(
2)+'.'+str(timenow.day).zfill(2))
time.sleep(0.005)
for i in range(0, delay):
y4.Display(str(timenow.hour).zfill(
2)+'.'+str(timenow.minute).zfill(2))
time.sleep(0.005)
y4.Display('....')
上述代碼的功能為:按一定的間隔循環顯示年月日時分。
因為數碼管實際上是無限循環展示各個需要顯示的位置,肉眼無法捕捉時間間隔很短的顯隱變化。也就是看起來顯示的年月日時分秒,真實應該是數碼管的各個小節循環在顯示,這樣就可以用幾個引腳顯示較為復雜的圖像。
【集成溫濕度數據獲取存儲和顯示】
可以操作數碼管顯示之后,我們將之前的溫濕度的數據和數碼管的顯示集成在一起(可以參考前面博文)
# coding=utf-8
from Utility.MySqlHelper import MySqlHelper
import _thread
import Adafruit_DHT
from GPIO.NixieTube import Yang4
import time
import datetime
import RPi.GPIO as GPIO
import sys
sys.path.append('..')
def WriteToDb(timenow, year, month, day, hour, temp, humi):
smartHomeDb = MySqlHelper("SmartHome")
smartHomeDb.executeSql("INSERT INTO DailyMonitor (DateTime,Year,Month,Day,Hour,Temperature,Humidity) VALUES ('{0}',{1},{2},{3},{4},{5},{6})".format(
timenow, year, month, day, hour, temp, humi))
y4 = Yang4(35, 16, 22, 32, 31, 36, 38, 33, 37, 12, 18, 40)
delay = 600
# 已經寫入數據庫的小時標識,插入數據的同時,修改為下一個小時,用於比較是否需要寫入
hasWriteToDbHour = datetime.datetime.now().hour
while(True):
# time
timenow = datetime.datetime.now()
for i in range(0, delay):
y4.Display(str(timenow.year))
time.sleep(0.005)
for i in range(0, delay):
y4.Display(str(timenow.month).zfill(
2)+'.'+str(timenow.day).zfill(2))
time.sleep(0.005)
for i in range(0, delay):
y4.Display(str(timenow.hour).zfill(
2)+'.'+str(timenow.minute).zfill(2))
time.sleep(0.005)
y4.Display('....')
# Use read_retry method. This will retry up to 15 times to
# get a sensor reading (waiting 2 seconds between each retry).
# this is bcm code
humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT11, 4)
print('time:{0},humidity:{1}%,temperature:{2}*C'.format(
datetime.datetime.now(), humidity, temperature))
# 異步將數據寫入mysql
if hasWriteToDbHour == timenow.hour:
_thread.start_new_thread(WriteToDb, (timenow, timenow.year,
timenow.month, timenow.day, timenow.hour, temperature, humidity))
if hasWriteToDbHour == 23:
hasWriteToDbHour = 0
else:
hasWriteToDbHour = hasWriteToDbHour + 1
if temperature is not None:
for i in range(0, delay):
y4.Display('{0:0.1f}C'.format(temperature))
time.sleep(0.005)
if humidity is not None:
for i in range(0, delay):
y4.Display('H{0:0.1f}'.format(humidity))
time.sleep(0.005)
上述代碼的功能:
- 循環獲取溫濕度,判斷一小時寫入數據庫一次
- 數碼管循環展示年/月日/時分/溫度/濕度
【樹莓派運行】
我們通過SSH遠程連接到樹莓派的終端
通過FTP將我們的項目上傳到樹莓派服務器
采用后台進程的方式運行我們的主腳本(關閉終端進程不會退出)
nohup python SmartHomeScreen.py
這樣我們的信息采集腳本就一直在工作中了,每小時會采集一次溫濕度,並存儲到數據庫表中。隔幾秒采集的數據同時實時顯示在數碼管上,我們抬頭便可以看到當前溫濕度。
效果圖(一張圖用到底):
【總結】
通過本節內容,我們實現了利用樹莓派的GPIO控制共陽數碼管展示溫濕度,並已經實現了我們開始規划好的溫濕度面板。
后續章節我們會介紹利用我們采集的24小時溫濕度數據制作溫濕度報表... 效果預熱: