こんにちは('ω')ノ
2年目社員のTachanです。
先日の記事ですが、たくさんの方に見ていただきました。
ありがとうございます。
https://cloudsolution.terilogy.com/
今回は、人生初の開発物、「デジタルサイネージ」について書いていきたいと思います!! ( ・´ー・`)ドヤァ
今回の記事の目次です。
デジタルサイネージの概要、用途
デジタルサイネージとは何でしょうか。
普段よく見るのに、用語は入社してから知りました…。
デジタルサイネージとは、紙ではなく電子による広告のことで、新しい情報伝達媒体として利用されています。
駅やショッピングモールなどで見かることが多いです。
これを会社用に開発して、来社いただいたお客様に見てもらえるようなデジタルサイネージを作ろう!ということで開発計画が始まりました。
ですが、例のウイルスの影響により、お客様向けではなく、社内の情報共有に利用することになりました。
アラーΣ(゚Д゚)
(一番の目的は、私のpythonのスキル習得なので問題なしです!)
構成図、運用方法
今回の開発で使用したものは、
- Raspberry pi
- モニター
- コンセントタイマー
です。
大まかな構成はこのようにしました。
処理の流れとしては
- コンセントタイマーで指定時間に通電し、Raspberry piを起動
- cronでスクリプトを実行
- cronで指定時間にシャットダウン実行
- コンセントタイマーで指定時間に通電を遮断
となります。
詳しい処理は3で書きます。
④を行う理由ですが、ラズパイは電気を流すことで起動します。
終了後に遮断しておかないと、起動する手段が無くなります。
コードの処理内容
コード作成にあたり、次のモジュールやソフトウェアを使いました。
①pdfminer
pythonのモジュールで、PDFファイルからテキストを抽出することができます。
また、総ページ数のカウントが可能です。
今回は、ページのカウント機能を使いました。
②evince
複数のドキュメント形式(PDF、Postscriptなど)に対応したオープンソースのドキュメントビュアーです。
プレゼンテーションモードで表示することも可能です。
今回はevinceを実行してコンテンツを画面表示させました。
③xautomation
LinuxのX Windows Systemを制御し、キーボード・マウス自動入力などができるオープンソースのアプリケーションソフトウェアです。
evinceだけだと表示するだけでスライドの移動ができないため、この機能でマウスをぽちぽちさせることで次のスライドに進めます。
以下が実際のコードです。
- #!/usr/bin/python
- import glob
- from pdfminer.pdfparser import PDFParser
- from pdfminer.pdfdocument import PDFDocument
- from pdfminer.pdfpage import PDFPage
- from subprocess import check_output
- import subprocess
- import os
- import sys
- import time
- class croncheck(object):
- def __init__(self, cmd):
- self.cmd = cmd
- def cron_check(self):
- try:
- res = subprocess.Popen(self.cmd, shell=True, stdout=subprocess.PIPE)
- stdout,strerr = res.communicate()
- res_decode = stdout.decode('utf-8')
- res_str = int(res_decode)
- if res_str > 2: #another cron exists
- return True
- else: #any cron does not exist
- return False
- except Exception as e:
- with open('フルパスのファイル名', mode='a') as f:
- f.write(str(e) + '\n')
- return False
- class files_and_pages(object):
- def __init__(self):
- self.FileList = []
- self.Pagenumber = []
- def get_files_and_pagenumber(self):
- files = glob.glob(os.path.dirname(os.path.abspath(__file__)) + "/PDF/*.pdf") #get all pdf name
- for file in files:
- fp = open(file, 'rb')
- parser = PDFParser(fp)
- document = PDFDocument(parser)
- num_pages = 0
- for page in PDFPage.create_pages(document): #count page number
- num_pages += 1
- self.FileList.append(file) #append to Filelist
- self.Pagenumber.append(num_pages) #append to page number
- print(self.FileList, self.Pagenumber)
- class evince_and_pid(object):
- def __init__(self, t, w):
- self.t = t
- self.w = w
- def do_evince(self):
- print(len(File_and_Pages.FileList))
- for i in range(len(File_and_Pages.FileList)):
- Pages = File_and_Pages.Pagenumber[i]
- PID1 = self.get_pid('evince', '') #get current evince pid
- print(PID1)
- args = ['evince', '-s', File_and_Pages.FileList[i]]
- args_mousemove = ['xte', 'mousemove 900, 510, 900, 510']
- args_mouseclick = ['xte', 'mouseclick 1']
- print(File_and_Pages.FileList[i], Pages)
- res = subprocess.Popen(args) #execute evince
- time.sleep(self.t)
- PID2 = self.get_pid('evince', PID1) #get new evince pid
- print(PID2)
- print(PID1, PID2)
- if PID1 != None:
- self.kill_pid(int(PID1), 9)
- PID1 = PID2
- for j in range(Pages): #move on to the next slide
- print(File_and_Pages.FileList[i] + str(j))
- res_mousemove = subprocess.call(args_mousemove)
- time.sleep(self.w)
- res_mouseclick = subprocess.call(args_mouseclick)
- sys.exit()
- def get_pid(self, name, last_pid):
- try:
- pid_byte = check_output(["pidof",name]) #return byte type
- pid_str = pid_byte.decode('utf-8') #change to standard character code(can't compare byte with string)
- pid_array = pid_str.split(' ') #separate with space
- if len(pid_array) == 0:
- return
- else:
- for current_pid in pid_array:
- current_pid = current_pid.replace('\n', '')
- if current_pid != last_pid: #lastpid = PID1
- return current_pid
- except:
- return
- return check_output(["pidof",name])
- def kill_pid(self, pid, number):
- if pid != None:
- os.kill(pid, number)
- def signage_loop():
- if Cron_Check.cron_check(): #another cron exists
- sys.exit()
- else: #if cron does not exit, execute follow
- File_and_Pages.get_files_and_pagenumber()
- Evince_and_pid.do_evince()
- if __name__ == "__main__":
- CRON = 'ps -aux | grep 実行ファイル名.py | grep -v -w vi | grep -v -w nano | grep -v -w grep | wc -l'
- TIME = 3
- WAIT = 15
- File_and_Pages =files_and_pages()
- Evince_and_pid = evince_and_pid(TIME, WAIT)
- Cron_Check = croncheck(CRON)
- signage_loop()
難しかった処理は、PIDの取得と多重起動チェックの処理です。
PIDでは、コマンドを実行するとByte型で返ってくるので、その値を変数に入れたい場合、UTF-8に変換する必要がありました。
見た目が同じでも文字コードが違うことに全く気づけず、時間がかかってしまいました。
多重起動チェックでは、if文の条件式にうまく入らず、1分おきにcronを実行していたので実行ファイルが複数動いてしまいました。
原因は、def signage_loop内の書き方ミス、def cron_check内の条件式のミスでした。
諸先輩方のご協力でなんとか修正することができました…(__)
さいごに
今回の開発を通して、pythonのスキル習得、構成図の書き方、段取りを学びました。
構成図や段取りは他の業務にも生かしていきたいと思います。
デジタルサイネージの今後としては、この機能を拡張して、社内の情報共有を活発にさせたいと思います!
最後までお読みいただきありがとうございました。
- カテゴリ:
- 技術コラム