はじめに
年末に家のタワー型のサーバ・ノートパソコンが一度に壊れてしまい、ごった煮環境の復旧に勤しんで新しい事に手が回ってませんでしたが、復旧が一段落してきたので前からやりたかったRabbitMQメッセージの通知アプリを作ってみました。
#タイトルにラズパイとJulius入れてますが、ホントに添えてるだけですスミマセン。
構成・動作
去年、ラズパイにUSBカメラと赤外線LEDをつなげて、音声認識でテレビを操作する感じのプチ電子工作環境を構築していたので、この環境に追加する感じでWindowsアプリを作ってみました。
※注 図以外にも色々と詰め込んでいて、ちょっと複雑な構成になっています。
データの流れは、以下のような感じ。
- USBカメラの内蔵マイクから入力した音声データをJuliusで認識。
- 認識した結果を自作のJuliusClientアプリで解釈・スコアの判定を行い、一定以上のスコアで「テレビ電源ON」と認識したら、RabbitMQにメッセージ送信。
- LIRCコマンドを発行するPythonアプリがRabbitMQからメッセージを受取りIRコマンドを実行。
- テレビに電源ONの信号を送信。
⇒2で送られるメッセージをノートパソコン側でも受信して、メッセージをポップアップさせました。
出来た
ポップアップはGrowlを使ってこんな感じになりました。
Growlお手軽で使いやすい!!
動作環境
-
Raspberry PI
- RabbitMQ 2.8.4
-
Windows10
- Python2.7(※)
- pika 0.10.0 # RabbitMQ接続
- pywin32 220 # Windowsサービス実装
- gntp 1.0.3 # Growlへの通知
- Growl 2.0.9
- Python2.7(※)
※Python3で作ったけど、Windowsのシステム環境変数のPATHは諸事情でPython2のパスを登録していて簡単に変えることは出来なかったので、Python2で動作してます。。
ちなみにpywin32のインストール・使い方でちょいハマりました。先駆者の方々の情報に感謝です。
pythonでのWindowsサービスの書き方
自分で作った Python スクリプトを Windows Server にサーヴィスとして登録するショートコント(1)
Python3.4でpywin32が動かなかったこと ―
Python、pywin32でWindowsサービスが起動できない
あとGrowlについてはこちらを参考にさせて頂きました。(パスワードは不要でした、環境差異かな?)
Windows で Growl 通知を行う
ソースコード
ソース丸ごと貼っつけます。動いてますが、色々と適当なのはご容赦です。
なにげにpikaでRabbitMQに接続する時は、これまでBlockingConnectionに頼り切っていたので、
ジェネレータを使って回すのは初めてでした。
import logging
import logging.handlers
import pika
import win32serviceutil
import win32service
import win32event
import servicemanager
from gntp.notifier import GrowlNotifier
# ログ
LOG_FILE_PATH = 'C:\\tmp\win_notification_consumer.log'
LOG_BK_COUNT = 2
LOG_LEVEL = logging.INFO
# MQ
MQ_IP = "x.x.x.x"
MQ_QUEUE = "Queue2"
# 通知
GROW_IP = "127.0.0.1"
GROW_PASS = None
GROW_APP_NAME = "amqp notif"
GROW_NOTIFS = ["Message"]
GROW_NOTE_TYPE = "Message"
GROW_TITLE = "Get Message"
# Windowsサービス
WIN_SRV_NAME = "WinNotificationConsumer"
WIN_DISP_NAME = "WinNotificationConsumer"
class WinNotificationConsumer(win32serviceutil.ServiceFramework):
# Required Attributes:
_svc_name_ = WIN_SRV_NAME
_svc_display_name_ = WIN_DISP_NAME
def __init__(self, args):
# ログ初期化
self.logger = logging.getLogger()
self.logger.setLevel(LOG_LEVEL)
formatter = logging.Formatter(
'%(asctime)s - %(levelname)s - %(message)s')
handler = logging.handlers.TimedRotatingFileHandler(
filename=LOG_FILE_PATH,
when='D',
backupCount=LOG_BK_COUNT
)
handler.setLevel(logging.DEBUG)
handler.setFormatter(formatter)
self.logger.addHandler(handler)
self.logger.debug('init log end.')
# Win32API周り初期化
win32serviceutil.ServiceFramework.__init__(self, args)
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
self.logger.debug('init win32 end.')
# 通知の初期化
self.notifier = GrowlNotifier(
applicationName=GROW_APP_NAME,
notifications=GROW_NOTIFS,
hostname=GROW_IP,
password=GROW_PASS)
self.notifier.register()
self.logger.debug('init notif end.')
def SvcDoRun(self):
# service start
self.logger.info('service starting...')
# イベントログ出力
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, 'test')
)
self.consuming_and_notificate()
def consuming_and_notificate(self):
self.logger.debug('consuming and notificate starting...')
# RabbitMQの接続設定
self.connection = pika.BlockingConnection(
pika.ConnectionParameters(host=MQ_IP)
)
self.channel = self.connection.channel()
# キューが無ければ作成
self.channel.queue_declare(
queue=MQ_QUEUE,
durable=True
)
# キューから取得したメッセージをgeneratorで回す。
self.logger.info('start consuming message.')
for msg in self.channel.consume(queue=MQ_QUEUE, no_ack=True):
message_body = msg[2]
self.logger.debug(message_body)
self.notifier.notify(noteType=GROW_NOTE_TYPE,
title=GROW_TITLE,
description=message_body)
def SvcStop(self):
# service stop
self.logger.info('service stopping...')
# 上位クラスのメソッドを利用
self.ReportServiceStatus(
win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.stop_event)
# MQ切断
self.channel.close()
self.connection.close()
self.logger.info('service stopped.')
def main():
# 引数('start','stop','install' etc.)を元にサービス起動/登録/停止/削除等を実行。
win32serviceutil.HandleCommandLine(WinNotificationConsumer)
if __name__ == '__main__':
main()
Windowsサービス登録
こんな感じで登録&自動起動できます。
C:\\Python27\python.exe win_notification.py --auto install
所感
結構かんたんにやりたいことが出来た(ポップアップに関してはGrowl様々感)。RabbitMQをWindowsサービスから接続しっぱなしに出来たので、パソコンも音声操作で色々出来る気がしてきた。
あとは他のPythonアプリについても何か書きたいな…既存コードはリファクタしなきゃ見せられたもんじゃないけども…。