ラズパイと対話する植物と自称IoT女子
こんにちは。ガリガリ君梨味ばっかり食べてます。五十嵐a.k.a自称IoT女子です😋
五十嵐a.k.a.自称IoT女子
2016入社☝️大学院で花の遺伝子を研究するも、日本のインダストリー4.0に夢中となり、その実現を目指す&その恩恵を直接受けるべく4月より入社し奮闘中✊💥💨
三度の飯よりでんぱ組.inc⚡️
前回うっかり自称を付け忘れてしまいましたが(IT農業とセンサーとIoT女子)、まだ自称IoT女子です😟
うっかりうっかり~(分かる人だけ分かればいいN●K番組ネタ)
そして今回は予告の通りの「slackと音声出力と自称IoT女子」ではありません。
さっくり、「対話する植物と自称IoT女子」でお送りします。
今回結構長いのですがお付き合いくださいませ。
前回はIT農業に必要なセンサーをつなぎ、データを取得しました。
今回はそのデータをslackに送って、遠隔で植物の状態を管理する、ということをやってみます。
ついでに、植物と対話できるようにしています😀
こんな感じでおはなしできるようにします
実行したコードたち
上段2つのコードをもとに、下段のコードを作成し、実行しました。

Googleに音声データを送るコード[gsa.py]
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import json
import urllib.parse
import urllib.request
class GoogleSpeechApi(object):
endpoint = "http://www.google.com/speech-api/v2/recognize"
def __init__(self,
api_key):
self.api_key = api_key
def send(self,
file_name="test.wav",
output="json",
lang="ja-JP"):
"""Google Cloud Speech APIに音声ファイルを送る
"""
query_string = {"output": output,
"lang": lang,
"key": self.api_key}
query = urllib.parse.urlencode(query_string)
url = "{0}?{1}".format(self.endpoint, query)
with open(file_name, "rb") as f:
voice_data = f.read()
headers = {"Content-Type": "audio/l16; rate=16000"}
request = urllib.request.Request(url, data=voice_data, headers=headers)
response = urllib.request.urlopen(request).read().decode('utf-8')
return self.parse_json(response)
def parse_json(self, jsn_str):
"""Google Cloud Speech APIから来たデータをパースする
"""
transcripts = []
for s in jsn_str.split("\n"):
if not s:
continue
js = json.loads(s)
if not js["result"]:
continue
elif not js["result"][0]["alternative"]:
return None
for r in js["result"][0]["alternative"]:
transcripts.append(r["transcript"])
return transcripts
音声データを録音するコード[rec.py]
# -*- coding: utf-8 -*-
import pyaudio
import wave
import time
class Rec(object):
frames = []
def __init__(self,
format=pyaudio.paInt16,
channels=1,
rate=16000,
chunk=2**11,
input=True,
record_seconds=3):
self.format = format
self.channels = channels
self.rate = rate
self.chunk = chunk
self.input = input
self.record_seconds = record_seconds
self.audio = pyaudio.PyAudio()
def callback(self, in_data, frame_count, time_info, status):
"""コールバック関数
"""
self.frames.append(in_data)
return(None, pyaudio.paContinue)
def record(self,
is_comment=True,
output_filename="test.wav"):
"""録音する関数
"""
stream = self.audio.open(format=self.format,
channels=self.channels,
rate=self.rate,
input=self.input,
stream_callback=self.callback)
if is_comment is True:
print("録音開始")
stream.start_stream()
time.sleep(self.record_seconds)
stream.stop_stream()
stream.close()
if is_comment is True:
print("録音終了")
with wave.open(output_filename, "wb") as f:
f.setnchannels(self.channels)
f.setsampwidth(self.audio.get_sample_size(self.format))
f.setframerate(self.rate)
f.writeframes(b"".join(self.frames))
self.frames = []
return self
センサーの値を取得して判定し、Slack、スピーカーに結果を出力するコード[sensor.py]
import os
import sys
import glob
import time
import datetime
import re
import subprocess
import spidev
import Adafruit_DHT
from slacker import Slacker
import RPi.GPIO as GPIO
from rec import Rec
from gsa import GoogleSpeechApi
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
TMP_DIR = BASE_DIR + "/tmp"
VOICE_DIR = BASE_DIR + "/voices"
class Sensor(object):
def __init__(self, switch_pin=18):
# SWITCH
self.switch_pin = switch_pin
GPIO.setup(self.switch_pin, GPIO.IN)
self.spi = spidev.SpiDev()
self.spi.open(0, 0)
def get_switch_status(self):
return GPIO.input(self.switch_pin)
def get_temp_and_humid(self, sensor=11, pin=4):
"""温度湿度センサー(DHT11)から温度と湿度を取得する
"""
# 湿度と温度を取得
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
# 湿度と温度が正常に取得できていたら、値を返す
if humidity is not None and temperature is not None:
return (temperature, humidity)
else:
print('Failed to get reading. Try again!')
sys.exit(1)
def get_moisture(self, channel):
"""ADCの指定したチャンネルのデータを取得する
--------------
パラメータ:
channel ADCのチャンネル番号
--------------
返り値:
整数 ADCの指定したチャンネルの値
"""
adc = self.spi.xfer2([1,(8+channel)<<4,0])
data = ((adc[1]&3) << 8) + adc[2]
return data
def get_current_time(self):
"""現在時刻を取得する
"""
now = datetime.datetime.now()
current_time = now.strftime("%Y-%m-%d %H:%M:%S")
return current_time
def get_sensor_data(self):
"""センサーデータを取得する
"""
(temp, humid) = self.get_temp_and_humid()
moisture = self.get_moisture(0)
time = self.get_current_time()
return {"temp": temp, "humid": humid, "moisture": moisture, "time": time}
def judge_health(self, moisture):
"""乾燥しているかどうかを判定する
"""
if moisture > 900:
return "very_dry"
elif moisture > 700:
return "dry"
elif moisture > 500:
return "good"
elif moisture > 400:
return "wet"
else:
return "very_wet"
if __name__ == '__main__':
GPIO.setmode(GPIO.BOARD)
sensor = Sensor()
rec = Rec()
GPIO.setmode(GPIO.BOARD)
sensor = Sensor()
rec = Rec()
gsa = GoogleSpeechApi("******Google APIキー******")
slack = Slacker("******Slack APIキー******")
pre_status = 0
while True:
# ボタンが押しっぱなしだったら終了
if pre_status > 3:
break
# ボタンが押されたかを調べる
button_current = sensor.get_switch_status()
# ボタンを押していたら中を実行
if button_current:
# ボタンが押されたばかりだった場合に実行
if pre_status == 1:
# センサーデータを取得
data = sensor.get_sensor_data()
# 録音
rec.record(output_filename=TMP_DIR + "/tmp.wav")
# 録音された音声ファイルをGoogle Cloud Speech API に投げる
word_candidate = gsa.send(file_name=TMP_DIR + "/tmp.wav")
# テキストの候補を一つ一つ調べる
for w in word_candidate:
# 乾 の文字が候補になったら、中を実行
if re.search("乾", w):
# 水分量の状態を調べる
health = sensor.judge_health(data["moisture"])
if health == "very_wet":
moisture_text = "よっぱらだて!"
elif health == "wet":
moisture_text = "多すぎらてば"
elif health == "good":
moisture_text = "いい塩梅だねっか"
elif health == "dry":
moisture_text = "もうちっとばかもらえねえかね"
elif health == "very_dry":
moisture_text = "水が足らねんと!"
# 表示/Slackに送るメッセージを決定する
message = "{}の状態をお知らせいたし候!\n室温は{}℃、湿度は{}%、{}。"
message = message.format(data["time"], data["temp"], data["humid"], moisture_text)
# メッセージを表示する
print(message)
# メッセージをSlackに送る
slack.chat.post_message(channel="it_agriculture_data",
text=message)
# 水分量に応じて、音声ファイルを再生する
subprocess.run(["aplay", VOICE_DIR + "/" + health + ".wav"])
break
pre_status += 1
else:
pre_status = 0
GPIO.cleanup()
Google APIキーと Slack APIキー の取得方法は今回は割愛します。
こうなりました。
Slackでもお話してくれます
更に、slackのほうでメイさん(新潟出身)が新潟弁でNMD(ナンマイドン)の様子をお知らせしてくれます👇

