「せばな」は言わない

綱の上を歩いたり、壁を登ったりする田舎のプログラマーのおはなし

【Raspberry Pi】ラズパイで7inch タッチディスプレイの回転

f:id:tk_thunder:20190223000715j:plain

ラズパイで7inch タッチディスプレイの回転

タッチディスプレイの画面とタッチ座標を回転させる方法。

3週間くらいかかったので記念にブログに書いておきます。

仕事でラズパイに7inchのディスプレイを接続して、「縦置き」するということがありました。
もちろん横に表示されている画面を縦にしないといけないのでハードのみならず、ソフト的にも画面を回転させなければいけません。
いろんな数値をいじったりキャリブレーションしたりあらゆる手段を講じて、なんとか希望通りになりました。
過去の記事もたくさん参考にしたのですが、どれもそのままの方法ではうまく行かず…試行した内容を整理しました。

今回の内容は画面を縦に使用する場合の内容です。通常の横置きならば "lcd_rotate=0" or "lcd_rotate=2" で対応できます。
ちなみにHDMIのディスプレイでは試していないので、このままの内容は適用できるかは分かりません。

手順
  • 接続されているタッチディスプレイの名前を調べる※sshからはコマンドが通らないので端末から操作する。ディスプレイとキーボード、マウスを接続する
xinput list

自分の結果(接続ディスプレイで違う結果になると思います)

Virtual core pointer                          id=2    [master pointer  (3)]
    Virtual core XTEST pointer                id=4    [slave  pointer  (2)]
    Compx 2.4G Receiver                       id=7    [slave  pointer  (2)]
    これ!→ FT5406 memory based driver                id=8    [slave  pointer  (2)]
    HID 04f3:0103                             id=10   [slave  pointer  (2)]
Virtual core keyboard                         id=3    [master keyboard (2)]
    Virtual core XTEST keyboard               id=5    [slave  keyboard (3)]
    Compx 2.4G Receiver                       id=6    [slave  keyboard (3)]
    Compx 2.4G Receiver                       id=9    [slave  keyboard (3)]
    HID 04f3:0103
  • /etc/X11に"xorg.conf.d"というディレクトリを作成する。
cd /etc/X11/
sudo mkdir xorg.conf.d
  • "xorg.conf.d"内に"99-calibration.conf"というファイルを作成する。
sudo nano 99-calibration.conf
  • "99-calibration.conf"に以下の内容を記述する
Section "InputClass"
        Identifier      "calibration"
        MatchProduct    "FT5406 memory based driver"
        Option          "TransformationMatrix" "0 -1 1 1 0 0 0 0 1"
EndSection

"MatchProduct"は1で調べたタッチディスプレイの名前
"Option"は90°か270°かで変わる。

90° : "TransformationMatrix" "0 1 0 -1 0 1 0 0 1"
270° : "TransformationMatrix" "0 -1 1 1 0 0 0 0 1"

数値も""で囲わないと起動時にデスクトップが表示されなくなったりするので注意。
そうなってもコマンドで操作できるので問題なかったです(やらかし)

  • 再起動する
sudo reboot

参考文献
キャリブレーションについて
https://a244.hateblo.jp/entry/2016/10/09/014932

ラズパイフォーラム
https://www.raspberrypi.org/forums/viewtopic.php?t=194273

【Raspberry Pi】Rasbian Stretch Liteのセットアップ

f:id:tk_thunder:20180203223050j:plain

はじめに

仕事で使うRaspberry Piと趣味用のRaspberry Pi Zero WにRasbian Stretch Liteをインストールしてセットアップしたのでその時の作業メモを残す。
もし同じようにセットアップする人がいれば参考にしてもらえればと思う。

前提とする環境

  • 本体:Raspberry Pi3 Model B / Raspberry Pi Zero W
  • OS:Rasbian Stretch Lite(GUIなし)
  • SSHに使用するPC:Windows 10 64bit

