本帖最后由 云天 于 2024-1-22 20:19 编辑
行空直播 弹幕物控
【项目背景】
本项目想实现从万物互联到万物可视。通过实景智能直播将智能技术与直播相结合实现新型直播方式,通过实时采集、编辑和传输实景数据,实现更加真实、生动的直播效果。并可通过弹幕留言来实现远程控制浇水、喂食等功能。 【项目设计】
平时,会全家出远门,一走好几天。家里的花和猫都处于无人照顾的情况。有时会给花一次性浇很多水,给猫放很多的猫粮和水。花还好,就是猫,每次回来都会胖很多。
想通过网络查看家里的情况,并能通过远程控制的方式,给花浇水、给猫喂食。远程控制可以使用物联网,查看图像可使用网络摄像头。那怎么将两者结合,我想到了直播。
【项目方案】
1.使用B站直播,获取服务器地址和直播码。2.使用opencv库获取摄像头图像,使用FFmpeg进程,将视频数据通过管道传递给RTMP推流B站,进行直播。
3.通过Pinpong库获取温湿度传感器、土壤湿度传感器数值,并通过“ImageDraw”库将中文及传感器数值绘制在画面上。
4.使用浏览器“开发者工具”,获取cookies和headers。
5.通过requests库的get方法,获取直播弹幕留言,并通过pinpong库控制舵机及电磁继电器。
【硬件装置】
行空板加扩展板,温湿度传感器接P1引脚,土壤湿度传感器接P4引脚,光照传感器接P10引脚。两舵机分别引脚P8、P9。电磁继电器和蓝光LED分别接P20、P19引脚。
土壤湿度传感器插入花盆土壤中。
水泵出水口有夹子固定到花盆里。
水泵电源接电磁继电器
摄像头接行空板USB口,并固定在直播架上。
【获取直播推流码】
【直播推流】
行空板自带了ffmpeg库,可直接使用。
- import cv2
-
- import subprocess
-
- # 设置摄像头参数
- capture = cv2.VideoCapture(0)
- capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
- capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
-
- # RTMP推流地址
- url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=*****************&schedule=rtmp&pflag=1'
-
- # 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
- cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
- 'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
- p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
-
- # 循环读取摄像头数据,将数据写入管道中
- while True:
- ret, frame = capture.read()
- if not ret:
- break
-
- p.stdin.write(frame.tostring())
-
- # 关闭进程和摄像头
- p.communicate()
- p.stdin.close()
- capture.release()
复制代码
【实时数据显示】
通过Pinpong库获取温湿度传感器、土壤湿度传感器数值,并通过“ImageDraw”库将中文及传感器数值绘制在画面上。
-
- import cv2
-
- import subprocess
- from PIL import ImageFont,ImageDraw,Image
- import numpy as np
- from pinpong.board import DHT11
- from pinpong.board import Board
- from pinpong.board import Pin
-
-
- Board().begin()
- pin1 = Pin(Pin.P1)
- dht1 = DHT11(pin1)
- pin0 = Pin(Pin.P4, Pin.ANALOG)
- pin2 = Pin(Pin.P2, Pin.ANALOG)
- # 设置摄像头参数
- capture = cv2.VideoCapture(0)
- capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
- capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
-
- # RTMP推流地址
- url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=*********************&schedule=rtmp&pflag=1'
-
- # 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
- cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
- 'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
- p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
-
- # 循环读取摄像头数据,将数据写入管道中
- while True:
- ret, frame = capture.read()
- if not ret:
- break
- #cv2.putText(frame, "hello", (100, 100), cv2.FONT_HERSHEY_COMPLEX, 1,(255,0,0),1)
- frame=Image.fromarray(frame)
- font1=ImageFont.truetype("./msyh.ttc",50)
- draw=ImageDraw.Draw(frame)
- draw.text((10,10),"温度:"+str(dht1.temp_c())+" 湿度:"+str(dht1.humidity()),font=font1,fill=(0,0,255))
- draw.text((10,400),"光照:"+str(pin2.read_analog())+" 土湿度:"+str(pin0.read_analog()),font=font1,fill=(0,0,255))
- frame=np.array(frame)
- p.stdin.write(frame.tostring())
-
- # 关闭进程和摄像头
- p.communicate()
- p.stdin.close()
- capture.release()
复制代码
【获取直播信息】
使用浏览器“开发者工具”,获取cookies和headers。
1.复制信息
2.使用Convert curl commands to Python (curlconverter.com)网站工具,将信息转换为python可用数据。
(cookies信息有效期为7天)
【弹幕控制】
通过requests库的get方法,获取直播弹幕留言。
-
- import requests
- import time
- import random
- import json
-
-
- def send_Danmu():
- watertime=""
- liketime=""
- watertimetem=""
- liketimetem=""
- while True:
-
- cookies = {**************}
-
- headers = {**************}
-
- response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
- json_data=response.text
-
- data=json.loads(json_data)
- if data["code"]==0:
- texts=data["data"]["room"]
- for text in texts :
- if text["nickname"]=="创客云天":
- if text["text"]=="浇水":
- if text["timeline"]!=watertimetem:
- watertimetem=text["timeline"]
-
- if text["text"]=="[牛]":
- if text["timeline"]!=liketimetem:
- liketimetem= text["timeline"]
-
- if watertimetem!=watertime:
- watertime=watertimetem
- print("浇水")
- if liketimetem!=liketime:
- liketime=liketimetem
- print("[牛]")
- time. sleep(21)#冷却时间,可以自己调
- send_Danmu()
复制代码
并通过pinpong库控制舵机及电磁继电器。-
- from pinpong.board import Board
- from pinpong.board import Pin
- import requests
- import time
- import random
- import json
- Board().begin()
- pin20 = Pin(Pin.P20, Pin.OUT)
- pin19 = Pin(Pin.P19, Pin.OUT)
- def send_Danmu():
-
- watertime=""
- liketime=""
- watertimetem=""
- liketimetem=""
- bs=0
- timekg=time.time()
- timefw=time.time()
- while True:
- if time.time()-timefw>5:
- timefw=time.time()
- cookies = {**************}
-
- headers = {**************}
-
- response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
- json_data=response.text
-
- data=json.loads(json_data)
- if data["code"]==0:
- texts=data["data"]["room"]
- for text in texts :
- if text["nickname"]=="创客云天":
- if text["text"]=="浇水":
- if text["timeline"]!=watertimetem:
- watertimetem=text["timeline"]
-
- if text["text"]=="[牛]":
- if text["timeline"]!=liketimetem:
- liketimetem= text["timeline"]
-
- if watertimetem!=watertime:
- if bs==0:
- watertime=watertimetem
- pin20.value(1)
- pin19.value(1)
- timekg=time.time()
- bs=1
- print("开始浇水 ")
- if liketimetem!=liketime:
- liketime=liketimetem
- print("[牛]")
- if time.time()-timekg>3:
- if bs==1:
- timekg=time.time()
- pin20.value(0)
- pin19.value(0)
- bs=0
- print("停止浇水 ")
-
- send_Danmu()
复制代码
增加控制舵机功能-
- from pinpong.board import Board,Servo
- from pinpong.board import Pin
- import requests
- import time
- import random
- import json
- Board().begin()
- pin20 = Pin(Pin.P20, Pin.OUT)
- pin19 = Pin(Pin.P19, Pin.OUT)
- pin20.value(0)
- pin19.value(0)
- s1 = Servo(Pin(Pin.P8))
- s2 = Servo(Pin(Pin.P9))
- def send_Danmu():
-
- watertime=""
- liketime=""
- watertimetem=""
- liketimetem=""
- bs=0
- bs2=0
- timekg=time.time()
- timefw=time.time()
- timedj=time.time()
- while True:
- if time.time()-timefw>5:
- timefw=time.time()
- cookies = {******************}
-
- headers = {******************}
-
- response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
- json_data=response.text
-
- data=json.loads(json_data)
- if data["code"]==0:
- texts=data["data"]["room"]
- for text in texts :
- if text["nickname"]=="创客云天":
- if text["text"]=="浇水":
- if text["timeline"]!=watertimetem:
- watertimetem=text["timeline"]
-
- if text["text"]=="[牛]":
- if text["timeline"]!=liketimetem:
- liketimetem= text["timeline"]
-
- if watertimetem!=watertime:
- if bs==0:
- watertime=watertimetem
- pin20.value(1)
- pin19.value(1)
- timekg=time.time()
- bs=1
- print("开始浇水 ")
- if liketimetem!=liketime:
- liketime=liketimetem
- s1.angle(60) #控制舵机转到0度位置
- s2.angle(60) #控制舵机转到0度位置
- timedj=time.time()
- bs2=1
- print("开始摆动")
- if time.time()-timekg>3:
- if bs==1:
- timekg=time.time()
- pin20.value(0)
- pin19.value(0)
- bs=0
- print("停止浇水 ")
- if time.time()-timedj>3:
- if bs2==1:
- timedj=time.time()
- s1.angle(120) #控制舵机转到0度位置
- s2.angle(120) #控制舵机转到0度位置
- bs2=0
- print("停止摆动")
-
- send_Danmu()
复制代码
【完整代码】
将直播与弹幕控制程序结合-
- import cv2
-
- import subprocess
- from PIL import ImageFont,ImageDraw,Image
- import numpy as np
- from pinpong.board import DHT11
- from pinpong.board import Board,Servo
- from pinpong.board import Pin
- import requests
- import time
- import random
- import json
- from unihiker import GUI
- u_gui=GUI()
- 显示1=u_gui.draw_text(text="行空板",x=30,y=10,font_size=40, color="#0000FF")
- 显示2=u_gui.draw_text(text="直播控制",x=10,y=80,font_size=40, color="#FF0000")
- 显示3=u_gui.draw_text(text="",x=10,y=180,font_size=40, color="#00FF00")
-
- Board().begin()
- pin20 = Pin(Pin.P20, Pin.OUT)
- pin19 = Pin(Pin.P19, Pin.OUT)
- pin20.value(0)
- pin19.value(0)
- s1 = Servo(Pin(Pin.P8))
- s2 = Servo(Pin(Pin.P9))
- pin1 = Pin(Pin.P1)
- dht1 = DHT11(pin1)
- pin4 = Pin(Pin.P4, Pin.ANALOG)
- pin10 = Pin(Pin.P10, Pin.ANALOG)
-
- watertime=""
- liketime=""
- watertimetem=""
- liketimetem=""
- bs=0
- bs2=0
- timekg=time.time()
- timefw=time.time()
- timedj=time.time()
-
- # 设置摄像头参数
- capture = cv2.VideoCapture(0)
- capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
- capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
-
- # RTMP推流地址
- url = 'rtmp://live-push.bilivideo.com/live-bvc/?streamname=live_511218715_31018533&key=**************************&schedule=rtmp&pflag=1'
-
- # 启动FFmpeg进程,将视频数据通过管道传递给RTMP推流
- cmd = ['ffmpeg', '-y', '-f', 'rawvideo', '-pix_fmt', 'bgr24', '-s', '640x480', '-i', '-', '-c:v', 'libx264', '-pix_fmt', \
- 'yuv420p', '-preset', 'ultrafast', '-f', 'flv', url]
- p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
-
- # 循环读取摄像头数据,将数据写入管道中
- while True:
- ret, frame = capture.read()
- if not ret:
- break
- #cv2.putText(frame, "hello", (100, 100), cv2.FONT_HERSHEY_COMPLEX, 1,(255,0,0),1)
- frame=Image.fromarray(frame)
- font1=ImageFont.truetype("./msyh.ttc",50)
- draw=ImageDraw.Draw(frame)
- draw.text((10,10),"温度:"+str(dht1.temp_c())+" 湿度:"+str(dht1.humidity()),font=font1,fill=(0,0,255))
- draw.text((10,400),"光照:"+str(pin10.read_analog())+" 土湿度:"+str(pin4.read_analog()),font=font1,fill=(0,0,255))
- frame=np.array(frame)
- p.stdin.write(frame.tostring())
- if time.time()-timefw>5:
- timefw=time.time()
- cookies = {***********************************}
-
- headers = {***********************************}
-
- response = requests.get('https://api.live.bilibili.com/xlive/web-room/v1/dM/gethistory?roomid=23994618&room_type=0', cookies=cookies, headers=headers)
- json_data=response.text
-
- data=json.loads(json_data)
- if data["code"]==0:
- texts=data["data"]["room"]
- for text in texts :
- if text["nickname"]=="创客云天":
- if text["text"]=="浇水":
- if text["timeline"]!=watertimetem:
- watertimetem=text["timeline"]
- 显示3.config(text=text["nickname"])
- if text["text"]=="[牛]":
- if text["timeline"]!=liketimetem:
- liketimetem= text["timeline"]
- 显示3.config(text=text["nickname"])
-
- if watertimetem!=watertime:
- if bs==0:
- watertime=watertimetem
- pin20.value(1)
- pin19.value(1)
- timekg=time.time()
- bs=1
- print("开始浇水 ")
- if liketimetem!=liketime:
- liketime=liketimetem
- s1.angle(60) #控制舵机转到0度位置
- s2.angle(120) #控制舵机转到0度位置
- pin20.value(1)
- timedj=time.time()
- bs2=1
- print("开始摆动")
- if time.time()-timekg>3:
- if bs==1:
- timekg=time.time()
- pin20.value(0)
- pin19.value(0)
- bs=0
- print("停止浇水 ")
- if time.time()-timedj>3:
- if bs2==1:
- timedj=time.time()
- s1.angle(120) #控制舵机转到0度位置
- s2.angle(60) #控制舵机转到0度位置
- pin20.value(0)
- bs2=0
- print("停止摆动")
- # 关闭进程和摄像头
- p.communicate()
- p.stdin.close()
- capture.release()
复制代码
【演示视频】
|