ちょうどいい水分量だそうです👍
~メイさん(新潟出身)とは~
新潟県新発田市出身(新潟県の中で随一強めの方言を話す地域。ここの方言は話す人が話すと脅しにしか聞こえない。)好きな食べ物はルマンド。
HTS Voice “Mei”
released by MMDAgent Project Team
http://www.mmdagent.jp/
Copyright (c) 2009-2015 Nagoya Institute of Technology
Department of Computer Science
次回
さて、私はこの週末にSORACOMさんのハンズオンイベントに参加してきます🚴
次回はその様子をレポートしたいと思います😺
ちなみにはじめてLTをさせていただくので、緊張して滑舌がとんでもないことにならないかが一番不安です!😺
☆IoT女子のギャグはウケるのか―――――――――!
テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!
Follow @twitterRecommends
こちらもおすすめ
-
自称IoT 女子が先端コンテンツ技術展でVR👓体験してきた
2016.7.8
-
去るIoT女子は日々に疎し
2016.11.2
-
【終了しました】Tech Night Vol.11開催
2018.9.30
-
自称IoT女子、Arduinoはじめました😈
2016.9.5
-
自称IoT女子がLTをやりまして・・・夏~SORACOM夏の電子工作祭り編~
2016.8.24
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28

AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16