※使用するOSは2018/05/19現在最新のもの

  • HDMIケーブルもしくはHDMI-DVI(D-SUB)変換ケーブルを通して画面に出力できること

※外部モニタが必要

やること

今回やることは以下の通りの基本的な設定ですよ。

  • OSインストール
  • 起動確認とログイン
  • ローカライゼーション設定(タイムゾーン、キーボードレイアウト、Wi-Fi)
  • インターフェース設定(SSH、I2C)
  • Wi-Fi(IPアドレス固定)
  • パッケージ管理システム設定

それでは細かい所をやっていこう。

起動確認

Raspberry Piに下記を接続し、最後に電源を入れる
電源スイッチは存在せず、ケーブルを接続した瞬間に電源が入る。

  1. MicroSD
  2. HDMI(ディスプレイへ)
  3. キーボード
  4. 電源ケーブル

ログイン

初期設定では下記のアカウントになる

  • ログインユーザ:pi
  • 初期パスワード:raspberry

設定

コンフィグ画面から下記を設定していく

$raspi-config

1.言語

1.1[4 Localisation Options]
地域、言語関係の設定を行う

1.1.1 [I2 Change Timezone]
タイムゾーンを日本の設定にする

Geographic area:Asia
Time zone:Tokyo

1.1.2 [I3 Change Keyboard Layout]
キーボードレイアウトを日本向けにする

Generic 105-key (Intl) PC
Japanese - Japanese (OADG 109A)
The default for the keyboard layout
No compose key

1.1.3 [I4 Change Wi-fi Country]
Wifiの設定を日本向けにする

JP Japan

2.インターフェース

2.1 [5 Interfacing Options]
接続機器の制御に関する設定を行う

2.1.1 [P2 SSH]
セキュアシェルの接続を許可する

Would you like the SSH server to be enabled?
Yesを選択。

2.1.2 [P5 I2C]

Would you like the ARM I2C interface to be enabled?
Yesを選択。

一度リブートする。

$ sudo reboot

WifiとSSH設定

1. Wifi設定

1.1 SSIDとパスワードをファイルに書き込む
下記のコマンドでSSIDとパスワードをファイルに書き込む。
[SSID]:接続先SSID
[PASSPHRASE]:接続先SSIDのパスワード

$sudo sh -c 'wpa_passphrase [SSID] [PASSPHRASE] >> /etc/wpa_supplicant/wpa_supplicant.conf'

書き込み先のファイルを参照する

$ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

生のパスワードがコメントアウトで書き込まれているため、これを削除する。
※アクセスポイントがステルスの場合は、SSIDサーチする下記コマンドを追記する。

scan_ssid=1

書き込みが終了したらCtrl + xを押下。Yを押下し、保存する。

1.2 IPアドレスを固定する
常に同じIPでSSH接続するためにIPアドレスを固定する。
設定に使用するファイルを開く。

$ sudo nano /etc/dhcpcd.conf

ファイルを開いたら下記の情報を書き込む。

interface wlan0
static ip_address=192.168.xx.xx(例)
static routers=xxx.xxx.xx.xx
static domain_name_servers=xxx.xxx.xx.xx

書き込みが終了したらCtrl + xを押下。Yを押下し、保存する。
保存後、再起動を実行する。

$ sudo reboot

1.3 接続確認
再起動後、下記コマンドでネットワーク環境の確認を行う

$ ifconfig

先程設定したIPがwlanの項目に表示されていれば、設定完了。

また、外のネットワークに接続可能か下記のコマンドで確認する。
※ ping先は任意でかまわない

$ ping www.yahoo.co.jp

下記のように通信が成功すればWifi設定は終了。
64 bytes from 182.22.25.124 (182.22.25.124): icmp_seq=1 ttl=54 time=20.2 ms
64 bytes from 182.22.25.124 (182.22.25.124): icmp_seq=2 ttl=54 time=22.1 ms
64 bytes from 182.22.25.124 (182.22.25.124): icmp_seq=3 ttl=54 time=22.1 ms
64 bytes from 182.22.25.124 (182.22.25.124): icmp_seq=4 ttl=54 time=24.9 ms

