• 闲来无事-树莓派控制风扇启停


    扯淡时间

    端午放假,本想注册个美团众包骑自行车送外卖体验一下生活,奈何这几天北京热的要死,只能作罢,还是苟在屋里空调续命吧。
    无事干的时候,想着给我花盆监控升个级,换个电容的土壤检测(之前的腐蚀了gg了)但是电容的是3v的,esp8266只能检测1v的,所以买了一个新的esp32-cam,正好带个摄像头,间隔5分钟拍个照片,一天下来还能拼接一个延时摄影的效果,奈何这个板子有点毛病,跑不起来,如下图(商家也无法解决)

    无奈退货(有大哥知道这个怎么解决麻烦指导一下小弟),想着下雨天打孩子,闲着也是闲着,这条路走不通了,换个其他的玩玩了。
    我的树莓派有个风扇,成天在转,给他加一个控制,超出设定的温度再启动,最好在给个页面去控制一下,开搞
    还有就是这个树莓派我买的时候400,我靠这玩意还涨价了,无语了,当时400我都觉得贵,还不如买个单片机30块就能玩

    思路

    1. 设备控制-远程控制启停
    2. 后台定时任务-定时记录温度,根据设定的温度控制风扇启停
    3. 服务处理请求-展示温度曲线

    来个流程图吧

    定时任务
    服务器
    http请求
    开关控制
    风扇状态写入
    最大温度写入
    读取信息
    定时任务
    定时任务
    控制启停
    开关控制/最大温度
    页面控制指令
    控制风扇
    数据库

    需要考虑的问题

    1. 当前的实现是用python来写的,我不想每次重启设备后都要ssh上去再使用命令行启动,问了公司大神给了个解决方案:systemctl,可以实现开机自启,使用方式如下,想了解更多可以看:https://ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html
      当人为了防止程序挂掉,或者我退出以后停了,使用了nohup让python脚本一直在后太运行
    2. 如何控制风扇启停呢?树莓派上带了不少Gpio的接口,但是输出的电流只能点亮个led带不动风扇,所以我们需要一个三极管,我买的是s8050NPN的有两种别买错了,pnp是接在地线上的,用流程图画一个接线图吧,意思一下得了markdown不知道怎么画电路图

    1. 配置方式和使用方法(当前的解决方案)

    /etc/systemd/system 增加对应的文件

    fanServer.service

    [Unit]
    Description=test deamon
    After=rc-local.service
    
    [Service]
    Type=simple
    User=root
    Group=root
    WorkingDirectory=文件的路径
    ExecStart=nohup python3 -u processRequest.py > service.log 2>&1 &
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    

    fan.service

    [Unit]
    Description=test deamon
    After=rc-local.service
    
    [Service]
    Type=simple
    User=root
    Group=root
    WorkingDirectory=文件所在的路径
    ExecStart=nohup python3 -u index.py > fan.log 2>&1 &
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    

    启动

    sudo systemctl start  fan.service
    sudo systemctl start  fanServer.service
    

    添加到开机自启

    sudo systemctl enable fan.service
    sudo systemctl enable fanServer.service
    

    2. 接线图

    正极
    地线
    地线
    高电开/低电关
    正极
    风扇
    三极管
    接地
    gpio

    意思一下得了哈,效果看图片

    现在看一下效果吧

    图片名称 图片名称 > 接线的效果图如图二

    正片干货结束无聊的实现时间

    全部代码地址:https://github.com/dadademo/piFan

    设备控制(网页端)

    设备控制主要就是:1. 展示数据 2. 发送设备控制指令

    写个vue的页面,用脑子设计一下:开关按钮得有,温度设定得有,还得有个图表,还得加个筛选时间,根据时间来筛选数据。就酱式的吧

    代码如下(太多了给个链接吧)

    https://github.com/dadademo/piFan/blob/main/fanUi/src/components/home.vue

    后台定时任务

    后台定时任务:1. 定时读取任务,根据设定的温度决定是否开/关风扇 2. 定时记录信息,将信息存在数据里面

    这些服务本来想用node写,奈何node操作gpio的库一直不能下载,只能用python来搞了
    注意这个代码我是直接复制的,依赖一些我写的其他的python脚本,如果想跑起来的话还直接拉全部代码去看吧
    这里就是用python启动一个服务,接收网页发送的请求,例如设定温度,还有启停的制冷

    定时任务python代码

    这里就是每隔5分钟读取一次温度,超过了就启动风扇,没超过就停止

    
    # 使用内建的signal库捕获Ctrl+C
    import signal
    # 风扇模块
    import controlFan
    # 退出程序
    import sys
    # 引用db模块
    import db
    import time
    
    
    # 开始时间
    beginTimeHour = 7
    # 结束时间
    endTimeHour = 20
    
    # 每隔5分钟判断一次温度
    timeOut = 60*5
    
    
    
    # 程序停止
    def stop():
        # 停止gpio操作
        controlFan.quit()
        # 退出程序
        sys.exit()
    
    controlFan.init_gpio()
    
    # 监听Ctr+C
    signal.signal(signal.SIGINT, stop)
    while True:
        # 0/1 当前风扇状态
        fanStatus = 0
        # 设定状态,默认40度
        setTemp = 0
        # 获取状态
        lastData = db.getLastData()
        fanStatus =  lastData.get('fanStatus')
        setTemp = lastData.get('setTemp')
    
        # 获取当前温度
        currentTemp = controlFan.read_cpu_temperature()
        # 时间
        currentTime = time.localtime()
        dt = time.strftime('%Y:%m:%d %H:%M:%S', currentTime)
        print(dt)
        # 当前温度大于设定温度
        ctrlVal = currentTemp > setTemp
        # 判断逻辑
        if ctrlVal:
            fanStatus = 1
        else:
            fanStatus = 0
        # 初始化后追加状态
        db.addInfo(fanStatus, currentTemp, setTemp)
        if ctrlVal:
            # 夜间模式
            if currentTime.tm_hour < beginTimeHour and currentTime.tm_hour > endTimeHour:
                controlFan.set_fan(False)
            else:
                controlFan.set_fan(True)
        else:
            controlFan.set_fan(False)
        time.sleep(timeOut)
    
    服务端python的代码

    这里就是用python启动一个服务,接收网页发送的请求,例如设定温度,还有启停的风扇指令,写这个代码还了解了一下python的数据类型,赚到了
    代码如下

    # 导入http.server模块
    import http.server
    import socketserver
    
    # json对象
    import json
    
    # 参数解析
    from urllib.parse import urlparse, parse_qs, parse_qsl
    
    import db
    import controlFan
    
    # 定义端口号
    HTTP_PORT = 3001
    
    # 获取query信息并转为obj
    
    
    def getQureyData(url):
        retObj = {}
        currentQuery = parse_qs(urlparse(url).query)
        for key in currentQuery:
            if len(currentQuery[key]) == 1:
                retObj[key] = currentQuery[key][0]
            else:
                retObj[key] = currentQuery[key]
        return retObj
    
    
    # 处理相应
    class httpResponse(http.server.SimpleHTTPRequestHandler):
        # 处理get请求
        def do_GET(self):
            # 当前访问的链接决定
            currentUrl = urlparse(self.path).path
            print(currentUrl)
            if currentUrl == '/getFan':
                self.send_response(200)
                self.send_header('Content-type', 'application/json')
                self.end_headers()
                # 读取信息
                query = getQureyData(self.path)
                jsonInfo = db.getInfo(
                    query.get('startTimestamp'), query.get('endTimestamp'), query.get('pageIndex'), query.get('pageSize'), query.get('all'))
    
                retStr = json.dumps(jsonInfo)
                self.wfile.write(bytes(retStr, "utf8"))
    
            if currentUrl == '/getLast':
                self.send_response(200)
                self.send_header('Content-type', 'application/json')
                self.end_headers()
                jsonInfo = db.getLastData()
                retStr = json.dumps(jsonInfo)
                self.wfile.write(bytes(retStr, "utf8"))
            return
    
        # 处理post请求
        def do_POST(self):
            # 获取POST请求的数据
            currentUrl = urlparse(self.path).path
            if currentUrl == '/setFan':
                self.send_response(200)
                self.send_header('Content-type', 'application/json')
                self.end_headers()
                # 当前信息
                query = getQureyData(self.path)
                # 获取最后的信息
                lastData = db.getLastData()
                fanStatus = int(query.get('fanStatus')
                                or lastData.get('fanStatus'))
                setTemp = int(query.get('setTemp') or lastData.get('setTemp'))
                print(fanStatus, fanStatus == 1)
                # 写入状态
                db.addInfo(fanStatus, controlFan.read_cpu_temperature(), setTemp)
    
                if fanStatus == 1:
                    controlFan.set_fan(True)
                else:
                    controlFan.set_fan(False)
    
                self.wfile.write(bytes("{status:200}", "utf8"))
            return
    
    
    # 启动http服务
    def beginServer():
        with socketserver.TCPServer(("", HTTP_PORT), httpResponse) as httpd:
            print("serving at port", HTTP_PORT)
            httpd.serve_forever()
    
    controlFan.init_gpio()
    # 开启服务
    beginServer()
    

    主要逻辑就这么多,全部的代码看git的地址吧,readme里面也有对应的操作,想网访问的话可以看我上一篇文章,有对应的链接,就不再这里哔哔了

  • 相关阅读:
    查找算法【平衡二叉树】 - 原理 AVL树详解
    挂耳式蓝牙耳机哪家的好用,推荐几款实用的挂耳式耳机
    (arxiv-2018) 重新审视基于视频的 Person ReID 的时间建模
    java计算机毕业设计美容院业务管理系统源码+系统+mysql数据库+lw文档
    箱讯科技成功闯入第八届“创客中国”全国总决赛—在国际物流领域一枝独秀
    封装的方法固定的参数,特殊环境下需要多带参数
    数据驱动农业农村现代化-国稻种芯-万祥军:谋定标准化生产
    数字签名标准(DSS)
    网页采集工具-免费的网页采集工具
    为什么有了并发安全的集合还需要读写锁?
  • 原文地址:https://www.cnblogs.com/niexianda/p/17506382.html