ラズパイと対話する植物と自称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
こちらもおすすめ
-
【終了しました】Tech Night Vol.11開催
2018.9.30
-
自称SORACOM女子編~ハンズオンに行きました~
2016.8.9
-
痛い意味ではなくSORACOMで植物と会話した話👍
2016.10.17
-
新卒 IoT 女子、自称やめるってよ
2016.7.20
-
サーバーと可視化と自称IoT女子
2016.11.1
-
去るIoT女子は日々に疎し
2016.11.2
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28
AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16