1.4 ロケール設定
ネットワークに接続できるようになったため、日本語のフォントをインストールする。

$ sudo apt-get install ttf-kochi-gothic xfonts-intl-japanese xfonts-intl-japanese-big xfonts-kaname

コンフィグ画面からロケールを日本に設定する

$raspi-config

[4 Localisation Options]→[I1 Change Locale]
下記を選択する。スペースキーを押下すると[*]マークをつけて複数選択できる。

en_GB.ISO-8859-15 ISO 8859-15
ja_JP.EUC-JP EUC-JP
ja_JP.UTF-8 UTF-8

デフォルトロケールを [ja_JP.UTF-8] にする。

参考
qiita.com

1.5 SSH接続
最後に個人のPCからWifi経由で制御できるようSSHの設定を実施する。
Raspberry Piに接続するPCに下記のソフトをインストールする。
[Tera Term Pro]
https://forest.watch.impress.co.jp/library/software/utf8teraterm/
ファイルをダウンロード後に開く。

参考
nw-electric.way-nifty.com

パッケージ管理システム設定

Raspberry Piには機能を拡張させるためのパッケージ管理システム「apt-get」がプリインストールされている。
Raspberry Piで保持しているパッケージ情報のリストを最新にする。下記のコマンドを入力する。
最新のリストがダウンロードされる。

$ sudo apt-get update

上で得たリストを元に、Raspberry Piにインストール済みのアプリケーションを最新に更新する。

$ sudo apt-get upgrade

OSのディストリビューションを最新に更新する。

$ sudo apt-get dist-upgrade

ファームウェアを最新に更新する。

$ sudo rpi-update

こんな感じですね。
アカウントの設定はデフォルトのまま進めていますが、セキュリティを向上させるために変更することをおすすめします。

【朗報】ワイのPC、復活を遂げる


はじめに

先日物理的に火を吹いた僕のPCだが、タイトルの通り復活を遂げたことをここに報告する。
tk-thunder.hateblo.jp

電源が火花を散らしたのでマザーボードを始め、すべてのパーツがお逝きになったのかと内心ヒヤヒヤだったが電源の交換のみで事なきを得た。

電源

ちなみに電源はこれ。

玄人志向 NEXTシリーズ 80 PLUS Bronze 600W ATX電源 KRPW-N600W/85+

玄人志向 NEXTシリーズ 80 PLUS Bronze 600W ATX電源 KRPW-N600W/85+

圧倒的なコストパフォーマンスだったので即決。

CPUファン

せっかくなので、CPUファンを取り付けたときの紹介もしておく。

サイズ オリジナルCPUクーラー 虎徹 Mark II

サイズ オリジナルCPUクーラー 虎徹 Mark II

このフィルムに気が付かずにそのままマザーボードに付けちゃう事例があるみたいなのでみなさまもお気をつけください。

結構でかい。

僕のマザーボードはソケットがLGA 1366なので、裏面にベースプレートを取り付ける必要がある。取り付けるとこんな感じ。

表面には裏面のベースプレートを固定するためのスペーサー蒹固定具をつける。

そんで上に乗っける。おぉ~。サイドフローのファンって初めて。

ケースファン

ケースファンもお世辞には回っていると言えない惨状だったので購入。

別にこだわりとかないのでコスト重視。
写真撮り忘れちゃたけど、ギュンギュン回って最高です。

Bluetooth

Bluetoothもついてねーのかよ!って言われそうだけど、昔のPCなもんでね!
ちなみに無線LANも搭載してないよ!!!

これも特にこだわりはないのでテキトウに。

電源投入

ホントにめっちゃ恐る恐る電源を入れたら静かに稼働しだした。異常があるのか?って疑いたくなるほど今のファンって静かなんですね。
でもマザーボードは未だに古いものを使用しているまま。いつ逝ってもおかしくはないので、徐々に新しいものを揃えていこうと思う。

