前回まで/次回以降の取り組みはこちらから。
今度はpythonアプリが落ちる現象に悩まされました。
エラーメッセージ
朝起きたらこんなエラーが出て止まってました。
おそらく通信関係のエラーでしょう。
約2日間問題なく動いたな…と思ったらエラー、再度動かしたら12時間後に再びエラーでアプリそのものが止まっていました。
当然タイムラプスもAmbientへのデータ送信もLINE通知も止まります。
例外処理を追加
関係する部分だけメインのpythonから引っ張ってきました。
ネットワーク接続絡みのエラーなので、Ambientへのデータ送信・LINE通知・写真のアップロード部分の3か所のネットワークと何かやり取りする部分に定石通りtry~except文を仕込みました。
(Ambient→LINE→タイムラプス→Googleドライブの順番で処理します。Ambientにデータが上がっておらず、LINEに通知が来てないので、多分ですがAmbientのデータ送信部分が犯人な気がします。)
これで、どこでネットワークエラーが発生してもアプリ自体は動き続けてくれるはずです。
例外発生時には、「logging.txt」というテキストファイルにどの処理でいつエラーが発生したか気ロックさせるようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | def Ambient_send(sendtime): if(ui.checkBox_AmbientSend.checkState()==2): #Ambient送信 try: #例外でプログラム全体が落ちてしまうので対処:V1.4.1.1 amSend = ambient.Ambient(ui.lineEdit_AmbientID.text(),ui.lineEdit_AmbientKey.text()) amSend.send({'d1': temp, 'd2':humid, 'd3':press, 'd4':bright, 'd5':water, 'd6':tank}) ui.lineEditAmbientLastUpdate.setText(sendtime.strftime('%Y/%m/%d %H:%M:%S')) except: file = "./logging.txt" fileObject = open(file, "a", encoding="utf-8") fileObject.write("Connection Error! Ambient Date Send : "+"\n") fileObject.write(str(takeTime.strftime('%Y/%m/%d %H:%M:%S'))+"\n") fileObject.close() def Line_send(): if(ui.checkBox_LineSend.checkState()==2): #水分量を見てLINE通知送信 tank_TH = int(ui.spinBoxLINE.value()) if(int(tank)<tank_TH): takenUrl = 'Bearer '+str(ui.lineEdit_LineTaken.text()) headers = {'Authorization': takenUrl,} massage = str(ui.lineEdit_LineMassage.text()) massage = massage.replace('\n','') files = {'message': (None, massage),} try: #例外でプログラム全体が落ちてしまうので対処:V1.4.1.1 response = requests.post('https://notify-api.line.me/api/notify', headers=headers, files=files) except: file = "./logging.txt" fileObject = open(file, "a", encoding="utf-8") fileObject.write("Connection Error! Line Notify : "+"\n") fileObject.write(str(takeTime.strftime('%Y/%m/%d %H:%M:%S'))+"\n") fileObject.close() def Take_TimeLapse(takeTime): global TimeLapseFlagHour global TimeLapseFlagMinute if(ui.checkBox_TL.checkState()==2): if(TimeLapseFlagHour!=takeTime.hour or TimeLapseFlagMinute!=takeTime.minute): TimeLapseFlagHour = takeTime.hour TimeLapseFlagMinute = takeTime.minute camera = picamera.PiCamera() TimeLapseFilename = './timelapse/'+str(takeTime.strftime('%Y%m%d%H%M%S'))+'.jpg' camera.capture(TimeLapseFilename) camera.capture('newest.jpg') camera.close() QI = QImage('newest.jpg') ui.label_TL_Image.setPixmap(QPixmap.fromImage(QI)) ui.lineEdit_TL_LastUpdate.setText(str(takeTime.strftime('%Y/%m/%d %H:%M:%S'))) #Googleドライブ送信 if(ui.checkBox_TL_Send.checkState()==2): GoogleDriveUpload(takeTime) def GoogleDriveUpload(taketime): image = 'newest.jpg' remote = 'asagaoiot' folder = 'Asagao_IoT_TimeLapse' cmd1 = 'rclone copy /home/pi/python/asagao_iot/timelapse/'+str(taketime.strftime('%Y%m%d%H%M%S'))+'.jpg' + ' ' + remote + ':' + folder cmd2 = 'rclone copy /home/pi/python/asagao_iot/'+ image + ' ' + remote + ':' + folder try: #例外でプログラム全体が落ちてしまうので対処:V1.4.1.1 os.system(cmd1) os.system(cmd2) except: file = "./logging.txt" fileObject = open(file, "a", encoding="utf-8") fileObject.write("Connection Error! Google Drive Send : "+"\n") fileObject.write(str(takeTime.strftime('%Y/%m/%d %H:%M:%S'))+"\n") fileObject.close() |
今日はもうひとつ。
AmbientにGoogleドライブにアップした写真を表示する
こともできます。
センサで得られる情報とともに最新の状態をモニタする、的な使い方ですね。
まず、Googleドライブにアクセスして、表示したい写真を右クリック、
「共有可能なリンクを取得」をクリックします。
「リンクをコピー」をクリックすると必要なリンクをコピーした状態になります。
(「コピペ」の「コピ」状態)
下の「制限付き」の右の▼をクリックして「リンクを知っている全員」に変えます。
これで、ここに表示されているURLにアクセスするとこのファイルを見れる状態ができました。
「完了」をクリックして、Googleドライブ側の作業は終了です。
続いてAmbientのチャネルのページにアクセスします。
右上の「チャネル設定」をクリックします。
(ページを読み込み切る前にスクショを撮ってしまったのでアイコンが出てませんね…。本来ここには歯車のアイコンが表示されています。)
「Embed Code」に先ほどコピーしたリンクを貼り付けます。
貼り付けたら「チャネル属性を設定する」をクリックすると最初の画面に戻り、グラフの次に写真が表示されているはずです。
ここで「ファイル名に関係なく最新の写真を選ぶ」とかできたらよかったんですが、それができないのでGoogleドライブにアップする際に「日付時刻.jpg」という画像ファイルに加えて「newest.jpg」という常に同じ名前のファイルをアップして、最新の状態に更新し続けることにしたという経緯があります。
pythonアプリについてはしばらくこれで仮運用してみてから実際にあさがおを植えたほうがよさそうですね。
ちゃんとエラーが起こった時の処理も含めて最初から作っておくべきでした。
もうちょっと続きます。
コメント