ラズパイと対話する植物と自称IoT女子

こんにちは。ガリガリ君梨味ばっかり食べてます。五十嵐a.k.a自称IoT女子です😋

profile_image五十嵐a.k.a.自称IoT女子
2016入社☝️大学院で花の遺伝子を研究するも、日本のインダストリー4.0に夢中となり、その実現を目指す&その恩恵を直接受けるべく4月より入社し奮闘中✊💥💨
三度の飯よりでんぱ組.inc⚡️

前回うっかり自称を付け忘れてしまいましたが(IT農業とセンサーとIoT女子)、まだ自称IoT女子です😟

うっかりうっかり~(分かる人だけ分かればいいN●K番組ネタ)

 

そして今回は予告の通りの「slackと音声出力と自称IoT女子」ではありません。

さっくり、「対話する植物と自称IoT女子」でお送りします。

今回結構長いのですがお付き合いくださいませ。

 

 

前回はIT農業に必要なセンサーをつなぎ、データを取得しました。

今回はそのデータをslackに送って、遠隔で植物の状態を管理する、ということをやってみます。

ついでに、植物と対話できるようにしています😀

 

こんな感じでおはなしできるようにします

現在のIoT概要

 

実行したコードたち

上段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(ナンマイドン)の様子をお知らせしてくれます👇

メイさん2

ちょうどいい水分量だそうです👍

 

~メイさん(新潟出身)とは~

新潟県新発田市出身(新潟県の中で随一強めの方言を話す地域。ここの方言は話す人が話すと脅しにしか聞こえない。)好きな食べ物はルマンド。


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利用料$100ドル無料

あなたにおすすめの記事