ちなみにデュアルディスプレイだったのも今は1枚壊れてシングル状態になっている。
ついでに、新しいディスプレイを注文した。


これでやっと快適な開発環境がもどってくる!!

【悲報】ワイのPCが火を噴く(物理)

f:id:tk_thunder:20180226225235p:plain

比喩表現でよくある、「俺の○○が火を噴くぜ」という言葉が現実になりました。
比較的分かりやすくお伝えすると、デスクトップPCが火を吹きました。

以上です。


さて、いったいなぜこんなことになったのか…

デスクトップPCは8〜9年位前に大学生の僕がせっせとアルバイトをしてBTOで買ったものだ。

そして1年前に起動しなくなった。僕のスマホアプリ開発やその他もろもろのプログラミングを支えてくれた相棒だった。

それ以来、MacBook Airでおおよそすべてのことを凌いでいたが、やはりマシンパワーが足りない。

そして思い立った。ケース、OSはそのままでマザボとか諸々換装すればよくね?と。

まずは現状把握ということで、軽くPC内を掃除をして試しに起動させてみた。

普通に起動した。

あ、あれ…。起動してるやんけ…

もしかして、グリス塗り直してCPUクーラーをつけ直したからかな。

でも、起動時にFan errorが出てる。所定の回転数まで届いてないのかな?

というわけで、CPUファンを変えることにしました。少しずつ部品を変えていく作戦です。

そして新たに購入したのが 虎徹 弐(コテツ マークツー)

サイズ オリジナルCPUクーラー 虎徹 Mark II

サイズ オリジナルCPUクーラー 虎徹 Mark II

超ウキウキで取り付けをすませ、電源をONにする。

勢い良くコテツが回り始める。

うぉぉ!回ってる!!!(あたりまえ)

しかし今度はCMOS Errorが発生。

BIOSで時間とかをセットして、再起動するとなかなかWindowsの画面が表示されない。

う〜んと思いつつ、一旦再起動する。

CMOSエラーは出なくなったけど、またもやWindowsの画面が表示されない。

一旦電源切ろう…と電源ボタンを押した瞬間…

バチバチバチっという音とともに電源ユニットのあたりから激しく火花が散る。

f:id:tk_thunder:20180226225235p:plain

「うぉぉ!?」という叫びが止む頃にはPCは沈黙していた。

部屋の中にプラスチックが焦げる匂いが立ち込める。

すぐさま電源プラグを引っこ抜き、PCをバラす。

電源が死んでいるのでどこまでぶっ壊れたか確認できないが、とりあえずHDDは無事だった。

電源から火花が出ていたので、電源を外してバラしてみると…

こんなにホコリが詰まっている。もはやスパークしてくれと言っているようなものである。

そういえば電源の掃除だけは一回もしていなかった。一生の不覚である。

家が火事にならなくて本当に良かったと思いながら、電源ユニットを注文した。

こりゃマザボもメモリもCPUも取り替えかなぁ…

みなさんも電源周りのホコリには十分お気をつけください。

【Azure+Nodered】Azure上にNoderedの環境を用意するメモ

f:id:tk_thunder:20180218091051p:plainf:id:tk_thunder:20180218091041p:plain

はじめに

前々回の記事について、Azure上のDBに向けてラズパイ上で動かすNoderedからデータを飛ばす旨で書いたんですが…何をトチ狂ったかAzure上にNoderedを展開することについても書いていました。混乱させてしまい申し訳ないです。あの時の僕はどうかしてたんだ。

tk-thunder.hateblo.jp


というわけで、分量も多くないのでこちらにメモ程度に記しておきます。

Azure上にNoderedの環境を用意する

※記事の中にgitのリポジトリを設定する部分がありますが、僕は2つめの記事に従って設定しました。
qiita.com

qiita.com

【Raspberry Pi】IoT入門 Azure+Noderedで環境データを見える化作戦 Part2

f:id:tk_thunder:20180213184914p:plain

