思路端午放假,本想注册个美团众包骑自行车送外卖体验一下生活,奈何这几天北京热的要死,只能作罢,还是苟在屋里空调续命吧。无事干的时候,想着给我花盆监控升个级,换个电容的土壤检测(
之前的腐蚀了gg了
)但是电容的是3v的,esp8266只能检测1v的,所以买了一个新的esp32-cam,正好带个摄像头,间隔5分钟拍个照片,一天下来还能拼接一个延时摄影的效果,奈何这个板子有点毛病,跑不起来,如下图(商家也无法解决)无奈退货(有大哥知道这个怎么解决麻烦指导一下小弟
),想着下雨天打孩子,闲着也是闲着,这条路走不通了,换个其他的玩玩了。我的树莓派有个风扇,成天在转,给他加一个控制,超出设定的温度再启动,最好在给个页面去控制一下,开搞还有就是这个树莓派我买的时候400,我靠这玩意还涨价了,无语了,当时400我都觉得贵,还不如买个单片机30块就能玩
设备控制-远程控制启停后台定时任务-定时记录温度,根据设定的温度控制风扇启停服务处理请求-展示温度曲线来个流程图吧graph TB subgraph 服务器 id1[页面控制指令]-.http请求.->id2{开关控制/最大温度} id2-.开关控制.->id3[控制风扇] id3-.风扇状态写入.->id4 id2-.最大温度写入.->id4[数据库] end subgraph 定时任务 id5[定时任务]<-.读取信息.->id4 id5-.定时任务.->id7[控制启停] end需要考虑的问题
当前的实现是用python来写的,我不想每次重启设备后都要ssh上去再使用命令行启动,问了公司大神给了个解决方案:systemctl,可以实现开机自启,使用方式如下,想了解更多可以看:https://ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html当人为了防止程序挂掉,或者我退出以后停了,使用了nohup让python脚本一直在后太运行如何控制风扇启停呢?树莓派上带了不少Gpio的接口,但是输出的电流只能点亮个led带不动风扇,所以我们需要一个三极管,我买的是1. 配置方式和使用方法(当前的解决方案)s8050
NPN的有两种别买错了
,pnp是接在地线上的,用流程图画一个接线图吧
,意思一下得了markdown
不知道怎么画电路图
/etc/systemd/system 增加对应的文件
(资料图片仅供参考)
fanServer.service
[Unit]Description=test deamonAfter=rc-local.service[Service]Type=simpleUser=rootGroup=rootWorkingDirectory=文件的路径ExecStart=nohup python3 -u processRequest.py > service.log 2>&1 &Restart=always[Install]WantedBy=multi-user.target
fan.service
[Unit]Description=test deamonAfter=rc-local.service[Service]Type=simpleUser=rootGroup=rootWorkingDirectory=文件所在的路径ExecStart=nohup python3 -u index.py > fan.log 2>&1 &Restart=always[Install]WantedBy=multi-user.target
启动
sudo systemctl start fan.servicesudo systemctl start fanServer.service
添加到开机自启
sudo systemctl enable fan.servicesudo systemctl enable fanServer.service
2. 接线图graph LR zheng[正极] zheng-.正极.->yongdianqi yongdianqi[风扇] yongdianqi-.地线.->sanjiguan sanjiguan[三极管] sanjiguan-.地线.->dixian dixian[接地] gpio[gpio]-.高电开/低电关.->sanjiguan现在看一下效果吧 > 接线的效果图如图二正片干货结束无聊的实现时间意思一下得了哈,效果看图片
全部代码地址:https://github.com/dadademo/piFan
设备控制(网页端)设备控制主要就是:1. 展示数据 2. 发送设备控制指令
代码如下(太多了给个链接吧)写个vue的页面,用脑子设计一下:开关按钮得有,温度设定得有,还得有个图表,还得加个筛选时间,根据时间来筛选数据。就酱式的吧
https://github.com/dadademo/piFan/blob/main/fanUi/src/components/home.vue
后台定时任务后台定时任务:1. 定时读取任务,根据设定的温度决定是否开/关风扇 2. 定时记录信息,将信息存在数据里面
定时任务python代码这些服务本来想用node写,奈何node操作gpio的库一直不能下载,只能用python来搞了
注意
这个代码我是直接复制的,依赖一些我写的其他的python脚本,如果想跑起来的话还直接拉全部代码去看吧这里就是用python启动一个服务,接收网页发送的请求,例如设定温度,还有启停的制冷
这里就是每隔5分钟读取一次温度,超过了就启动风扇,没超过就停止
# 使用内建的signal库捕获Ctrl+Cimport signal# 风扇模块import controlFan# 退出程序import sys# 引用db模块import dbimport time# 开始时间beginTimeHour = 7# 结束时间endTimeHour = 20# 每隔5分钟判断一次温度timeOut = 60*5# 程序停止def stop(): # 停止gpio操作 controlFan.quit() # 退出程序 sys.exit()controlFan.init_gpio()# 监听Ctr+Csignal.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.serverimport socketserver# json对象import json# 参数解析from urllib.parse import urlparse, parse_qs, parse_qslimport dbimport controlFan# 定义端口号HTTP_PORT = 3001# 获取query信息并转为objdef 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里面也有对应的操作,想网访问的话可以看我上一篇文章,有对应的链接,就不再这里哔哔了