上篇博文<树莓派智能家居-语音聊天机器人实现>实现了树莓派的语音聊天功能,在其基础上,实现语音获取天气预报和当前温湿度。
获取天气预报
目前有现成的天气预报API,直接调用即可,代码如下:
def getWeather(city,date=0):
s=''
rb=requests.get('http://wthrcdn.etouch.cn/weather_mini?city='+city)
#print(rb.text)
data=json.loads(rb.text)
if(data['status']==1000):
d=data['data']
if(date==0):
s+=d['city']+'今天'+d['forecast'][0]['type']+','
s+=d['forecast'][0]['low'][2:]+'到'+d['forecast'][0]['high'][2:]+','
s+=d['forecast'][0]['fengxiang']+d['forecast'][0]['fengli'][8:]+','
s+='当前室外温度:'+d['wendu']+'度,'
s+=d['ganmao']
elif(date>0 and date<5):
s+=d['city']
if(date==1):
s+='明天'
elif(date==2):
s+='后天'
else:
s+=d['forecast'][date]['date']
s+=d['forecast'][date]['type']+','
s+=d['forecast'][date]['low'][2:]+'到'+d['forecast'][date]['high'][2:]+','
s+=d['forecast'][date]['fengxiang']+d['forecast'][date]['fengli'][8:]
elif(date==-1):
s+=d['city']+'昨天'+d['yesterday']['type']+','
s+=d['yesterday']['low'][2:]+'到'+d['yesterday']['high'][2:]+','
s+=d['yesterday']['fx']+d['yesterday']['fl'][8:]
else:
s='天气请求失败'
return s
输入参数:city-要获取的天气的城市名字,date-获取什么时候的天气,0表示今天。但是我们要做的是从用户说的话中获得他想知道什么城市,哪天的天气。这首先需要知道有什么城市,然后通过关键词判断用户的意图。总的代码如下:
#weather.py
import requests
import json
import re
class Weather:
cityList=[]
def __init__(self):
self.getCity()
def getCity(self):
fileName='city.txt'
with open(fileName,'r') as f:
lines=f.readlines()
for line in lines:
cities=line.split(' ')
for w in cities:
self.cityList.append(w.strip())
self.cityList.append(w.strip().replace('市',''))
def isCityExits(self,text):
isExist=False
cityName=''
#print(self.cityList)
for c in self.cityList:
if(c in text):
cityName=c
isExist=True
break
return isExist,cityName
def getWeatherByText(self,text):
result=''
#judge city in text
isCity,cityName=self.isCityExits(text)
#print(isCity)
if(isCity):
#is get weather
reStr=r'(.*?)'+cityName+r'(.*?)今天(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,0)
return result
reStr=r'(.*?)今天(.*?)'+cityName+r'(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,0)
return result
reStr=r'(.*?)'+cityName+r'(.*?)明天(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,1)
return result
reStr=r'(.*?)明天(.*?)'+cityName+r'(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,1)
return result
reStr=r'(.*?)'+cityName+r'(.*?)后天(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,2)
return result
reStr=r'(.*?)后天(.*?)'+cityName+r'(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,2)
return result
reStr=r'(.*?)'+cityName+r'(.*?)昨天(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,-1)
return result
reStr=r'(.*?)昨天(.*?)'+cityName+r'(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,-1)
return result
reStr=r'(.*?)'+cityName+r'(.*?)天气(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
result=self.getWeather(cityName,0)
return result
return result
def getWeather(self,city,date=0):
s=''
rb=requests.get('http://wthrcdn.etouch.cn/weather_mini?city='+city)
#print(rb.text)
data=json.loads(rb.text)
if(data['status']==1000):
d=data['data']
if(date==0):
s+=d['city']+'今天'+d['forecast'][0]['type']+','
s+=d['forecast'][0]['low'][2:]+'到'+d['forecast'][0]['high'][2:]+','
s+=d['forecast'][0]['fengxiang']+d['forecast'][0]['fengli'][8:]+','
s+='当前室外温度:'+d['wendu']+'度,'
s+=d['ganmao']
elif(date>0 and date<5):
s+=d['city']
if(date==1):
s+='明天'
elif(date==2):
s+='后天'
else:
s+=d['forecast'][date]['date']
s+=d['forecast'][date]['type']+','
s+=d['forecast'][date]['low'][2:]+'到'+d['forecast'][date]['high'][2:]+','
s+=d['forecast'][date]['fengxiang']+d['forecast'][date]['fengli'][8:]
elif(date==-1):
s+=d['city']+'昨天'+d['yesterday']['type']+','
s+=d['yesterday']['low'][2:]+'到'+d['yesterday']['high'][2:]+','
s+=d['yesterday']['fx']+d['yesterday']['fl'][8:]
else:
s='天气请求失败'
return s
#w=Weather()
#print(w.getWeatherByText('上海今天天气怎么样'))
其中city.txt的内容在附录。上面通过类的形式封装了天气相关操作。使用时,调用getweatherByText()函数。该函数首先判断输入文本中有没有城市名称,若存在城市名称,在通过正则表达式判断是否相应的关键词,若存在,则获取对应城市,对应日期的天气。
实时监控温湿度
dht11是一款便宜、又好用用于获取空气温湿度的传感器。 其精度湿度±5%RH, 温度±2℃,量程湿度20-90%RH, 温度0~50℃。DHT11利用单总线协议,因此有严格的时序,关系通信协议可参考
树莓派根据通信协议直接获取DHT11数据的代码如下:
#encoding=utf-8
import RPi.GPIO as GPIO
import time
import dht11
import datetime
import re
def getDHT11Data_1(dht11_pin):
isOk=True
GPIO.setmode(GPIO.BOARD)#io number with BOARD
GPIO.setup(dht11_pin, GPIO.OUT)
GPIO.output(dht11_pin, GPIO.LOW)
time.sleep(0.02) #给信号提示传感器开始工作
GPIO.output(dht11_pin, GPIO.HIGH)
GPIO.setup(dht11_pin, GPIO.IN)
while GPIO.input(dht11_pin) == GPIO.LOW:
continue
while GPIO.input(dht11_pin) == GPIO.HIGH:
continue
data=[]
j=0
while j < 40:
k = 0
while GPIO.input(dht11_pin) == GPIO.LOW:
continue
while GPIO.input(dht11_pin) == GPIO.HIGH:
k += 1
if k > 100:
break
if k < 8:
data.append(0)
else:
data.append(1)
j += 1
humidity_bit = data[0:8] #分组
humidity_point_bit = data[8:16]
temperature_bit = data[16:24]
temperature_point_bit = data[24:32]
check_bit = data[32:40]
humidity = 0
humidity_point = 0
temperature = 0
temperature_point = 0
check = 0
for i in range(8):
humidity += humidity_bit[i] * 2 ** (7 - i) #转换成十进制数据
humidity_point += humidity_point_bit[i] * 2 ** (7 - i)
temperature += temperature_bit[i] * 2 ** (7 - i)
temperature_point += temperature_point_bit[i] * 2 ** (7 - i)
check += check_bit[i] * 2 ** (7 - i)
tmp = humidity + humidity_point + temperature + temperature_point #十进制的数据相加
if check == tmp:#数据校验,相等则输出
print ("temperature : ", temperature, ".", temperature_point, ", humidity : " , humidity, ".", humidity_point)
else:
#错误输出错误信息,和校验数据
isOk=False
print ("DHT11 Get Wrong")
print ("temperature : ", temperature, ", humidity : " , humidity, " check : ", check, " tmp : ", tmp)
GPIO.cleanup()
return isOk,temperature,temperature_point,humidity,humidity_point
树莓派上面跑着一个linux系统,由于进程调用的缘故并不严格服从DHT11通信的时序,因此这样直接写代码获取数据很容易出错。szazo的github项目解决了这个问题,使用他的代码可以准确的得到DHT11的数据。此外同上面获取天气的情况一样,需要通过关键词判断用户的意图,总的代码如下:
#getDHT11.py
#encoding=utf-8
import RPi.GPIO as GPIO
import time
import dht11
import datetime
import re
class GetDHT11:
isOk=True
def __init__(self,dht11_pin):
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BOARD)
self.instance = dht11.DHT11(pin=dht11_pin)
def __del__(self):
GPIO.cleanup()
def getDataDHT11(self):
result = self.instance.read()
if result.is_valid():
self.isOk=True
return result.temperature,result.humidity
else:
self.isOk=False
return 0,0
def getIsOk(self):
return self.isOk
def getTemperatureAndHumidityByText(self,text):
reStr=r'(.*?)现在(.*?)温度(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
t,h=do.getDataDHT11()
if(do.getIsOk()):
result='当前温度'+str(int(t))+'摄氏度,空气湿度百分之'+str(h)
return result
reStr=r'(.*?)现在(.*?)湿度(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
t,h=do.getDataDHT11()
if(do.getIsOk()):
result='当前温度'+str(int(t))+'摄氏度,空气湿度百分之'+str(h)
return result
eStr=r'(.*?)当前(.*?)温度(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
t,h=do.getDataDHT11()
if(do.getIsOk()):
result='当前温度'+str(int(t))+'摄氏度,空气湿度百分之'+str(h)
return result
reStr=r'(.*?)当前(.*?)湿度(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
t,h=do.getDataDHT11()
if(do.getIsOk()):
result='当前温度'+str(int(t))+'摄氏度,空气湿度百分之'+str(h)
return result
reStr=r'(.*?)此(.*?)温度(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
t,h=do.getDataDHT11()
if(do.getIsOk()):
result='当前温度'+str(int(t))+'摄氏度,空气湿度百分之'+str(h)
return result
reStr=r'(.*?)此(.*?)湿度(.*?)'
obj=re.search(reStr,text,re.M|re.I)
if(obj!=None):
t,h=do.getDataDHT11()
if(do.getIsOk()):
result='当前温度'+str(int(t))+'摄氏度,空气湿度百分之'+str(h)
return result
return ''
主程序
在上一篇博文写的基础上,代码修改如下:
from weather import Weather
from speech import *
from voice import *
from chatbot import *
from getDHT11 import GetDHT11
from microrecord import *
import time
mp3FileName='dialog.mp3'
wavFileName='dialog.wav'
dht11_pin=12
do=GetDHT11(dht11_pin)
wobj=Weather()
def getResponse(text):
output_text=''
#get weather
output_text=wobj.getWeatherByText(text)
if(len(output_text)>0):
t,h=do.getDataDHT11()
if(do.getIsOk()):
output_text+='当前温度'+str(int(t))+'摄氏度,空气湿度百分之'+str(h)
else:
output_text=do.getTemperatureAndHumidityByText(text)
if(len(output_text)==0):
output_text=chat(text)
return output_text
while True:
getMicroRecord(wavFileName)
input_text=speechRecognition(wavFileName)
print('input:'+input_text)
if(len(input_text)==0):
break
output_text=getResponse(input_text)
if(speechSynthesis(output_text,mp3FileName)):
playMp3ByShell(mp3FileName)
print('output:'+output_text)
print('dialog done')
效果还是可以的。
附录:city.txt
河南省
郑州市 洛阳市 焦作市 商丘市 信阳市 周口市 鹤壁市 安阳市 濮阳市 驻马店市
南阳市 开封市 漯河市 许昌市 新乡市 济源市 灵宝市 偃师市 邓州市 登封市 三门峡市
新郑市 禹州市 巩义市 永城市 长葛市 义马市 林州市 项城市 汝州市 荥阳市
平顶山市 卫辉市 辉县市 舞钢市 新密市 孟州市 沁阳市 郏县
安徽省
合肥市 亳州市 芜湖市 马鞍山市 池州市 黄山市 滁州市 安庆市
淮南市 淮北市 蚌埠市 宿州市 宣城市 六安市 阜阳市
铜陵市 明光市 天长市 宁国市 界首市 桐城市 潜山市
福建省
福州市 厦门市 泉州市 漳州市 南平市 三明市 龙岩市 莆田市
宁德市 建瓯市 武夷山市 长乐市 福清市 晋江市 南安市 福安市
龙海市 邵武市 石狮市 福鼎市 建阳市 漳平市 永安市
甘肃省
兰州市 白银市 武威市 金昌市 平凉市 张掖市 嘉峪关市 酒泉市
庆阳市 定西市 陇南市 天水市 玉门市 临夏市 合作市 敦煌市 甘南州
贵州省
贵阳市 安顺市 遵义市 六盘水市 兴义市 都匀市 凯里市 毕节市 清镇市
铜仁市 赤水市 仁怀市 福泉市
海南省
海口市 三亚市 万宁市 文昌市 儋州市 琼海市 东方市 五指山市
河北省
石家庄市 保定市 唐山市 邯郸市邢台市 沧州市 衡水市 廊坊市 承德市 迁安市
鹿泉市 秦皇岛市 南宫市 任丘市 叶城市 辛集市 涿州市 定州市 晋州市 霸州市
黄骅市 遵化市 张家口市 沙河市 三河市 冀州市 武安市 河间市深州市 新乐市
泊头市 安国市 双滦区 高碑店市
黑龙江省
哈尔滨市 伊春市 牡丹江市 大庆市 鸡西市 鹤岗市 绥化市 齐齐哈尔市
黑河市 富锦市 虎林市 密山市 佳木斯市 双鸭山市 海林市 铁力市 北安市
五大连池市 阿城市 尚志市 五常市 安达市 七台河市 绥芬河市 双城市
海伦市 宁安市 讷河市 穆棱市 同江市 肇东市
湖北省
武汉市 荆门市 咸宁市 襄阳市 荆州市 黄石市 宜昌市 随州市
鄂州市 孝感市 黄冈市 十堰市 枣阳市 老河口市 恩施市 仙桃市
天门市 钟祥市 潜江市 麻城市 洪湖市 汉川市 赤壁市 松滋市
丹江口市 武穴市 广水市 石首市大冶市 枝江市 应城市 宜城市
当阳市 安陆市 宜都市 利川市
湖南省
长沙市 郴州市 益阳市 娄底市 株洲市 衡阳市 湘潭市
岳阳市 常德市 邵阳市 永州市 张家界市 怀化市 浏阳市
醴陵市 湘乡市 耒阳市 沅江市 涟源市 常宁市 吉首市
津市市 冷水江市 临湘市 汨罗市 武冈市 韶山市 湘西州
吉林省
长春市 吉林市 通化市 白城市 四平市 辽源市 松原市 白山市
集安市 梅河口市 双辽市 延吉市 九台市 桦甸市 榆树市 蛟河市
磐石市 大安市 德惠市 洮南市 龙井市 珲春市 公主岭市 图们市
舒兰市 和龙市 临江市 敦化市
江苏省
南京市 无锡市 常州市 扬州市 徐州市 苏州市 连云港市 盐城市
淮安市 宿迁市 镇江市 南通市 泰州市 兴化市 东台市 常熟市
江阴市 张家港市 通州市 宜兴市 邳州市 海门市 溧阳市 泰兴市
如皋市 昆山市 启东市 江都市 丹阳市 吴江市 靖江市 扬中市
新沂市 仪征市 太仓市 姜堰市 高邮市 金坛市 句容市 灌南县
江西省
南昌市 赣州市 上饶市 宜春市 景德镇市 新余市 九江市 萍乡市
抚州市 鹰潭市 吉安市 丰城市 樟树市 德兴市 瑞金市 井冈山市
高安市 乐平市 南康市 贵溪市 瑞昌市 东乡县 广丰县 信州区 三清山
辽宁省
沈阳市 葫芦岛市 大连市 盘锦市 鞍山市 铁岭市 本溪市 丹东市
抚顺市 锦州市 辽阳市 阜新市 调兵山市 朝阳市 海城市 北票市
盖州市 凤城市 庄河市 凌源市 开原市 兴城市 新民市 大石桥市
东港市 北宁市 瓦房店市 普兰店市 凌海市 灯塔市 营口市
青海省
西宁市 格尔木市 德令哈市
山东省
济南市 青岛市 威海市 潍坊市 菏泽市 济宁市 东营市烟台市
淄博市 枣庄市 泰安市 临沂市 日照市 德州市 聊城市 滨州市
乐陵市 兖州市 诸城市 邹城市 滕州市 肥城市 新泰市 胶州市
胶南市 即墨市 龙口市 平度市 莱西市
山西省
太原市 大同市 阳泉市 长治市 临汾市 晋中市 运城市 忻州市
朔州市 吕梁市 古交市 高平市 永济市 孝义市 侯马市 霍州市
介休市 河津市 汾阳市 原平市 晋城市 潞城市
陕西省
西安市 咸阳市 榆林市 宝鸡市 铜川市 渭南市 汉中市 安康市
商洛市 延安市 韩城市 兴平市 华阴市
四川省
成都市 广安市 德阳市 乐山市 巴中市 内江市 宜宾市 南充市
都江堰市 自贡市 泸州市 广元市达州市 资阳市 绵阳市 眉山市
遂宁市 雅安市 阆中市 攀枝花市 广汉市 绵竹市 万源市 华蓥市
江油市 西昌市 彭州市 简阳市 崇州市 什邡市 峨眉山市 邛崃市 双流县
云南省
昆明市 玉溪市 大理市 曲靖市 昭通市 保山市 丽江市 临沧市 楚雄市
开远市 个旧市 景洪市 安宁市 宣威市
浙江省
杭州市 宁波市 绍兴市 温州市 台州市 湖州市 嘉兴市 金华市 舟山市
衢州市 丽水市 余姚市 乐清市 临海市 温岭市 永康市 瑞安市 慈溪市
义乌市 上虞市 诸暨市 海宁市 桐乡市 兰溪市 龙泉市 建德市 富德市
富阳市 平湖市 东阳市 嵊州市 奉化市 临安市 江山市
台湾省
台北市 台南市 台中市 高雄市 桃源市
广东省
广州市 深圳市珠海市 汕头市 佛山市 韶关市 湛江市 肇庆市 江门市 茂名市 惠州市 梅州市 汕尾市 河源市 阳江市 清远市 东莞市 中山市 潮州市 揭阳市 云浮市
自治区编辑
广西壮族自治区
南宁市 贺州市 玉林市 桂林市 柳州市 梧州市 北海市 钦州市 百色市
防城港市 贵港市 河池市 崇左市 来宾市 东兴市 桂平市 北流市
岑溪市 合山市 凭祥市 宜州市
内蒙古自治区
呼和浩特市 呼伦贝尔市 赤峰市 扎兰屯市 鄂尔多斯市 乌兰察布市
巴彦淖尔市 二连浩特市 霍林郭勒市 包头市 乌海市 阿尔山市
乌兰浩特市 锡林浩特市 根河市 满洲里市 额尔古纳市 牙克石市
临河市 丰镇市 通辽市
宁夏回族自治区
银川市 固原市 石嘴山市 青铜峡市 中卫市 吴忠市 灵武市
西藏藏族自治区
拉萨市 那曲市 山南市 林芝市 昌都市 阿里地区日喀则市
新疆维吾尔自治区
乌鲁木齐市 石河子市 喀什市 阿勒泰市 阜康市 库尔勒市 阿克苏市
阿拉尔市 哈密市 克拉玛依市 昌吉市 奎屯市 米泉市 和田市
香港 澳门
北京市 上海市 天津市 重庆市