はじめに

さてさて、前回は本当に疲れましたね。
tk-thunder.hateblo.jp

今回でケリをつけてやりましょう。今回やることはこんな感じです。

  • Noderedのフロー構築
  • Noderedで環境データを定期的に取得
  • AzureのDBに環境データをアップする
  • AzureのDBにアクセスして環境データをグラフ化する

Nodered起動(ようやく登場だよチクショウ!)

まずは、ラズパイ上のNoderedを起動します。
僕はOS Stretchをインスコしているので、Noderedは最初から存在しています。
もしNoderedが入っていなかったらインストールしておきましょう。

参考
qiita.com

まずはNoderedをアップデート。

$ sudo update-nodejs-and-nodered

アップデートが完了したらNoderedを起動。
Noderedを自動起動にしたい場合は下記のコマンドで設定。僕は自動起動にしておきます。

$ sudo systemctl enable nodered.service

それではNodered起動です。

$ sudo node-red-start

実行ログ

Start Node-RED

Once Node-RED has started, point a browser at http://192.168.xx.xx:1880
On Pi Node-RED works better with the Firefox or Chrome browser

Use sudo systemctl enable nodered.service to autostart Node-RED at every boot
Use sudo systemctl disable nodered.service to disable autostart on boot

To find more nodes and example flows - go to http://flows.nodered.org
12 Feb 20:36:15 - [info]

Welcome to Node-RED

ノード追加

Dashboard

表示されているIPにアクセスするとNoderedのフロー編集画面が表示されます。
次にNoderedにノード追加していきましょう。
右上のメニューを表示して[パレットの管理]。
f:id:tk_thunder:20180212210751p:plain

最初に追加するのはグラフなどUIを提供してくれる[dashboard]
[ノードを追加]に[dashboard]と入力して画像のノードを追加。
f:id:tk_thunder:20180212210756p:plain

