2019年08月01日 めざましじゃんけん結果
個人の実験的な試行内容であり、めざましじゃんけんの結果を保証したり、全ての結果が記載を保証するものではありません。
2019年08月01日のめざましじゃんけんの結果をベストエフォートで公開します。
Goo(グー) Choki(チョキ) Pa(パー)
回次 | 結果 | |
---|---|---|
(木曜日) | 07時58分 | |
07時35分 | ||
06時58分 | ||
05時58分 |
個人の実験的な試行内容であり、めざましじゃんけんの結果を保証したり、全ての結果が記載を保証するものではありません。
2019年08月01日のめざましじゃんけんの結果をベストエフォートで公開します。
Goo(グー) Choki(チョキ) Pa(パー)
回次 | 結果 | |
---|---|---|
(木曜日) | 07時58分 | |
07時35分 | ||
06時58分 | ||
05時58分 |
1秒より短いスリープを利用したい場面もあると思います。
「usleep」を利用しようとしましたが、Raspberry Piでは利用出来ませんでした。当然初期状態では、「sleepenh」もインストールされていませんでした。
root@raspberrypi:~# usleep -bash: usleep: コマンドが見つかりません root@raspberrypi:~# sleepenh -bash: sleepenh: コマンドが見つかりません
sleepenh利用時には、一秒以下は小数点で指定する必要があります。
root@raspberrypi:~# apt-get install sleepenh パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 以下のパッケージが自動でインストールされましたが、もう必要とされていません: libboost-system1.62.0 libboost-thread1.62.0 libreoffice-gtk2 これを削除するには 'apt autoremove' を利用してください。 以下のパッケージが新たにインストールされます: sleepenh アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 0 個。 8,912 B のアーカイブを取得する必要があります。 この操作後に追加で 26.6 kB のディスク容量が消費されます。 取得:1 http://ftp.tsukuba.wide.ad.jp/Linux/raspbian/raspbian buster/main armhf sleepenh armhf 1.7-1 [8,912 B] 8,912 B を 2秒 で取得しました (3,950 B/s) 以前に未選択のパッケージ sleepenh を選択しています。 (データベースを読み込んでいます ... 現在 161139 個のファイルとディレクトリがインストールされています。) .../sleepenh_1.7-1_armhf.deb を展開する準備をしています ... Isleepenh (1.7-1) を展開しています... sleepenh (1.7-1) を設定しています ... man-db (2.8.5-2) のトリガを処理しています ... root@raspberrypi:~# sleepenh -h Usage: sleepenh [[--warp|-w] INITIALTIME] TIMETOSLEEP An enhanced sleep program. Options: -h, --help display this help and exit -w, --warp warp resulting timestamp, when there is no need to sleep. An immediately following call of sleepenh with the resulting TIMESTAMP would most probably result in a real sleep. -V, --version output version information and exit TIMETOSLEEP is in seconds, microsecond resolution, ex: 80.123456. INITIALTIME is the output value of a previous execution of sleepenh. root@raspberrypi:~# sleepenh 0.5 1563487094.854379 root@raspberrypi:~# sleepenh 1 1563487105.724811 root@raspberrypi:~# sleepenh 10 1563487119.604938 root@raspberrypi:~# exit exit Script done, file is sleepenh.log
個人の実験的な試行内容であり、めざましじゃんけんの結果を保証したり、全ての結果が記載を保証するものではありません。
2019年07月31日のめざましじゃんけんの結果をベストエフォートで公開します。
Goo(グー)
Choki(チョキ)
Pa(パー)
回次 | 結果 | |
---|---|---|
(水曜日) | 07時58分 | |
07時35分 | ||
06時58分 | ||
05時58分 |
開発自体は、できる限り手間をかけずに各種実装を進めているのですが、プログラム言語により各種フレームワークが準備されております。
最近の利用実態は分かりませんが、以前はPHPのPEARは、各所で利用されておりました。
Raspberry Piに導入した際の手順を公開します。
マニュアルでインストールしようとしたのですが、apt-getしたソフトで全く問題なかったので、簡単な手順となりました。
DBを例に、個別の機能をインストールする際の例も記載しております。
sudo apt-get install php-pear sudo pear update-channels sudo pear upgrade-all sudo pear install DB
導入時点では、以下のパッケージがインストールされていました。
以下、コマンド抜粋です。
@raspberrypi:~ $ sudo apt-get install php-pear [sudo] パスワード: パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています 状態情報を読み取っています... 完了 php-pear はすでに最新バージョン (1:1.10.6+submodules+notgz-1.1) です。 php-pear は手動でインストールしたと設定されました。 アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 0 個。 @raspberrypi:~ $ pear -h Commands: build Build an Extension From C Source bundle Unpacks a Pecl Package channel-add Add a Channel channel-alias Specify an alias to a channel name channel-delete Remove a Channel From the List channel-discover Initialize a Channel from its server channel-info Retrieve Information on a Channel channel-login Connects and authenticates to remote channel server channel-logout Logs out from the remote channel server channel-update Update an Existing Channel clear-cache Clear Web Services Cache config-create Create a Default configuration file config-get Show One Setting config-help Show Information About Setting config-set Change Setting config-show Show All Settings convert Convert a package.xml 1.0 to package.xml 2.0 format cvsdiff Run a "cvs diff" for all files in a package cvstag Set CVS Release Tag download Download Package download-all Downloads each available package from the default channel info Display information about a package install Install Package list List Installed Packages In The Default Channel list-all List All Packages list-channels List Available Channels list-files List Files In Installed Package list-upgrades List Available Upgrades login Connects and authenticates to remote server [Deprecated in favor of channel-login] logout Logs out from the remote server [Deprecated in favor of channel-logout] makerpm Builds an RPM spec file from a PEAR package package Build Package package-dependencies Show package dependencies package-validate Validate Package Consistency pickle Build PECL Package remote-info Information About Remote Packages remote-list List Remote Packages run-scripts Run Post-Install Scripts bundled with a package run-tests Run Regression Tests search Search remote package database shell-test Shell Script Test sign Sign a package distribution file svntag Set SVN Release Tag uninstall Un-install Package update-channels Update the Channel List upgrade Upgrade Package upgrade-all Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters] Usage: pear [options] command [command-options] <parameters> Type "pear help options" to list all options. Type "pear help shortcuts" to list all command shortcuts. Type "pear help version" or "pear version" to list version information. Type "pear help <command>" to get the help for the specified command. @raspberrypi:~ $ sudo pear update-channels Updating channel "doc.php.net" could not create lock file: fopen(/usr/share/php/.lock): failed to open stream: Permission denied Updating channel "pear.php.net" could not create lock file: fopen(/usr/share/php/.lock): failed to open stream: Permission denied Updating channel "pecl.php.net" could not create lock file: fopen(/usr/share/php/.lock): failed to open stream: Permission denied miki@raspberrypi:~ $ sudo pear update-channels Updating channel "doc.php.net" Update of Channel "doc.php.net" succeeded Updating channel "pear.php.net" Update of Channel "pear.php.net" succeeded Updating channel "pecl.php.net" Update of Channel "pecl.php.net" succeeded @raspberrypi:~ $ sudo pear upgrade-all Will upgrade channel://pear.php.net/console_getopt Will upgrade channel://pear.php.net/archive_tar Will upgrade channel://pear.php.net/pear WARNING: "pear/Console_Getopt" is deprecated in favor of "pear/Console_GetoptPlus" downloading Console_Getopt-1.4.2.tgz ... Starting to download Console_Getopt-1.4.2.tgz (5,736 bytes) .....done: 5,736 bytes downloading Archive_Tar-1.4.7.tgz ... Starting to download Archive_Tar-1.4.7.tgz (21,134 bytes) ...done: 21,134 bytes downloading PEAR-1.10.9.tgz ... Starting to download PEAR-1.10.9.tgz (291,931 bytes) ...done: 291,931 bytes upgrade-all ok: channel://pear.php.net/Console_Getopt-1.4.2 upgrade-all ok: channel://pear.php.net/Archive_Tar-1.4.7 Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in PEAR/PackageFile/v1.php on line 1424 PHP Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in /usr/share/php/PEAR/PackageFile/v1.php on line 1424 upgrade-all ok: channel://pear.php.net/PEAR-1.10.9 PEAR: Optional feature webinstaller available (PEAR's web-based installer) PEAR: Optional feature gtkinstaller available (PEAR's PHP-GTK-based installer) PEAR: Optional feature gtk2installer available (PEAR's PHP-GTK2-based installer) PEAR: To install optional features use "pear install pear/PEAR#featurename" @raspberrypi:~ $ sudo pear list Installed packages, channel pear.php.net: ========================================= Package Version State Archive_Tar 1.4.7 stable Console_Getopt 1.4.2 stable PEAR 1.10.9 stable PEAR_Manpages 1.10.0 stable Structures_Graph 1.1.1 stable XML_Util 1.4.3 stable miki@raspberrypi:~ $ miki@raspberrypi:~ $ php -v PHP 7.3.4-2 (cli) (built: Apr 13 2019 19:05:48) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.4, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.3.4-2, Copyright (c) 1999-2018, by Zend Technologies @raspberrypi:~ $ sudo pear install DB WARNING: "pear/DB" is deprecated in favor of "pear/MDB2" downloading DB-1.9.3.tgz ... Starting to download DB-1.9.3.tgz (132,290 bytes) .............................done: 132,290 bytes install ok: channel://pear.php.net/DB-1.9.3
テレビの状態が知りたいと思い、東芝のレグザ(REGZA)に何かI/F(インターフェース)がないのか、調べてみました。
残念ながら、テレビの状態は分かりませんでした。電源が付いていなければ、なにかのコマンドやネットワーク接続失敗などで、電源ONかOFFぐらいは分かるかなが現時点の結果です。操作系は、Nature RemoのAPIやNature Remo経由のIFTTTが利用しやすいですし、他デバイスと同じ方式で統一した操作が可能など優位点が多いです。東芝はテレビを頑張っているように見えるので、せっかくI/F(インターフェース)があるようなので、今後IFTTT対応をしてほしいです。Google home搭載モデルなどもありますし、今後に期待!
非公式と思われる情報であり、有用となり得る情報なので設定方法や確かめた内容を記事にしておきます。
利用にあたり、REGZA側に2つ設定を行いました。
「(リモコン)設定ボタン」「初期設定」「ネットワーク設定」「IPアドレス設定」
デフォルト設定のIPアドレス自動取得を「しない」に設定変更しました。
その後、ネットワーク設定に合わせて、IPアドレスの設定を行いました。
「(リモコン)設定ボタン」「接続機器設定」「外部連携設定」「レグザAppコネクト設定」
API利用時に、ユーザー名とパスワードの認証が必要となります。
Digest認証(ダイジェストにんしょう)が利用されているようで、プログラムからの利用時には、Digest認証に対応した方法で利用する必要があります。
http://[REGZA IP]/remote/remote.htm?key=[command_key]
IE、Chrome、Firefoxなど一般ブラウザから動作確認できます。
戻り値は、テキスト出力として数字が返ってきました。
「0」成功 「0以外」失敗。
ブラウザで操作している際に、テレビの音量を上げようとすると「4」というエラー番号も見ることが出来ました。電源ボタンを押した直後に音量操作実施のタイミング。
テレビのIPアドレスが192.168.0.77の場合のコマンドサンプル
ボタン名 | [command_key] |
1 | 40BF01 |
2 | 40BF02 |
3 | 40BF03 |
4 | 40BF04 |
5 | 40BF05 |
6 | 40BF06 |
7 | 40BF07 |
8 | 40BF08 |
9 | 40BF09 |
10 | 40BF0A |
11 | 40BF0B |
12 | 40BF0C |
入力切替 | 40BF0F |
消音 | 40BF10 |
電源 | 40BF12 |
音声切り替え | 40BF13 |
音量↑ | 40BF1A |
チャンネル↑ | 40BF1B |
画面表示 | 40BF1C |
音量↓ | 40BF1E |
チャンネル↓ | 40BF1F |
ブロードバンド | 40BF25 |
クイック | 40BF27 |
マルチ画面 | 40BF29 |
画面サイズ | 40BF2B |
戻る | 40BF3B |
終了 | 40BF3C |
決定 | 40BF3D |
↑ | 40BF3E |
↓ | 40BF3F |
一時停止(静止) | 40BF50 |
→ | 40BF5B |
← | 40BF5F |
CH番号 | 40BF60 |
サーチ | 40BF60 |
ラジオ/データ | 40BF6D |
番組表 | 40BF6E |
番組説明 | 40BF71 |
青 | 40BF73 |
赤 | 40BF74 |
緑 | 40BF75 |
黄 | 40BF76 |
ミニ番組表 | 40BF77 |
地デジ | 40BF7A |
地アナ | 40BF7B |
BS | 40BF7C |
CS | 40BF7D |
録画 | 40BF86 |
設定メニュー | 40BFD0 |
↑↑ | 40BE20 |
↓↓ | 40BE21 |
→→(30秒送り) | 40BE22 |
←←(10秒戻し) | 40BE23 |
早送りスキップ | 40BE26 |
戻るスキップ | 40BE27 |
録画リスト | 40BE28 |
停止 | 40BE2B |
巻き戻し | 40BE2C |
再生 | 40BE2D |
早送り | 40BE2E |
レグザメニュー | 40BE34 |
タイムシフト | 40BE35 |
番組検索 | 40BE36 |
始めにジャンプ | 40BE47 |
イジェクト | 40BE93 |
ディスク | 40BE9E |
dデータ | 43BC14 |
字幕 | 43BC52 |
表示されるDigest認証画面
音量を上げるコマンド実行後の結果「0」(成功)
フジテレビのめざましじゃんけんシステムGo-Live!!
本日分が無事に動いたので、早速公開!
めざましじゃんけん結果一覧はこちら
初めての技術習得が結構多く、開発極小がポリシーなのですが、時間かかりました。各種勉強から初めて3週間弱でしょうか。
7月13日の週末に、関連書籍とWEBカメラをアマゾンで購入していました。
Deep Learning(ディープラーニング、深層学習)、DNN(ディープニューラルネットワーク)、AI(人工知能)やML(機械学習)を少し触ってみました。初めての技術ばかりで、ライフのデジタル化計画に有益な技術習得を行いました。
以下サンプル画像です。デジタル放送部分のみなので、著作権には配慮しているつもりです。問題のある際は、ご連絡下さい。大手なので、使用許諾にも時間がかかりそうなので、時間を見つけて画像の使用許諾を考えます。
8月からのブログネタは、このシステム構築に関わる技術内容とする予定です。
次の週末にでも記事を書き溜めます。
さて、次は、、、まだ未定。
PHPでWEB APIを利用していると、制御文字や改行文字を削除(エスケープ)したい場面が出てきます。
x0A Line Feed(改行)およびx0D Carriage Return(復帰)と制御文字を削除したい場合の、PHPコードです。
$string = preg_replace('/[\x00-\x1F\x7F]/','', $string);
改行文字含むコントロール文字は、POSIXキャラクタクラスにおいて [:cntrl:] で定義されており、以下のように記載することも可能です。
$string = preg_replace('/[[:cntrl:]]/', '', $string);
x0A Line Feed(改行)およびx0D Carriage Return(復帰)と制御文字は残し、その他の制御文字を削除する場合の、PHPコードです。
$string = preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $string);
Remove control characters from PHP string
16進 | 略号 | 名称 | CS |
00 | NUL | 空白(Null) | ^@ |
01 | SOH | ヘッディング開始(Start of Heading) | ^A |
02 | STX | テキスト開始(Start of Text) | ^B |
03 | ETX | テキスト終結(End of Text) | ^C |
04 | EOT | 伝送終了(End of Transmission) | ^D |
05 | ENQ | 問い合わせ(Enquiry) | ^E |
06 | ACK | 肯定応答(Acknowledge) | ^F |
07 | BEL | ベル(Bell) | ^G |
08 | BS | 後退(Backspace) | ^H |
09 | HT | 水平タブ(Horizontal Tabulation) | ^I |
0A | LF | 改行(Line Feed) | ^J |
0B | VT | 垂直タブ(Vertical Tabulation) | ^K |
0C | FF | 書式送り(Form Feed) | ^L |
0D | CR | 復帰(Carriage Return) | ^M |
0E | SO | シフトアウト(Shift Out) | ^N |
0F | SI | シフトイン(Shift In) | ^O |
10 | DLE | 伝送制御拡張(Data Link Escape) | ^P |
11 | DC1 | 装置制御1(Device Control 1) | ^Q |
12 | DC2 | 装置制御2(Device Control 2) | ^R |
13 | DC3 | 装置制御3(Device Control 3) | ^S |
14 | DC4 | 装置制御4(Device Control 4) | ^T |
15 | NAK | 否定応答(Negative Acknowledge) | ^U |
16 | SYN | 同期信号(Synchronous Idle) | ^V |
17 | ETB | 伝送ブロック終結(End of Transmission Block) | ^W |
18 | CAN | 取り消し(Cancel) | ^X |
19 | EM | 媒体終結(End of Medium) | ^Y |
1A | SUB | 置換(Substitute Character) | ^Z |
1B | ESC | 拡張(Escape) | ^[ |
1C | FS | ファイル分離(File Separator) | ^\ |
1D | GS | グループ分離(Group Separator) | ^] |
1E | RS | レコード分離(Record Separator) | ^^ |
1F | US | ユニット分離(Unit Separator) | ^_ |
7F | DEL | 抹消(Delete) | ^? |
クラス名 | 意味 |
[:alnum:] | アルファベットと(十進)数字 |
[:alpha:] | アルファベット |
[:blank:] | 空白文字(スペース、タブ等) |
[:cntrl:] | 制御文字 |
[:digit:] | 十進数字 |
[:graph:] | 印字可能かつ表示可能な文字(スペースは印字可能だが表示可能ではない) |
[:lower:] | アルファベットの小文字 |
[:print:] | 印字可能なキャラクタ(=制御文字以外のキャラクタ) |
[:punct:] | 句読点(通常の文字、数字、制御文字、スペースのいずれでもないキャラクター) |
[:space:] | スペース、タブ、改ページ |
[:upper:] | アルファベットの大文字 |
[:xdigit:] | 十六進数字 |
SendGridは、メール配信などで利用されている方は多いのかもしれませんが、メール受信トリガーにWEB API経由でPOSTしてくれるサービスも提供されているようです。メール受信時のWEB APIプッシュの実現方法を探している際に見つけました。
グローバルで、企業向けにサービスを展開されているので、サービス品質などに間違いはなさそうです。
IFTTTでメール受信をしっかりとトリガー出来ていれば本サービスを利用することも無かったかもしれませんが、利用してみてPubSubというような使い方が出来そうなのでメインで利用する予定です。一般向け製品では通知手段がメールというサービスが多いです。
DNS設定に関しては、利用しているVALUE-DOMAIN(バリュードメイン)を例に説明を行います。
sendgridで扱うEmail専用のサブドメインを準備します。サブドメイン宛のメールはすべてSendGridのメールサーバーに送信されるように設定し、SendGridでは、メール受信時のアクション(アクセスするWEB APIのURL)を設定します。あとは、受信を受けたWEB APIがメールの件名や差出人などにより実施したい処理を実施します。
現時点では、モーションセンサーの通知などをメール受信し、各種情報のデータ化としてデーターベースへの蓄積を行っております。
SendGridのサイトよりアカウントの新規登録を行います。
メールアドレスを登録し、簡単なアンケートや情報入力を行い、本登録を待ちます。人の手でサービス品質を保っているようで、以下メールが来て1日程度登録を待ちました。
実際、住所登録に不備があり、住所修正を行い、本登録が終了しました
SendGridにご登録いただき、誠にありがとうございます。 ログイン用のユーザ名につきましては、ご登録内容の確認およびアカウントのご利用準備が整い次第、 別途ご連絡いたします(通常、翌2営業日以内)。 ※ユーザ名はメールアドレスではございません。 なお、 ご登録内容について確認のご連絡をさせていただく場合がございま すので、あらかじめご了承ください。
サービス登録後の、利用者向けポータルのトップページ。
SendGrid-Inbound Email Parse Webhookを利用すると、利用条件としてドメインの認証が必要と、ドメイン認証の画面に誘導されます。以下の画面が、まずドメインの認証が必要とダイアログが出ています。
ドメインの認証方法は、利用しているドメインサーバのDNS設定にDNSレコードの追加を行います。SendGridで指定されたDNSレコードを追加する必要があります。SendGrid側でDNS変更を確認し、DNS変更の確認が完了すれば、ドメインの認証が終了します。
ドメイン認証は、SendGridのDomain Authentication(Authenticate Your Domain)のダイアログに従い、Install DNS Recourdsまで進み、登録するDNS情報を入手して下さい。
取得した追加するDNSレコードを自分のDNSサーバに追加します。
今回は、利用しているVALUE-DOMAIN(バリュードメイン)での設定例を例示して起きます。
ポイントは、DNS設定には時間を要するので、正しく設定出来た状態で、しばらく待ちましょう。数時間で反映されると思いますが、各種サーバなどの設定に依存します。
追加したDNSレコードが確認され、ドメイン認証が完了される際に表示されるWEB画面です。「Verify Your Domain」It worked!と表示されました。
日本法人 公式サイトの関連するQAです。
独自ドメイン利用(Sender Authentication)および設定時のDNSレコードについて、詳しく教えてください
ドメイン認証が完了すると SendGridでSendGrid-Inbound Email Parse Webhook(メール受信時とWeb APIのマッピング)設定となります。
SendGridで受信するメールアドレスのドメインおよびWeb APIのURLを設定します。
オプションで、SendGrid側でのSpamチェック有無と受信するPOSTデータを指定します。
最後に、SendGridへ転送したいメールアドレスを自分のDNSサーバに設定します。
この設定が終了すると、DNS情報がインターネットに反映され次第、受信メールのSendGridへ転送、SendGridでメール受信時にWEB APIへのメールデータPOSTが開始されます。
必ず、WEB API側の準備後に、DNSレコードの追加を行って下さい。(最低限WEB受信可能な状態)
以下の例では、MXレコードを追加し、対象のサブドメインをSendGridのメールサーバーに転送されるように指定します。
Inbound Email Parse WebhookのPOST情報
HEADERS | The raw headers of the email. |
---|---|
DKIM | A string containing the verification results of any DKIM and domain keys signatures in the message. |
CONTENT-IDS | A string containing the number of attachments. |
TO | Email recipient field, as taken from the message headers. |
HTML | HTML body of email. If not set, email did not have an HTML body. |
FROM | Email sender, as taken from the message headers. |
SENDER_IP | A string of the sender’s ip address. |
SPAM_REPORT | Spam Assassin’s spam report. |
ENVELOPE | A string containing the SMTP envelope. This will have 2 variables: to , which is a single-element array containing the address that we received the email to, and from , which is the return path for the message. |
ATTACHMENTS | Number of attachments included in email. |
SUBJECT | Email Subject. |
SPAM_SCORE | Spam Assassin’s rating for whether or not this is spam. |
ATTACHMENT-INFO | A JSON map where the keys are named attachment{X}. Each attachment key points to a JSON object containing three fields, filename , type , and content-id . The filename field is the name of the file (if it was provided). The type field is the media type of the file. X is the total number of attachments. For example, if the number of attachments is 0, there will be no attachment files. If the number of attachments is 3, parameters attachment1, attachment2, and attachment3 will have file uploads. |
CHARSETS | A string containing the character sets of the fields extracted from the message. |
SPF | The results of the Sender Policy Framework verification of the message sender and receiving IP address. |
[Date] array(16) { ["headers"]=> string(1970) "Received: by mx0047p1mdw1.sendgrid.net with SMTP id 6WCVv7KAWn Wed, 27 Jul 2016 20:53:06 +0000 (UTC) Received: from mail-io0-f169.google.com (mail-io0-f169.google.com [209.85.223.169]) by mx0047p1mdw1.sendgrid.net (Postfix) with ESMTPS id AA9FFA817F2 for <example@example.comom>; Wed, 27 Jul 2016 20:53:06 +0000 (UTC) Received: by mail-io0-f169.google.com with SMTP id b62so81593819iod.3 for <example@example.comom>; Wed, 27 Jul 2016 13:53:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sendgrid.com; s=ga1; h=mime-version:from:date:message-id:subject:to; bh=DpB1CYYeumytcPF3q0Upvx3Sq/oF4ZblEwnuVzFwqGI=; b=GH5YTxjt6r4HoTa+94w6ZGQszFQSgegF+Jlv69YV76OLycJI4Gxdwfh6Wlqfez5yID 5dsWuqaVJZQyMq/Dy/c2gHSqVo60BKG56YrynYeSrMPy8abE/6/muPilYxDoPoEyIr/c UXH5rhOKjmJ7nICKu1o99Tfl0cXyCskE7ERW0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=DpB1CYYeumytcPF3q0Upvx3Sq/oF4ZblEwnuVzFwqGI=; b=Sq6LVHbmywBdt3sTBn19U8VOmelfoJltz8IcnvcETZsYwk96RBxN+RKMN5fOZSKw4j 15HrgdIFfyDmp67YK0ygvOITlTvZ6XY5I0PtnvDtAQt79kS3tKjI3QKJoEp/ZjIjSzlL KG7agl6cxFgBbIN0yHWBOvy3O+ZXY8tZdom1yOvULjmjW1U9JkdOs+aJ6zq4qhZX/RM/ tIgLB461eJ5V95iQDDc5Ibj9Cvy4vJfXLQRO0nLVQAT2Yz58tkEO1bDZpWOPAyUNneIL yhIWp+SpbuqhMA68mq0krG1PjmWalUbpVcGJIGuOKB9mQFFo/MqdrUCjvYnyo1jPLPeX psdQ== X-Gm-Message-State: AEkoousvdxmDoxLlTUYJ1AOmCGJv77xRBBlfKv6YrthH0M2NueMwlOxUD6t8nidE9uonXbdJ/DQy/chmHUnN//a4 X-Received: by 10.107.6.101 with SMTP id 98mr38024553iog.41.1469652785829; Wed, 27 Jul 2016 13:53:05 -0700 (PDT) MIME-Version: 1.0 Received: by 10.107.48.17 with HTTP; Wed, 27 Jul 2016 13:53:05 -0700 (PDT) From: Sender Name <example@example.com> Date: Wed, 27 Jul 2016 14:53:05 -0600 Message-ID: <CAN_P_JMvV7ZpAQhOnDienypLrJmuhN=LQWweu4yScw4jQyXY2w@mail.gmail.com> Subject: Different File Types To: example@example.comom Content-Type: multipart/mixed; boundary=001a113f8ad03e85160538a4343c " ["dkim"]=> string(22) "{@sendgrid.com : pass}" ["content-ids"]=> string(37) "{"ii_1562e2169c132d83":"attachment1"}" ["to"]=> string(26) "example@example.comom" ["html"]=> string(479) "<div dir="ltr">Here's an email with multiple attachments<div><br></div><div><img src="cid:ii_1562e2169c132d83" alt="Inline image 1" width="455" height="544"><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><img src="https://sendgrid.com/brand/sg-logo-email.png" width="96" height="17"><br><div><br></div></div></div> </div></div> " ["from"]=> string(33) "Sender Name example@example.com" ["text"]=> string(139) "Here's an email with multiple attachments " ["sender_ip"]=> string(14) "209.85.223.169" ["spam_report"]=> string(844) "Spam detection software, running on the system "mx0047p1mdw1.sendgrid.net", has identified this incoming email as possible spam. The original message has been attached to this so you can view it (if it isn't spam) or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Here's an email with multiple attachments [image: Inline image 1] -- [...] Content analysis details: (2.6 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.8 HTML_IMAGE_RATIO_02 BODY: HTML has a low ratio of text to image area 0.0 HTML_MESSAGE BODY: HTML included in message 1.8 HTML_IMAGE_ONLY_08 BODY: HTML: images with 400-800 bytes of words 0.0 T_MIME_NO_TEXT No text body parts " ["envelope"]=> string(66) "{"to":["example@example.comom"],"from":"example@example.com"}" ["attachments"]=> string(1) "2" ["subject"]=> string(20) "Different File Types" ["spam_score"]=> string(5) "2.597" ["attachment-info"]=> string(287) "{"attachment2":{"filename":"DockMcWordface.docx","name":"DockMcWordface.docx","type":"application/vnd.openxmlformats-officedocument.wordprocessingml.document"},"attachment1":{"filename":"MG_2359.jpg","name":"_MG_2359.jpg","type":"image/jpeg","content-id":"ii_1562e2169c132d83"}}" ["charsets"]=> string(77) "{"to":"UTF-8","html":"UTF-8","subject":"UTF-8","from":"UTF-8","text":"UTF-8"}" ["SPF"]=> string(4) "pass" }
SendGridは、メール配信などで利用されている方は多いのかもしれませんが、メール受信トリガーにWEB API経由でPOSTしてくれるサービスも提供されているようです。メール受信時のWEB APIプッシュの実現方法を探している際に見つけました。
グローバルで、企業向けにサービスを展開されているので、サービス品質などに間違いはなさそうです。
IFTTTでメール受信をしっかりとトリガー出来ていれば本サービスを利用することも無かったかもしれませんが、利用してみてPubSubというような使い方が出来そうなのでメインで利用する予定です。一般向け製品では通知手段がメールというサービスが多いです。
WEBサーバーにPOST受信可能なPHPファイルを配置し、SendGridがメール受信したさいのWEBリクエストを受信するPHP APIを準備します。
以下は、サンプルとなります。受信後に実施したい処理を利用形態に合わせて実装して下さい。本ページの各種ユースケースもサンプルになると思います。ユースケース一覧 V1
以下サンプルコードとなります。
<?php /************************************************************************* * sendgrid-api (MAIN) * Home Tools for private. Using IFTTT and Google Home etc * * PHP 5 or later * * @category Home IoT * @author Miki * @url https://www.miki-ie.com/ * @copyright 2019 (c) MIKI-IE All rights Reserved. * @license https://opensource.org/licenses/mit-license.html MIT License * @version 1.0 *************************************************************************/ //ログのファイル名 define("SENDGRID_API_LOG_NAME","sendgrid"); //DB define("DB_HOST","@IP_Adress@:@Port@"); define("DB_USER","@User@"); define("DB_PASS","@Password@"); define("DB_DBNAME","@DB_Name@"); define("DB_TABLENAME1","@TableName1@"); define("DB_TABLENAME2","@TableName2@"); function addDBRecord($table, $datetime, $value1) { $mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DBNAME); if (mysqli_connect_errno()) { logger("Connect failed: ".mysqli_connect_error(),"ERROR"); exit(); } if (!$mysqli->set_charset("utf8")) { logger("Error loading character set utf8: ".$mysqli->error,"ERROR"); exit(); } switch ($table) { case DB_TABLENAME1: // SQL(INSERT)を作成 $sql = "INSERT INTO $table ( DATETIME, COUNT ) VALUES ( '$datetime', $value1 )"; break; //addDBRecord(DB_TABLENAME2, $datetime_text, $state_text); case DB_TABLENAME2: // SQL(INSERT)を作成 $str = mb_convert_encoding($value1, "UTF-8"); $sql = "INSERT INTO $table ( DATETIME2, STATE ) VALUES ( '$datetime', N'$str' )"; break; default: logger("Internal DB Tabel Name Error. table:{$table}","ERROR"); } if (!$mysqli->query($sql)) { logger("SQL query error Errormessage: ".$mysqli->error,"ERROR"); } $mysqli->close(); } function logger($text, $level) { $datetime = date('Y-m-d H:i:s'); $date = date('Ym'); $file_name = __DIR__ . "/log/".SENDGRID_API_LOG_NAME."-{$date}.log"; $text = "{$datetime} [{$level}] {$text}" . PHP_EOL; echo $text; if(!(file_exists($file_name))){ touch($file_name); chmod($file_name, 0777); } return error_log(print_r($text, TRUE), 3, $file_name); } $post_from = $_POST['from']; $post_charsets = $_POST['charsets']; $post_charsets_array = json_decode($post_charsets, true); $post_charsets_all = print_r($post_charsets_array, true); $post_encode_subject = mb_convert_encoding($_POST['subject'], "UTF-8", $post_charsets_array["subject"]); $post_encode_subject = preg_replace('/[\x00-\x1F\x7F]/', '', $post_encode_subject); $post_encode_text = mb_convert_encoding($_POST['text'], "UTF-8", $post_charsets_array["text"]); $post_encode_text = preg_replace('/[\x00-\x1F\x7F]/', '', $post_encode_text); logger("mb_convert_encoding, post_subject : {$post_encode_subject}","DEBUG"); logger("mb_convert_encoding, post_text : {$post_encode_text}","DEBUG"); $text_substr = mb_substr($post_text, 0, 15); logger("Start sendgrid: key={$key} , from={$post_from} , subject={$post_subject} , text={$text_substr}","INFO"); if(isset($_POST['from'])) { switch ($post_from) { case 'aaa1@bbb.ccc': //メール受信内容に合わせて個別処理。以下はメール本文から文字列切り出しを実施 $start = mb_strpos($post_text, "時刻:"); $datetime_text = mb_substr($post_text, $start + 4, 19,"utf-8"); logger("Start CAM-A7DE datetime : {$datetime_text}","INFO"); addDBRecord(DB_TABLENAME1, $datetime_text, 1); break; case 'aaa2@bbb.ccc': //メール受信内容に合わせて個別処理。以下はメール本文から文字列切り出しを実施 $datetime_text = mb_substr($post_text, 0, 16,"utf-8"); $temp_text = mb_substr($post_text, 18); $end_point = mb_strpos($temp_text, "。"); $state_text = mb_substr($temp_text, 0, $end_point,"utf-8"); logger("end_point : {$end_point} ,state : {$state_text}","DEBUG"); logger("Start CSP-Security datetime : {$datetime_text} state : {$state_text}","INFO"); addDBRecord(DB_TABLENAME2, $datetime_text, $state_text); break; default: logger("This is private API. (in Default)","ERROR"); } }else{ logger("This is private API. (in else)","ERROR"); } ?>
Inbound Email Parse WebhookのPOST情報
HEADERS | The raw headers of the email. |
---|---|
DKIM | A string containing the verification results of any DKIM and domain keys signatures in the message. |
CONTENT-IDS | A string containing the number of attachments. |
TO | Email recipient field, as taken from the message headers. |
HTML | HTML body of email. If not set, email did not have an HTML body. |
FROM | Email sender, as taken from the message headers. |
SENDER_IP | A string of the sender’s ip address. |
SPAM_REPORT | Spam Assassin’s spam report. |
ENVELOPE | A string containing the SMTP envelope. This will have 2 variables: to , which is a single-element array containing the address that we received the email to, and from , which is the return path for the message. |
ATTACHMENTS | Number of attachments included in email. |
SUBJECT | Email Subject. |
SPAM_SCORE | Spam Assassin’s rating for whether or not this is spam. |
ATTACHMENT-INFO | A JSON map where the keys are named attachment{X}. Each attachment key points to a JSON object containing three fields, filename , type , and content-id . The filename field is the name of the file (if it was provided). The type field is the media type of the file. X is the total number of attachments. For example, if the number of attachments is 0, there will be no attachment files. If the number of attachments is 3, parameters attachment1, attachment2, and attachment3 will have file uploads. |
CHARSETS | A string containing the character sets of the fields extracted from the message. |
SPF | The results of the Sender Policy Framework verification of the message sender and receiving IP address. |
[Date] array(16) { ["headers"]=> string(1970) "Received: by mx0047p1mdw1.sendgrid.net with SMTP id 6WCVv7KAWn Wed, 27 Jul 2016 20:53:06 +0000 (UTC) Received: from mail-io0-f169.google.com (mail-io0-f169.google.com [209.85.223.169]) by mx0047p1mdw1.sendgrid.net (Postfix) with ESMTPS id AA9FFA817F2 for <example@example.comom>; Wed, 27 Jul 2016 20:53:06 +0000 (UTC) Received: by mail-io0-f169.google.com with SMTP id b62so81593819iod.3 for <example@example.comom>; Wed, 27 Jul 2016 13:53:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sendgrid.com; s=ga1; h=mime-version:from:date:message-id:subject:to; bh=DpB1CYYeumytcPF3q0Upvx3Sq/oF4ZblEwnuVzFwqGI=; b=GH5YTxjt6r4HoTa+94w6ZGQszFQSgegF+Jlv69YV76OLycJI4Gxdwfh6Wlqfez5yID 5dsWuqaVJZQyMq/Dy/c2gHSqVo60BKG56YrynYeSrMPy8abE/6/muPilYxDoPoEyIr/c UXH5rhOKjmJ7nICKu1o99Tfl0cXyCskE7ERW0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=DpB1CYYeumytcPF3q0Upvx3Sq/oF4ZblEwnuVzFwqGI=; b=Sq6LVHbmywBdt3sTBn19U8VOmelfoJltz8IcnvcETZsYwk96RBxN+RKMN5fOZSKw4j 15HrgdIFfyDmp67YK0ygvOITlTvZ6XY5I0PtnvDtAQt79kS3tKjI3QKJoEp/ZjIjSzlL KG7agl6cxFgBbIN0yHWBOvy3O+ZXY8tZdom1yOvULjmjW1U9JkdOs+aJ6zq4qhZX/RM/ tIgLB461eJ5V95iQDDc5Ibj9Cvy4vJfXLQRO0nLVQAT2Yz58tkEO1bDZpWOPAyUNneIL yhIWp+SpbuqhMA68mq0krG1PjmWalUbpVcGJIGuOKB9mQFFo/MqdrUCjvYnyo1jPLPeX psdQ== X-Gm-Message-State: AEkoousvdxmDoxLlTUYJ1AOmCGJv77xRBBlfKv6YrthH0M2NueMwlOxUD6t8nidE9uonXbdJ/DQy/chmHUnN//a4 X-Received: by 10.107.6.101 with SMTP id 98mr38024553iog.41.1469652785829; Wed, 27 Jul 2016 13:53:05 -0700 (PDT) MIME-Version: 1.0 Received: by 10.107.48.17 with HTTP; Wed, 27 Jul 2016 13:53:05 -0700 (PDT) From: Sender Name <example@example.com> Date: Wed, 27 Jul 2016 14:53:05 -0600 Message-ID: <CAN_P_JMvV7ZpAQhOnDienypLrJmuhN=LQWweu4yScw4jQyXY2w@mail.gmail.com> Subject: Different File Types To: example@example.comom Content-Type: multipart/mixed; boundary=001a113f8ad03e85160538a4343c " ["dkim"]=> string(22) "{@sendgrid.com : pass}" ["content-ids"]=> string(37) "{"ii_1562e2169c132d83":"attachment1"}" ["to"]=> string(26) "example@example.comom" ["html"]=> string(479) "<div dir="ltr">Here's an email with multiple attachments<div><br></div><div><img src="cid:ii_1562e2169c132d83" alt="Inline image 1" width="455" height="544"><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature"><div dir="ltr"><img src="https://sendgrid.com/brand/sg-logo-email.png" width="96" height="17"><br><div><br></div></div></div> </div></div> " ["from"]=> string(33) "Sender Name example@example.com" ["text"]=> string(139) "Here's an email with multiple attachments " ["sender_ip"]=> string(14) "209.85.223.169" ["spam_report"]=> string(844) "Spam detection software, running on the system "mx0047p1mdw1.sendgrid.net", has identified this incoming email as possible spam. The original message has been attached to this so you can view it (if it isn't spam) or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Here's an email with multiple attachments [image: Inline image 1] -- [...] Content analysis details: (2.6 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.8 HTML_IMAGE_RATIO_02 BODY: HTML has a low ratio of text to image area 0.0 HTML_MESSAGE BODY: HTML included in message 1.8 HTML_IMAGE_ONLY_08 BODY: HTML: images with 400-800 bytes of words 0.0 T_MIME_NO_TEXT No text body parts " ["envelope"]=> string(66) "{"to":["example@example.comom"],"from":"example@example.com"}" ["attachments"]=> string(1) "2" ["subject"]=> string(20) "Different File Types" ["spam_score"]=> string(5) "2.597" ["attachment-info"]=> string(287) "{"attachment2":{"filename":"DockMcWordface.docx","name":"DockMcWordface.docx","type":"application/vnd.openxmlformats-officedocument.wordprocessingml.document"},"attachment1":{"filename":"MG_2359.jpg","name":"_MG_2359.jpg","type":"image/jpeg","content-id":"ii_1562e2169c132d83"}}" ["charsets"]=> string(77) "{"to":"UTF-8","html":"UTF-8","subject":"UTF-8","from":"UTF-8","text":"UTF-8"}" ["SPF"]=> string(4) "pass" }
Raspberry Piでない環境で利用したことのあるSleniumの導入を行いました。
各種WEBツールの自動操作(スクレイピング)などが出来ると、更に自宅IoTの幅が広がると思い、導入してみましたが、「Raspberry Pi 3 Model B+」のCPUが1.2GHz、4コアのBroadcom BCM2837から1.4GHz駆動4コアのBCM2837B0は、32bitでありchromedriverの導入方法が限られ、高い信頼性で動作する状態まで構築出来ておりません。とりあえず動作しますが、信頼性が低いです。(数回に1回は失敗します)
pi@raspberrypi:~ $ cat /proc/cpuinfo processor : 0 model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 38.40 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 1 model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 38.40 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 2 model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 38.40 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 processor : 3 model name : ARMv7 Processor rev 4 (v7l) BogoMIPS : 38.40 Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x0 CPU part : 0xd03 CPU revision : 4 Hardware : BCM2835 Revision : a020d3 Serial : 00000000e63ad038 pi@raspberrypi:~ $ cat /etc/debian_version 10.0 pi@raspberrypi:~ $ uname -a Linux raspberrypi 4.19.57-v7+ #1244 SMP Thu Jul 4 18:45:25 BST 2019 armv7l GNU/Linux
root@raspberrypi:~# pip install selenium Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple Collecting selenium Downloading https://files.pythonhosted.org/packages/80/d6/4294f0b4bce4de0abf13e17190289f9d0613b0a44e5dd6a7f5ca98459853/selenium-3.141.0-py2.py3-none-any.whl (904kB) 100% |████████████████████████████████| 911kB 306kB/s Requirement already satisfied: urllib3 in /usr/lib/python2.7/dist-packages (from selenium) (1.24.1) Installing collected packages: selenium Successfully installed selenium-3.141.0
@raspberrypi:~ $ pip list |grep selenium selenium 3.141.0
sudo apt-get install chromium-browser
sudo npm -g install chromedriver
chromiumブラウザともバージョンが合い、まだ安定して動作しました。
sudo apt-get install chromium-chromedriver
あまり安定して動作しませんでした。
root@raspberrypi:~# pip install chromedriver Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple Collecting chromedriver Downloading https://files.pythonhosted.org/packages/c8/5e/1daf3c71852f5b8536e30b2afa1e6442c454e91947678ac1a37daba2d7f5/chromedriver-2.24.1-py2.py3-none-any.whl (14.3MB) 100% |████████████████████████████████| 14.3MB 16kB/s Installing collected packages: chromedriver Successfully installed chromedriver-2.24.1
miki@raspberrypi:~ $ pip list |grep chromedriver chromedriver 2.24.1
以下のスクリプトでheadlessモードでの動作検証を行いました。タイミングにより失敗するケースも有り、IoT家電のメインパスとして利用するにはもう少し試行錯誤が必要かなという状況です。ただし、APIがなくWEBのみに温度など取得したい情報があるツールなどの情報GET系には利用していこうかなと考えております。
それとは、別に設定変更など操作を行うことはもう少し、信頼のおける構築方法が見つかってから導入したいと考えております。
#!/usr/bin/env python # -*- coding: utf-8 -*- import time from selenium import webdriver from selenium.webdriver.chrome.options import Options CHROME_BIN = "/usr/bin/chromium-browser" CHROME_DRIVER = '/usr/lib/chromium-browser/chromedriver' options = Options() options.binary_location = CHROME_BIN options.add_argument('--headless') driver = webdriver.Chrome(CHROME_DRIVER, options=options) driver.get("https://www.google.co.jp") time.sleep(5) html = driver.page_source print(html) driver.quit()