自己动手实现智能家居之温湿度数码管展示(四位共阳数码管)

【前言】

一个热爱技术的人一定向往有一个科技感十足的环境吧,那何不亲自实践一下属于技术人的座右铭:“技术改变世界”。

就让我们一步步动手搭建一个属于自己的“智能家居平台”吧(不要对这个名词抬杠啦,技术在手,怎么设计实现因人而异),本文只做抛砖引玉,各路大神如果有更好的想法可以各显神通,当然能在评论区留下更好的想法让大家共同学习是再好不过啦。

在文章最后附有所有源代码,有需要的可以自行下载,感谢Star~

【系列目录】

  1. 树莓派GPIO简介(Python版)
  2. 温湿度数据采集存储(DHT11,MySql)
  3. 温湿度数码管展示(四位共阳数码管)
  4. 构建App展示温湿度报表(ApiCloud,Python Flask)
  5. 普通家用排插集成继电器手工改造
  6. App远程控制“自制智能”排插
  7. 使用花生棒内网穿透实现外网访问
  8. 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)

上述代码的功能:

  1. 循环获取温湿度,判断一小时写入数据库一次
  2. 数码管循环展示年/月日/时分/温度/湿度

【树莓派运行】

我们通过SSH远程连接到树莓派的终端

PI

通过FTP将我们的项目上传到树莓派服务器

采用后台进程的方式运行我们的主脚本(关闭终端进程不会退出)

nohup python SmartHomeScreen.py

这样我们的信息采集脚本就一直在工作中了,每小时会采集一次温湿度,并存储到数据库表中。隔几秒采集的数据同时实时显示在数码管上,我们抬头便可以看到当前温湿度。

效果图(一张图用到底):

【总结】

通过本节内容,我们实现了利用树莓派的GPIO控制共阳数码管展示温湿度,并已经实现了我们开始规划好的温湿度面板。

后续章节我们会介绍利用我们采集的24小时温湿度数据制作温湿度报表... 效果预热:

【源码地址】

Github:https://github.com/sevenTiny/SevenTiny.SmartHome

posted @ 2020-01-17 08:32  7tiny  阅读(1209)  评论(2编辑  收藏  举报