Raspberry Pi入門〜Pythonで電源ランプ制御〜
ほったらかしラズパイをやっと動かしてみた
PyConJPで電子工作のセッションを聞いて勢いでラズパイを買ったものの、買って満足してしまい。。。
今年もPyLadiesアドベントカレンダー参加したいなあ、と思っていたのでこのタイミングでラズパイ始めました!
この記事ではPythonコードからRaspberry Piの電源ランプをチカチカさせます
秋葉原の書泉で買ったスターターキットと入門書(付属のSDカードはRaspbianインストール済)
準備.ラズパイ起動
ラズベリーパイをモニター、マウス、キーボードと繋げて電源に接続
モニターが虹色に(壊れたのかと思った・・・)少し経つとラズベリーが
Raspbianのホーム画面が表示された!画面から日本語設定、wi-fi設定をして準備完了!
電源ランプの設定ファイルを編集
ここからはこの記事をお手本にしました
Raspberry Pi 3の電源ランプ、アクセスランプでLチカをする
※初心者のため説明に誤りがあるかもしれません。。。
写真左下にある2つのランプを制御します
- 上がSDカード読み込み時に点灯する緑ランプ(led0)
- 下が電源接続時に常に点灯している赤ランプ(led1)
右のトゲトゲ(コネクタピン)には番号があり、この20番と22番の出力命令を上のランプにそれぞれ流すようにランプの設定ファイルに追記する
※電源を消して再度つけた時はこのコマンドを実行しないと以降のpythonが効かないので注意
sudo su echo gpio > /sys/class/leds/led0/trigger echo 20 > /sys/class/leds/led0/gpio echo gpio > /sys/class/leds/led1/trigger echo 22 > /sys/class/leds/led1/gpio exit
ランプを制御するPythonコードを記述
20番、22番ピンにランプをつける(GPIO.HIGH)消す(GPIO.LOW)の命令をする
1秒間隔で点灯・消灯を繰り返すようにしています
import RPi.GPIO as GPIO from time import sleep Green=20 Red=22 GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(Green, GPIO.OUT, initial=GPIO.LOW) GPIO.setup(Red, GPIO.OUT, initial=GPIO.LOW) try: while True: GPIO.output(Green, GPIO.HIGH) sleep(1) GPIO.output(Green, GPIO.LOW) sleep(1) GPIO.output(Red, GPIO.HIGH) sleep(1) GPIO.output(Red, GPIO.LOW) sleep(1) except KeyboardInterrupt: pass GPIO.cleanup()
このコードをpyファイルにしてsudoで実行すればランプがチカチカ!
sudo python3 ファイル名.py
React Nativeを始めてみた
やっとReact Native始めました
夏頃からReact Nativeやるぞ〜と言って早数ヶ月…すっかり寒くなってしまった
今日やっとReact Nativeに入門しました!!
React NativeはJavaScriptフレームワークReactのモバイル版で、1つのコードでiOSとAndroidどちらでも動くクロスプラットフォームが実現できる!
(Reactやったことないんだが、大丈夫かな)
開発環境を構築する
このQiita記事の通りにやっただけですが、書いていきます
また、今回はAndroid環境のみです
React Nativeをインストール
既にNode.js、npmはインストール済みだったので
Homebrewでファイルのバージョン管理ライブラリ?のwatchmanをインストール
(Qiitaに書いてあったからインストールしました これはなくても良いのかも)
brew update brew install watchman
npmでReact Nativeをインストール
npm install -g react-native-cli
AndroidStudioの設定
私の環境ではOreoのみ入っていたので、QiitaにしたがってMarshmallowを追加しました
Google APIなどはデフォルトで入っているようだったので特に設定していません
あとはAndroidSDKにパスを通すだけ
vi ~/.bash_profile # .bash_profileの末尾に以下を追加して保存 export ANDROID_HOME=$HOME/Library/Android/sdk export PATH=$PATH:$ANDROID_HOME/tools export PATH=$PATH:$ANDROID_HOME/platform-tools
React Nativeプロジェクトを作成
あとはコマンドでプロジェクトを作成して実行するだけ!
以下のコマンドでReact Nativeプロジェクトを作成します
# 事前にプロジェクトを作るディレクトリに移動しておく react-native init プロジェクト名
React Nativeプロジェクト実行!
プロジェクトが作成されたら、AndroidStudioを起動した状態でスマホを接続
AndroidStudio画面上部に接続したスマホが表示されていればOK
それでは実行!
cd プロジェクト名 react-native run-android
ん!?openjdkの開発元を検証できないため開ません!?
システム環境設定-セキュリティ-一般からopenjdkを許可すればいいみたい
これで再度react-native run-android
を実行するとプロジェクトのビルドが成功!
スマホにこんな画面が表示されました
Kotlin入門 おみくじアプリを作ってみた
簡単なアプリを作りました
アプリを起動時 ボタンを押すとおみくじ結果画面に遷移します
おみくじ結果画面 3秒ほど「Fortune Telling...」と表示され、結果が表示されます
githubで公開しています Kotlin学習にどうぞ! https://github.com/butorisa/fortune-app
※画像には表示されていませんが、利用しているAPIのリンク・占い提供元のリンクを3枚目画面の下部に表示するようにしました
アプリの概要
- 開発端末OS:Android 8.1.0(Oreo)
- 利用API:Web ad Fortune 無料版API
HTTP通信ライブラリ:OkHttp3
MainActivity
- ActionBar(正確にはToolBar)のみ
- 画面部分はFragmentで描画
- EntryFragment
- 起動時の画面(1枚目)
- MainActivityの上から描画
- FortuneResultFragmentに遷移するボタンを保持
- FortuneResultFragment
- FortuneResultBean
- RestApiClient
MainActivity
MainActivityはActionBarしかない空っぽの画面なのでEntryFragmentを表示するだけ アプリテーマを「NoActionBar」にしているのでActionBarの設定コードを書いている
/** * Activity描画 */ @RequiresApi(Build.VERSION_CODES.O) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // actionbar val toolbar = findViewById<Toolbar>(R.id.toolbar_fortune) toolbar.title = "pretty chipper" setSupportActionBar(toolbar) // EntryFragment描画 val transaction = supportFragmentManager.beginTransaction() transaction.addToBackStack(null) transaction.replace(R.id.container, EntryFragment()) transaction.commit() }
EntryFragment
inflater.inflate()
でFragmentのxmlファイルをバインド
ボタンに押下時の処理を設定
/** * EntryFragment描画 */ override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { super.onCreateView(inflater, container, savedInstanceState) val view = inflater.inflate(R.layout.fragment_entry, container, false) // ボタン押下でFortuneResultFragmentに移動 view?.findViewById<Button>(R.id.button_telling_fortune)?.setOnClickListener { val transaction = fragmentManager?.beginTransaction() transaction?.addToBackStack(null) transaction?.replace(R.id.container, FortuneResultFragment()) transaction?.commit() } return view }
FortuneResultFragment
onCreateView()
で画面描画時にCoroutineを使って非同期で占いAPIを実行
APIのURLには「yyyy/MM/dd」形式で現在日付をつけると本日の占い結果が返却される
APIレスポンスが返ってきたら、TextViewに占い結果を設定
レスポンスjsonを全てgetJSONObject()
で取得するのは面倒なので、12星座の運勢のレスポンス部分だけBeanクラスを作りマッピング
/** * FortuneResultFragment描画 */ @RequiresApi(Build.VERSION_CODES.O) override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { super.onCreateView(inflater, container, savedInstanceState) val view = inflater.inflate(R.layout.fragment_fortune_result, container, false) /* Coroutine start */ this.lifecycleScope.launch { // call API withContext(Dispatchers.Default) { val url = "http://api.jugemkey.jp/api/horoscope/free/" + getCurrentDate() RestApiClient().requestGet(url) }.let { delay(2000) // mapping json to bean val fortuneResult = parseJson(getCurrentDate(), it) // set TextView view?.findViewById<TextView>(R.id.fortune_content)?.text = fortuneResult.get((0..11).random())?.content // TODO ランダムな星座を表示 // ボタン押下で前画面へ移動 view.findViewById<Button>(R.id.button_back_to_entry).setOnClickListener { fragmentManager?.popBackStack() } } } /* Coroutine end */ return view } /** * 現在日付取得 * @return 現在日付(yyyy/MM/dd) */ @RequiresApi(Build.VERSION_CODES.O) fun getCurrentDate(): String { val today = LocalDate.now() val dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd") return dateFormatter.format(today) } /** * json→FortuneResultBean変換 * @param today:現在日付(yyyy/MM/dd) * @param strJson:レスポンスjson * @return 運勢一覧(FortuneResultBeanリスト) */ private fun parseJson(today: String, strJson: String): List<FortuneResultBean> { val json = JSONObject(strJson) // remove "\" from json-property val strResult = json.getJSONObject("horoscope").getString(today.replace("\\", "")) return ObjectMapper().readValue(strResult, object: TypeReference<List<FortuneResultBean>>(){}) }
FortuneResultBean
占いAPIの運勢部分のjsonをマッピングするBeanクラス このBeanクラスを12星座分のリストにして受け取る
/** * 占いAPIレスポンスBean */ class FortuneResultBean { @JsonProperty("content") var content: String? = null @JsonProperty("money") var money: String? = null @JsonProperty("job") var job: String? = null @JsonProperty("love") var love: String? = null @JsonProperty("total") var total: String? = null @JsonProperty("item") var item: String? = null @JsonProperty("color") var color: String? = null @JsonProperty("day") var day: String? = null @JsonProperty("rank") var rank: String? = null @JsonProperty("sign") var sign: String? = null }
RestApiClient
OkHttp3を利用してGETリクエスト レスポンスボディをString型のまま呼び出し元へ返す
/** * GETリクエスト * @param APIリクエストURL * @param リクエストパラメータ * @return APIレスポンス(String) */ @RequiresApi(api = Build.VERSION_CODES.N) fun requestGet(url: String, vararg param: String?): String { val request = Request.Builder().url(url!!).build() val httpClient = OkHttpClient() try { val response = httpClient.newCall(request).execute() return response.body!!.string() } catch (e: IOException) { // TODO handle exception e.printStackTrace() } // TODO Handle Exception throw NullPointerException() } companion object { private val JSON: MediaType = "application/json; charset=utf-8".toMediaTypeOrNull() as MediaType }
きれいに書くよう意識しました
今までとりあえず動くことだけ意識していたのですが、後で見返すと分かりづらい。。。 FragmentにあるボタンのクリックリスナーをActivityに書いていたり、API呼び出し関数にUI操作を書いていたり、不要な変数を宣言していたり… このあたりをスッキリするようにコーディングしてみました Androidのコード設計、デザインパターンも意識しながらコーディングできるようになりたい!
Docker ElasticSearchでPDF全文検索
ElasticSearchイメージでサクッと全文検索してみる!!
ElasticSearch環境構築
#elasticsearchイメージをダウンロード docker pull elasticsearch # コンテナ作成・起動 docker run -it -d --name elastic_search -p 9200:9200 -p 9300:9300 -v C:¥Users¥buto¥share:/mnt/share elasticsearch
全文検索に使うプラグインをインストール
# コンテナに入る docker exec -it elastic_search /bin/bash ###### ここからコンテナ環境 ###### # ログイン直後はrootユーザー su - elasticsearch # elasticsearch-pluginコマンドでプラグイン操作 elasticsearch-plugin install kuromoji # 日本語対応 elasticsearch-plugin install analysis-icu # 文字の解析器 elasticsearch-plugin install ingest-attachment # ESにファイルを取り込む # プラグインが追加された elasticsearch-plugin list # analysis-icu # analysis-kuromoji # ingest-attachment
プラグインをElasticSearchに反映させるためにコンテナ再起動(Docker for Windows GUIから実行)
※ コンテナ内でsudo systemctl elasticsearch restart
できなかった。。。
PDFを取り込むパイプラインを作成
以下のリクエストでPDFをElasticSearchに流すパイプラインを作成する
curl --location --request PUT 'http://localhost:9200/_ingest/pipeline/attachment' --header 'Content-type: application/json' --data-raw '{ "description" : "sample mapping", "processors" : [ { "attachment" : { "field" : "data", "indexed_chars" : -1, "properties" : [ "content", "content_type" ] } } ] }'
attachmentという名前のパイプラインができる!
文字解析器を作成
PDFの文章を2~3文字ずつ区切って解析するよう設定
curl --location --request PUT 'http://localhost:9200/ngram_1' --header 'Content-type: application/json' --data-raw '{ "settings": { "analysis": { "analyzer": { "my_ja_analyzer": { "type": "custom", "tokenizer": "my_tokenizer", "char_filter": [ "icu_normalizer", "kuromoji_iteration_mark" ], "filter": [ "kuromoji_baseform", "kuromoji_part_of_speech", "ja_stop", "kuromoji_number", "kuromoji_stemmer" ] } }, "tokenizer": { "my_tokenizer": { "type": "ngram", "min_gram": 2, "max_gram": 3, "token_chars": [ "letter", "digit" ] } } } }, "mappings": { "properties": { "attachment.content": { "type": "text", "analyzer": "my_ja_analyzer", "search_analyzer": "my_ja_analyzer" } } } }'
ngram_1という名前の解析器が作成される
PDFデータをBase64エンコード
HTTPリクエストボディでPDFをパイプラインに送るため、PDFファイルをBase64エンコードする ElasticSearchのVM(Linux)で以下のコマンドを実行
base64 -w 0 sample.pdf > sample.txt
sample.txtにBase64エンコードした内容が出力される
PDFをパイプラインに投入
curl --location --request POST 'http://localhost:9200/ngram_1/_doc/1?pipeline=attachment' --header 'Content-type: application/json' --data-raw '{ "index": { "_index": "ngram", "_type": "pdffile", "_id": "1", "pipeline": "attachment" }, "data": "sample.txtの中身" }'
これでElasticSearchにPDFの文章が取り込まれる!
文字列検索してみる
GETリクエストのqパラメータ
に検索したい文字列をセットする
curl --location --request GET 'http://localhost:9200/ngram_1/_search?q=検索ワード'
ヒットするとこんなレスポンスが返ってきます
{ "took": 34, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 2.7496266, "hits": [ { "_index": "ngram_1", "_type": "_doc", "_id": "1", "_score": 2.7496266, "_source": { "data": "sample.txtの中身", "attachment": { "content_type": "application/pdf", "content": "sample.txtをBase64デコードした内容" }, "index": { "pipeline": "attachment", "_index": "ngram", "_type": "pdffile", "_id": "1" } } } ] } }
ヒットしなかった場合はこんなレスポンス
{ "took": 6, "timed_out": false, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 0, "relation": "eq" }, "max_score": null, "hits": [] } }
やってみて
ElasticSearchのDockerイメージがあったので構築は楽でした! PDFを取り込むためのパイプライン、解析器の作成などが理解できず時間が掛かりました この設定で大体の日本語はヒットするのですが、ヒットするべきでないワードでもヒットしてしまうことが多々ありました… AWSのElasticsearchServiceもありますが、あちらはanalysis-icuがサポートされていなかったので、ヒットしてほしい時にヒットできないことがありました(AWSの方はプラグイン追加はできない) 全文検索をちょっと試してみたい時にどうぞ!!
Ruby インクリメント演算子が使えない理由
昨日、夜中の空腹をまぎらわせるためにRubyをインストールしてみました
今朝から制御構文などの基礎コードを書いていたのですが、num++
のような
インクリメント演算子が使えないことが分かり「なんで?」と気になったので調べました
理由:Rubyでは数値もオブジェクトだから
こちらのブログで分かりました! Ruby にインクリメント演算子のようなものが無い理由
インクリメント演算子が利用できない理由をRuby開発者が以下のように語っています
[ruby-list:5323] Re: Questions on specs and threads
3) 記号的な記法 これは単なる私の趣味ですが, 単項インクリメントとかがたまに欲しく なります. i += 1 でいいわけですが. i++ と書いて怒られる (^^; すんません.この件は以前から指摘されているのですが(演算子はC に似ているのに++と--は対応する演算子が無い),++の動作が本質 的に「変数を操作する」ものであるため,変数がオブジェクトでな いRubyでは導入できないでいます.++や--の「オブジェクト指向的 意味」がRubyの他の部分と整合性を保ったまま定義できれば採用し たいのですが….
Rubyは変数の操作をさせたくない言語なんですね 「変数がオブジェクトでない」ってどういうことなんだろう??
「Rubyでは変数がオブジェクトでない」とは
変数numは(numそのものが)オブジェクトではなくて、数値オブジェクトへの参照 → 1つの数値オブジェクトを共有している
# 変数numには123そのものではなく # 123へのアドレスが格納されている num = 123 puts num.object_id # 247が出力される num_cp = 123 puts num_cp.object_id # 247が出力される
変数はオブジェクトへの参照だから、「変数自体がオブジェクトでない」ってことなんですね
数値オブジェクトはimmutable
上記コードのようにnum
とnum_cp
は1つの数値オブジェクトを参照している
→ 数値オブジェクト「123(object_id:247)」自体が操作されたら、
参照している変数の値が全部変わっちゃう!!
なので、数値オブジェクトはimmutable(不変、final)になっている 以下のコードは変数の値を操作しているように見えるが、参照先を付け替えているだけ
cnt = 123 puts cnt.object_id # 247が出力される cnt = 456 puts cnt.object_id # 913が出力される
参照している数値オブジェクトを付け替えることによって数値オブジェクト自体は操作されずに 変数の値が操作されているように見える!
インクリメント演算子は数値オブジェクトの操作を意味する
もう一度、最初に引用した開発者のコメントを見てみます
++の動作が本質的に「変数を操作する」ものであるため,変数がオブジェクトでな いRubyでは導入できないでいます.
インクリメント演算子は数値オブジェクト自体に加算することを意味するので、 Rubyの「数値オブジェクトはimmutable」のルールと合わなくてサポートされていない
言語って奥が深い!!
Rubyでインクリメント演算子がサポートされていないことにもちゃんと理由があった! Pythonも同じ理由でインクリメント演算子をサポートしていないらしい(使えると勘違いしていた)
このテーマとは違いますが、調べている時に「各言語のメモリの使い方」の解説に遭遇して とても面白かったです メモリとスタックとヒープとプログラミング言語
Haskell VSCodeで実行できない
前回の記事でHaskellをIDEでコーディングするのに必要なツールが分かったので、早速試してみる!!
- OS:Windows10
StackからGHCをインストール
- Stackをインストール
- StackからGHCをインストール
stack setup
- GHCがインストールできたことを確認
stack ghc -- --version
- コンパイラがインストールできた!
The Glorious Glasgow Haskell Compilation System, version 8.8.3
haskell-ide-engineをインストール
- コマンドプロンプトの文字コードをUTF-8にしておく
chcp 65001
- haskell-ide-engine(HIE)をインストール
- あらかじめGitをインストールしておく
cd クローンするフォルダ
git clone https://github.com/haskell/haskell-ide-engine
cd haskell-ide-engine
stack ./install.hs hie
Version 1.4, Git revision e4972ff44c7649e3f53ffac37ae899410075aa0f (3903 commits) x86_64 ghc-8.8.3
stack ./install.hs data
stack install
ではなくstack ./install.hs
を使うのがポイントらしい
(StackのinstallコマンドではなくHIEのinstall.hsを使う)
VisutalStudioCodeをインストール
intelliJだとstack.exeを認識してくれなかったのでVSCodeでやってみる
- VSCodeインストーラをダウンロードしてインストール
- インストール後にVSCodeを起動して[Extensions]からプラグインを導入
- setting.jsonにHIEのパスを設定
"haskell.serverExecutablePath": "~/hie/haskell-ide-engine"
これでVSCodeを再起動するとHaskellのビルド・実行ができるはずだった…
あれ?Haskell実行できない??? (2時間経過) 一旦、コマンドら実行でいいや
Haskell 開発環境に必要なツール
HaskellもIDEでコーディングしたい
最近またHaskellに興味がわいてきて、再び入門することにしました これまではAtomなどのテキストエディタでコードを書いて、コマンドでコンパイル・実行していました 他の言語ではIDEを使っているのでHaskellもIDEで開発できるようにしたい!
この記事ではHaskell開発環境に必要なツールのまとめです
※正確にはライブラリ、プラグイン…などの言い方があると思いますが、まとめてツールと言っています
Haskellの実行に必要なツール
Haskellコードを書いてコンパイル・実行するためには以下が必要です - GHC(Glasgow Haskell Compiler) - Haskellコンパイラ - グラスゴー大学の先生?が開発したコンパイラで最もメジャーなHaskellコンパイラ - コンパイラのブランドって意識したことなかった。。。
プロジェクト作成・ビルドに必要なツール
- Stack
- Haskellプロジェクトの作成・ビルド・パッケージ管理ツール
- StackからGHCをインストールすることもできる
- Haskell Stack とは何をするツールなのか
Cabalというビルド・パッケージ管理ツールもありますが、初心者にはStackがおすすめと紹介されていたので私はStackを使います CabalとStackの違いは何ですか?
StackはCabalライブラリを使っているようです Cabalを使っているとcabal hell(カバル地獄)という恐ろしい事象があるみたい