はいエラー!!!
だ、大丈夫だ、落ち着いて…(震え声

module.js:471
throw err;
^

Error: Cannot find module '/root/.node-red/node_modules/node-red-dashboard/fixfa.js'
(以下略)

まずはこの記事で足りないモジュールをインストールして、ラズパイを再起動。
qiita.com

もっかいノードの追加にトライ!
オッケーですね。追加されると左のノード一覧にこんな感じに表示されます。

f:id:tk_thunder:20180212210801p:plain

MSSQL

続いてMSSQLに接続するためのノードを追加します。
[パレットの管理]から[ノードを追加]で[MSSQL]と検索。
画像のノードを追加します。
f:id:tk_thunder:20180212210802p:plain

追加されるとこんな感じです。
f:id:tk_thunder:20180212210805p:plain

フロー構築

さて、準備が整ったらNoderedのフローを構築していきましょう。
ノードの一覧から画像のようにフローを作成しました。

やっていることはこんな感じです。

  1. 10分毎に処理を実行
  2. 各センサーからデータを取得してデータベースに書き込む
  3. データベースからデータを取得する
  4. データをチャートに表示するように整形する
  5. チャートに渡して表示する

f:id:tk_thunder:20180213190003p:plain

クリップボード(コピーしてNoderedに貼り付けると同じのができます)
コピー:右上のドロワーをクリック→[読み込み]→[クリップボード]→下のJSONを貼り付ける

[{"id":"e810a0b3.f3ec38","type":"function","z":"fe3fcd41.22fef","name":"温度・湿度","func":"var temp = [];\nvar hum = [];\n\nfor(var i = 0; i < msg.payload.length; i++)\n{\n    var n = msg.payload[i];\n    \n    var time = n.register_at;\n    // y軸とx軸の設定 それぞれ取得したデータを設定\n    temp.push({\"y\":n.temperature, \"x\":time.toString()});\n    hum.push({\"y\":n.humidity, \"x\":time.toString()});\n}\nmsg.payload = [{\"series\":[\"温度[℃]\",\"湿度[%]\"],\"data\":[temp,hum], \"labels\":[\"test\"]}];\nreturn msg;","outputs":1,"noerr":0,"x":611,"y":322,"wires":[["f2018d3a.5014b8","358a5d7c.9ce102"]]},{"id":"c740f89b.d467f8","type":"inject","z":"fe3fcd41.22fef","name":"定期実行","topic":"","payload":"","payloadType":"date","repeat":"600","crontab":"","once":true,"onceDelay":"10","x":128,"y":179,"wires":[["baa536f8.a514b","ef91a84.a68eed8"]]},{"id":"baa536f8.a514b","type":"exec","z":"fe3fcd41.22fef","command":"(例)sudo python3 /home/pi/python/bme280db/bme280db.py","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"環境データ取得","x":429,"y":169.5,"wires":[["4c0b3340.37224c"],[],[]]},{"id":"4c0b3340.37224c","type":"debug","z":"fe3fcd41.22fef","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":691,"y":155,"wires":[]},{"id":"ef91a84.a68eed8","type":"MSSQL","z":"fe3fcd41.22fef","mssqlCN":"2d4a26c3.ec7902","name":"Azure接続","query":"(クエリを記述)\nSelect *\nFrom **********","outField":"payload","x":379,"y":282,"wires":[["e810a0b3.f3ec38","2796d5ef.8f52aa"]],"inputLabels":["msg.payload"]},{"id":"358a5d7c.9ce102","type":"debug","z":"fe3fcd41.22fef","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":817,"y":370,"wires":[]},{"id":"f2018d3a.5014b8","type":"ui_chart","z":"fe3fcd41.22fef","name":"","group":"e9bee9b8.1c9bd","order":0,"width":0,"height":0,"label":"Labo 温度/湿度","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"bezier","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"86400","cutout":0,"useOneColor":false,"colors":["#D62728","#1F77B4","#FF7F0E","#2CA02C","#98DF8A","#D62728","#FF9896","#9467BD","#C5B0D5"],"useOldStyle":false,"x":833,"y":294,"wires":[[],[]],"inputLabels":["msg.payload"]},{"id":"2796d5ef.8f52aa","type":"function","z":"fe3fcd41.22fef","name":"気圧","func":"var pres = [];\n\nfor(var i = 0; i < msg.payload.length; i++) \n{\n    var n = msg.payload[i];\n    var time = n.register_at;\n    // y軸とx軸の設定 それぞれ取得したデータを設定\n    pres.push({\"y\": n.pressure, \"x\": time.toString()});\n}\nmsg.payload = [{\"series\": [\"気圧[hPa]\"], \"data\": [pres], \"labels\": [\"test\"]}];\nreturn msg;","outputs":1,"noerr":0,"x":580,"y":455,"wires":[["96de0c0d.83b22","97548ee1.546e5"]]},{"id":"96de0c0d.83b22","type":"ui_chart","z":"fe3fcd41.22fef","name":"","group":"e9bee9b8.1c9bd","order":0,"width":0,"height":0,"label":"Labo 気圧","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"bezier","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#FF7F0E","#AEC7E8","#FF7F0E","#2CA02C","#98DF8A","#D62728","#FF9896","#9467BD","#C5B0D5"],"useOldStyle":false,"x":769,"y":431,"wires":[[],[]],"inputLabels":["msg.payload"]},{"id":"97548ee1.546e5","type":"debug","z":"fe3fcd41.22fef","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":769.5,"y":495,"wires":[]},{"id":"2d4a26c3.ec7902","type":"MSSQL-CN","z":"","name":"任意の名前","server":"***********.database.windows.net","encyption":true,"database":"データベース名"},{"id":"e9bee9b8.1c9bd","type":"ui_group","z":"","name":"Labo","tab":"af51bbaf.922318","disp":true,"width":"12","collapse":false},{"id":"af51bbaf.922318","type":"ui_tab","z":"","name":"Labo環境データ","icon":"dashboard"}]
Injectノードの設定

フローの最初のノードです。実行タイミングなどを指定します。
今回はNoderedがスタートして10秒後に1回実行。その後は10分間隔で実行するように設定しました。

f:id:tk_thunder:20180213213002p:plain

MSSQLノードの設定

ノードをダブルクリックすると編集画面が開きます。
ここでは取得したいデータのクエリを記述しましょう。

f:id:tk_thunder:20180213211840p:plain

クエリ編集画面でペンマークをクリックすると、接続設定の画面が開くのでデータベースの情報を入力します。

f:id:tk_thunder:20180213211627p:plain

execノードの設定

このノードで環境データを取得するPythonを実行するコマンドを記述します。
例えばこんな感じです。

f:id:tk_thunder:20180213211917p:plain

チャートの設定

チャートはこんな感じです。てきとーでいいよ

f:id:tk_thunder:20180213211929p:plain

設定を開いて受け取るデータを記述しましょう。[msg.payload]

f:id:tk_thunder:20180213211614p:plain

さて、これで完璧ですね。
10分待たずとも、Injectノードの左端をクリックするとタイミング関係なく実行してくれます。
チャートを確認してみましょう。右端の[ダッシュボード]タブをクリックし、その下のよくわからないボタンをクリックします。

f:id:tk_thunder:20180213213440p:plain

問題なくデータが取れればチャートにはこんな感じに表示されます。
f:id:tk_thunder:20180213213542p:plain

いい感じです!
ここまで来るのに死ぬほど手間がかかりましたけど、形になると達成感が半端ないです。
手順も分かったので、次は今回の半分以下の時間で実現できますね。
さーて、お次は照度センサーを搭載して明るさの測定とかやってみたいですね!!!

【Raspberry Pi】IoT入門 Azure+Noderedで環境データを見える化作戦 Part1

はじめに

前回の記事でラズパイとBME280を使用して温度、湿度、気圧がとれました!
今度は取得したデータをAzureにアップします。なんだかそれっぽいですよね(それって何だ)
※タイトルにNoderedと入っていますが、このPartではまだ出てきません!!ごめんね!

環境用意

さて、まずはMicrosoftのAzureに環境を用意しなければいけませんね。
これらの記事を見ながら設定しました。

DBの作成はこの記事で。
tamafuyou.hatenablog.com

DBができたらテーブルを作ろう。
Azureのクエリエディタを使うならこんな感じ。


そんでクエリを書いて、実行を押せばテーブルができます。テーブルの名前は任意でつけてください。

CREATE TABLE test_table
(
     tempreture  float DEFAULT NULL
    ,humidity float DEFAULT NULL
    ,pressure float DEFAULT NULL
    ,regiater_at datetime DEFAULT getdate()
    ,CONSTRAINT regiater_at PRIMARY KEY CLUSTERED 
    (
      regiater_at
    )
)

pythonからAzureに接続

怒りのインストール編

まずは、odbcドライバをインストール

pythonで使用できるodbcドライバを検索

$ apt-cache search odbc | grep python

ラズパイにドライバインストール

$ sudo apt-get install python-pyodbc

pythonのライブラリをインストール

$ sudo pip3 install pyodbc


ここでお待ちかねのエラー発生!!

src/pyodbc.h:56:17: fatal error: sql.h: そのようなファイルやディレクトリはありません
#include
^
compilation terminated.
error: command 'arm-linux-gnueabihf-gcc' failed with exit status 1

Command "/usr/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-pn8_m4v_/pyodbc/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-in8uz67z-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-pn8_m4v_/pyodbc/

 

以下stack overflowを参考に足りないモノを追加でインストール
stackoverflow.com

ワイ氏、怒りのインストール

$ sudo apt-get install unixodbc
$ sudo apt-get install unixodbc-dev
$ sudo apt-get install freetds-dev
$ sudo apt-get install tdsodbc
$ sudo apt-get install freetds-bin

ふえぇ…泣きそう。

でもこれでやっとインストールできるよ!ヤッター

$sudo pip3 install pyodbc

できた(白目

Successfully built pyodbc
Installing collected packages: pyodbc
Successfully installed pyodbc-4.0.22

絶望のDB接続編

さて接続。ここからがとてつもなく長かった。
まずはFreeTDSの接続用ファイルを作成する。

こちらの記事を参考にして dsn.template を用意。

qiita.com

参考に。

[AZURE] ←データソースの名前
Description=AZURE
Driver=/usr/lib/arm-linux-gnueabihf/odbc/libtdsodbc.so
Setup=/usr/lib/arm-linux-gnueabihf/odbc/libtdsS.so
Trace=No
Server=xxxxxxxxxx.database.windows.net(Azule上のサーバ名)
Database=xxxxxx(接続するDB名)
Port=1433
TDS_Version=8.0
ClientCharset=UTF-8

ドライバの場所は記事とは違ったのでみなさんも適宜修正してください。
作成できたら下記のコマンドでインストール(内容を)

$sudo odbcinst -i -s -l -f dsn.template


手始めに isql で接続確認。

$isql -v データソースの名前 ユーザ名 パスワード

上記を入力して…よし実行だ!

Connected!

sql-statement
help [tablename]
quit

SQL>

うおおおおおおおおお、きたああああああああ!!

試しにSQLにAzureのデータベースバージョンを出力してみる。

SQL> SELECT @@version

Microsoft SQL Azure (RTM) - 12.0.2000.8
Nov 29 2017 09:37:51
Copyright (C) 2017 Microsoft Corporation

や っ た ぜ !

もしもここでエラーが出る場合、下記の理由が考えられます。

  • dsn.templateの設定にミスがある。

もう一度内容を確認してください。ここでハマると少々やっかいです

  • AzureのファイアウォールにクライントIPを許可していない

Azureダッシュボード→SQLデータベース→該当のDBをクリック→詳細画面上部のサーバーファイアウォールの設定
→クライアントIPをコピーして開始、終了にコピーしたIPを入力。接続の名前をつけて保存

ここまできたら、あとはラズパイで取得した環境データをPythonからDBに流し込むだけだろう…と楽観視していたときが私にもありました。

よもやここから実働6時間くらいハマることになるとは、この時の僕はまだ知らない。

まずはPythonでDBにアクセスするプログラムを作成する。
最終的にgitに上げた感じになりました。
何かあっても責任はとれませんが、ご自由に利用してください。

・bme280db.py(メインプログラム これを実行します)
・connect_ms.py(ご自身が使用するDBの設定に書き換えてください)

github.com


さてここで問題発生。
上記のプログラムは正常に動作するが、ある一部分の間違いにより下記のエラーを1000回くらい見る羽目になった。

Traceback (most recent call last):
File "connect_ms.py", line 41, in
(中略)
pyodbc.InterfaceError: ('IM002', '[IM002] [unixODBC][Driver Manager]Data source name not found, and no default driver specified (0) (SQLDriverConnect)')

いつもより2時間も夜更かしした上に結局解決しないし。モヤモヤして夜中に目が覚めるしで最悪のユーザ体験だった。
さて問題の部分は下記である。

# 接続文字列作成
con_string = 'DSN = %s;UID = %s;PWD = %s;DATABASE = %s;' % (dsn, user, password, database)

さて、どこが間違っているか分かりますかな??

じゃあ見比べてみよう!(ブチギレ)

正:con_string = 'DSN=%s;UID=%s;PWD=%s;DATABASE=%s;' % (dsn, user, password, database)
誤:con_string = 'DSN = %s;UID = %s;PWD = %s;DATABASE = %s;' % (dsn, user, password, database)

気が付きましたか?そう、接続文字列のイコール前後に空白が入っていたんです!

ふぁーーーーーwwwwwwwwwwwwwwwwwwwwww

こんなことで一晩悩んだなんて意味が分からん!!!!

さて、気を取り直して続きをやりましょう。
Part2へ続く。