Androidのメモとか

ポキオの日記です。今日も遅延してない。

M5STACKでデジタル名刺を作る

クールに自己紹介。

ポキオ M5STACK

M5STACKで何しよう?

relativelayout.hatenablog.com

前回、ノリで買ってしまったM5STACK。ノリで買ったのはいいものの、いい感じのユースケースが思い浮かびませんでしたが、後輩の@ktansaiがいい感じのデジタル名刺を作っていたので、早速パクらせていただきました(笑)

準備するもの

  • M5STACK
  • 表示する画像
  • Micro SDカード
  • パクってもいいじゃないかという強い心

正直言うと、SDカードではなく、画像を内蔵ストレージに書き込んでもいいのですが、それでは本家と全くおなじになってしまうので、私はSDカードに書き込んで、プログラムからそれを参照してみます。

画像

320x240のJPG画像を数枚用意しました。macOSKeynoteでテキトーに作りました。

プログラム

MicroPythonで書きました。

github.com

  • ButtonAとCを押すと、画像が変わる仕組みになっています。
  • SDカードはわざわざマウントしてあげる必要があります。
  • 画像の表示は便利関数が用意されています。
from m5stack import lcd
from m5stack import buttonA
from m5stack import buttonC
import uos
import utime

imageList = ["/sd/image1.jpg", "/sd/image2.jpg",
             "/sd/image3.jpg", "/sd/image4.jpg"]
position = 0

uos.mountsd()

lcd.clear()
lcd.image(0, 0, file=imageList[0], scale=0, type=lcd.JPG)

while True:
    if buttonA.wasPressed():
        position = position + 1
        lcd.clear()
        lcd.image(0, 0, file=imageList[position %
                                       len(imageList)], scale=0, type=lcd.JPG)
    if buttonC.wasPressed():
        position = position - 1
        lcd.clear()
        lcd.image(0, 0, file=imageList[position %
                                       len(imageList)], scale=0, type=lcd.JPG)

    utime.sleep(0.1)

いざプログラム実行!

いい感じっすねー。

ポキオ M5STACK

これで、ドヤ顔して勉強会にいけますね!

M5Stack Basic

M5Stack Basic

  • メディア: おもちゃ&ホビー

M5STACKことはじめ

エムファァァァイブスタアアアアアック!!!

ポキオ M5STACK

買ってしまった

M5Stack Basic

M5Stack Basic

  • メディア: おもちゃ&ホビー

M5STACKだけは絶対に買わない、そう思ってました。でも、気づいたら買ってました。どうも、ポキオです。買ったのは一番に安いBasic。色黒の子です。

ポキオ M5STACK

コンパクトなパッケージングをキープしながら、拡張性も両立しているところがすごいですねぇ。

ポキオ M5STACK

中身もギュッと詰まっています。

ポキオ M5STACK

unboxingの儀はこのくらいにして、とりあえずHello Worldしてみましょう。

M5Cloudにつないでみる

Arduino IDEでも開発できますが、せっかくなのでM5Cloudで開発してみます。Web上のIDEで、コンパイルとバイナリの流し込みもオンラインで実行できてしまいます。わざわざUSBで接続する必要は一切ありません。

github.com

このページのとおりにやれば簡単にセットアップでき・・・ると思ってたんですが、相変わらずmacOSのrootless系の問題にぶち当たったので、Pixel OSが動いているマシンでセットアップしてみました。基本的に公式ガイドに書いてある手順と変わりません。

ファームウェアのダウンロード

github.com

binファイルをダウンロード

esptoolでファームを焼く

まずpipesptoolをインストール。

pi@pokiiio-pixel:~ $ sudo pip install esptool

そんでもって、M5STACKをラップトップにUSB接続してから、M5Cloud用のファームを焼きます。

pi@pokiiio-pixel:~ $ esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
pi@pokiiio-pixel:~ $ esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash --flash_mode dio -z 0x1000 ./Downloads/m5cloud-20180516-v0.4.0.bin 

これでOK。

M5STACKとM5Cloudをリンクさせる

github.com

ここに書いてあることと同じなので詳細は割愛。

  • M5STACKがWi-Fi APとして動作するので、スマホでアクセスして家のAPなどを登録
  • M5STACK上にPIN CODEが表示されるので、M5Cloud上でそのPIN CODEを入力してリンクする
  • あとはM5Cloud上でプログラミングするだけ

Hello World

M5Cloud上で、MicroPythonでプログラミング。

ポキオ M5STACK

コード自体はシンプル。

from m5stack import lcd

lcd.clear()
lcd.setCursor(0, 0)
lcd.setColor(lcd.WHITE)
lcd.print("Hello, pokio!")

これで、Upload & Runすると・・・

ポキオ M5STACK

うぇーい!

京急遅延ガジェット「ダァ3号」が山手線に対応しました

まさかの国鉄対応。

ポキオ 京急 ダァ3号

ポキオ、異動する

いままでは京急一本で行けるオフィスだったのですが、今回異動をしましてオフィスも変わり、通勤経路に山手線に乗るというイベントが発生してしまいました。なので、ダァ3号を致し方なく山手線に対応させてみました。

安心と信頼のNode-RED

ポキオ 京急 ダァ3号

[{"id":"3ad520c3.545e78","type":"tab","label":"フロー 1","disabled":false,"info":""},{"id":"80cbf517.c17cc8","type":"twitter-credentials","z":"","screen_name":"@pokiiiwo"},{"id":"3eb4297b.7362fe","type":"twitter in","z":"3ad520c3.545e78","twitter":"80cbf517.c17cc8","tags":"@keikyu_official","user":"user","name":"京急公式Twitterに新しい投稿","topic":"tweets","inputs":0,"x":180,"y":100,"wires":[["60533152.38f37"]]},{"id":"22429d61.35d622","type":"inject","z":"3ad520c3.545e78","name":"京急 + 山手線","topic":"","payload":"","payloadType":"date","repeat":"600","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":140,"wires":[["60533152.38f37"]]},{"id":"60533152.38f37","type":"http request","z":"3ad520c3.545e78","name":"京急運行情報取得","method":"GET","ret":"txt","url":"http://unkou.keikyu.co.jp","tls":"","x":150,"y":180,"wires":[["77d3de0e.446b9"]]},{"id":"77d3de0e.446b9","type":"function","z":"3ad520c3.545e78","name":"京急運行情報パース","func":"msg.payload = msg.payload.split(\"<div class=unko-panel>\")[1];\nmsg.payload = msg.payload.split(\"</div>\")[0];\nmsg.payload = msg.payload.replace(/\\r?\\n/g,\"\");\nmsg.keikyu = msg.payload;\nmsg.payload = null;\nreturn msg;","outputs":1,"noerr":0,"x":160,"y":220,"wires":[["49eb60e7.4544c"]]},{"id":"49eb60e7.4544c","type":"http request","z":"3ad520c3.545e78","name":"JR運行情報取得","method":"GET","ret":"txt","url":"https://transit.yahoo.co.jp/traininfo/detail/21/0/","tls":"","x":140,"y":260,"wires":[["8119d93e.e43388"]]},{"id":"8119d93e.e43388","type":"function","z":"3ad520c3.545e78","name":"JR運行情報パース","func":"msg.payload = msg.payload.split(\"\\\"og:description\\\" content=\\\"\")[1];\nmsg.payload = msg.payload.split(\"(\")[0];\nmsg.payload = msg.payload.replace(/\\r?\\n/g,\"\");\nmsg.yamanote = msg.payload;\nmsg.payload = null;\nreturn msg;","outputs":1,"noerr":0,"x":150,"y":300,"wires":[["1fbe8bb5.87f034"]]},{"id":"6f00e56f.8150ec","type":"exec","z":"3ad520c3.545e78","command":"python /home/pi/GitHub/TextToEPaper/text_to_e_paper.py","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"電子ペーパーに表示","x":480,"y":280,"wires":[[],[],[]]},{"id":"1fbe8bb5.87f034","type":"function","z":"3ad520c3.545e78","name":"keikyu, yamanote -> payload","func":"msg.payload = \"京浜急行 \\\"\" + msg.keikyu + \"\\\" 山手線 \\\"\" + msg.yamanote + \"\\\"\";\nreturn msg;","outputs":1,"noerr":0,"x":500,"y":140,"wires":[["71e04a63.eb8114"]]},{"id":"7dac4a68.ffcf04","type":"inject","z":"3ad520c3.545e78","name":"","topic":"起動時","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"5","x":150,"y":60,"wires":[["60533152.38f37"]]},{"id":"71e04a63.eb8114","type":"switch","z":"3ad520c3.545e78","name":"差分があった場合だけ更新","property":"payload","propertyType":"msg","rules":[{"t":"neq","v":"info","vt":"global"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":500,"y":180,"wires":[["b6900e34.b64bb"],[]]},{"id":"b6900e34.b64bb","type":"function","z":"3ad520c3.545e78","name":"globalにセット","func":"global.set(\"info\",msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":460,"y":220,"wires":[["6f00e56f.8150ec"]]}]
  • メインのシーケンスはNode-REDで組み立てています。
  • (シーケンシャルですが)京急と山手線の運行情報をWebから取得しています
  • 山手線の運行情報はYahoo!から拝借
  • Global変数に、直前に表示させていた文字列を覚えておき、不要な画面書き換えを抑制

ちなみに、表示ロジックも変更。

github.com

Pythonスクリプトの引数とその数から、よしなに情報表示してくれます。よしなに。

番外編

こういうこともできます。

#iotlt も第40回!

A post shared by pokio (@pokiiiiio) on

エサヒィ。

エセヒィ #iotlt

A post shared by pokio (@pokiiiiio) on

GooglePhotoMarkdownerを更新しました

ちょっとだけ改善。

pokiiio googlephotomarkdowner

前回はオレオレElectronアプリを作りました

relativelayout.hatenablog.com

Google Photosにアップした写真を秒で、Markdown記法などでブログに埋め込める形に変換する俺得アプリを作りました。今回の改善ポイントは大きく2点です。

  • macOSで何故か出来ていなかったコピーアンドペーストに対応
  • 前回使った画像サイズ・代替テキスト・タイトルを永続化するように変更

地味に使いやすくなりました。

github.com

macOSで何故か出来ていなかったコピーアンドペーストに対応

なぜか出来てなかった。

pracucci.com

上記のワークアラウンドを鵜呑みにして、コードに追加しています。appのreadyで、以下のようにメニューを追加して、コピペに対応しています。

app.on('ready', function () {
    mainWindow = new BrowserWindow({ width: 800, height: 600 });
    mainWindow.loadURL('file://' + __dirname + '/index.html');
    // mainWindow.toggleDevTools();
    mainWindow.on('closed', function () {
        mainWindow = null;
    });

    var template = [{
        label: "Application",
        submenu: [
            { label: "About Application", selector: "orderFrontStandardAboutPanel:" },
            { type: "separator" },
            { label: "Quit", accelerator: "Command+Q", click: function () { app.quit(); } }
        ]
    }, {
        label: "Edit",
        submenu: [
            { label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
            { label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
            { type: "separator" },
            { label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
            { label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
            { label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
            { label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }
        ]
    }
    ];

    Menu.setApplicationMenu(Menu.buildFromTemplate(template));
});

前回使った画像サイズ・代替テキスト・タイトルを永続化するように変更

electron-json-storageJSONデータを永続化するようにしています。

npm install electron-json-storage --save

いつもどおり、こんな感じでインストールします。

var storage = require('electron-json-storage');
var data = {};
data.photoSize = "hogehoge";
data.photoAlt = "fugafuga";
data.photoTitle = "piyopiyo";
storage.set('config', data, function (error) {
    if (error) throw error;
    // 保存完了
});

保存はこんな感じで、JSONオブジェクトを作って保存します。

var storage = require('electron-json-storage');
storage.get('config', function (error, data) {
    if (error) throw error;
    if (Object.keys(data).length === 0) return;
    // dataを読み込む
});

読み込みはこんな感じで簡単に出来ます。

というわけで

オレオレElectron、最高ですね。

オレオレElectronアプリを作ってGooglePhotosの写真をブログに貼り付ける処理を効率化する

オレオレ。

GooglePhotoMarkdowner

Google Photosの写真をブログに

皆さんはブログに載せる写真をどこに保存してますでしょうか。私は面倒くさいので、よくGoogle Photosに写真をアップロードして、StackEditなどでその写真へのリンクを取得してMarkdownでブログに埋め込んでいます。

ただ、StackEditも最近UIをガラ変させてきたのが嫌なのと、StackEditに頼らずとも簡単にGoogle Photosの写真をブログに埋め込むべく、オレオレアプリをElectronで書いてみました。

コードの内容はこれと同じです。 relativelayout.hatenablog.com

GooglePhotoMarkdowner

github.com

文字通り、Google Photos上の写真へのリンクからMarkdown記法による画像埋め込みコードを生成します。

こんな感じです。

GooglePhotoMarkdowner

生成物は3つ。

まずは、Google PhotoへのリンクURLから、下記のような誰でもアクセスできるURLを生成します。

https://lh3.googleusercontent.com/xxxxx=s600

次に、同時にMarkdown記法の文字列も生成します。

![GooglePhotoMarkdowner](https://lh3.googleusercontent.com/xxxxx=s600 "GooglePhotoMarkdowner")

念のため、HTML記法の文字列も生成します。

<img src="https://lh3.googleusercontent.com/xxxxx=s600" alt="GooglePhotoMarkdowner" title="GooglePhotoMarkdowner">

はい、これで執筆が捗る。

Electronでアプリを作るときにハマったメモ

メモ。

electron tips

Electronはじめました

前回からElectronアプリを書き始めたんですが、何箇所かハマったのでメモ。

relativelayout.hatenablog.com

Zoomを無効にしたい

フツーにアプリをElectronで作ると、タッチパッドのピンチイン・ピンチアウトが効いてしまって、なんかアプリっぽくありません。

Zoomを無効化するには、webFrameを使うといいらしく、こんな関数を書いてみました。

function disableZoom() {
    var webFrame = require('electron').webFrame;
    webFrame.setVisualZoomLevelLimits(1, 1);
}

これをHTML上で実行するだけ。意外と簡単。

npm installしたモジュールがElectronアプリから呼び出せない

requireしても、モジュールが無いよって怒られる件。結局、npm installするときに--saveオプションを有効にしないとrequire出来ないっぽい。--save-devではだめっぽい。

それでもElectronでjQueryがundefinedになる

もう意味がわからない。

<script src="./node_modules/jquery/dist/jquery.min.js"></script>

こういう記述の代わりに、これを書けば解決できる。理由は知らない。

<script>
    window.jQuery = window.$ = require('./node_modules/jquery/dist/jquery.min.js');
</script>

stackoverflow.com

クリップボードの読み書きがしたい

こんな感じで出来ました。

var clipboard = require('electron').clipboard;
var hoge = clipboard.readText(); // クリップボードの値を読む
clipboard.writeText("fuga"); // クリップボードに値を書き込む

みなさんも、よいElectronライフを。

ElectronでmacOSアプリをチョッパヤで書いてみる

意外と簡単?

electron アプリ 開発

Electronとは?

これ。

electronjs.org

要はWeb技術でクロスプラットフォームアプリ開発が出来てしまう、すごいやつです。モバイルアプリではPhonegap・Cordovaなどが有名ですが、そのDesktop版といったところでしょうか。いままで書いてきたWebの資産が活かせそうなので、今回はmacOS向けに簡単なアプリを書いてみようと思います。

まずは準備

nodeやnpmが使える前提です。

まずは適当なところにフォルダを掘っておきます。

mkdir electron-test
cd electron-test

そのフォルダ直下で初期化して、electronelectron-packagerをインストール。 これで、Electronを使ってアプリを動作させる環境と、macOS向けにアプリという単位でバイナリを吐ける環境が整いました。

npm init -y
npm install electron --save-dev
npm install electron-packager --save-dev

いろんなサイトにかかれているお作法に則って、srcフォルダを掘ります。実際のアプリのコードはsrc内に書いていきます。

mkdir src

lsするとこんな感じ。

ls
node_modules        package.json
package-lock.json   src

おいおいElectronでアプリを実行したり、アプリとして配布できる形に書き出すときに必要なコマンドがありますが、それをpackage.jsonに上記のように書き込んでおくと、npm run startnpm run build-macOSのように簡単にコマンドを呼ぶことができるようになり便利です。

  "scripts": {
    "start": "electron ./src",
    "build-macOS": "electron-packager ./src electron-test --platform=darwin --arch=x64 --overwrite",
    "build-windows": "electron-packager ./src electron-test --platform=win32 --arch=x64 --overwrite"
  }

アプリの中身を書いていく

先述のとおり、src内でコードを書いていきます。そして、src直下でも初期化します。

cd src
npm init -y

上記コマンドで生成されたpackage.jsonを少し変更します。Electronではmain.jsが最初に読まれ、アプリのエントリポイントもmain.jsになるので、下記のようにmainを変更します。

  "main": "main.js",

そして、そのmain.jsを書いていきます。今回は、このサイトのコピペをさせていただきます・・・。

'use strict';

var electron = require('electron');
var app = electron.app;
var BrowserWindow = electron.BrowserWindow;

var mainWindow = null;

app.on('window-all-closed', function () {
    if (process.platform != 'darwin')
        app.quit();
});

app.on('ready', function () {
    mainWindow = new BrowserWindow({ width: 800, height: 600 });
    mainWindow.loadURL('file://' + __dirname + '/index.html');

    mainWindow.on('closed', function () {
        mainWindow = null;
    });
});

main.jsではアプリのウィンドウを開きつつindex.htmlを開いて表示させるコードになっています。では、つぎにindex.htmlを作ります。こちらはテキトーにHello, Electron!とだけ書かれたファイルを準備します。

これで一旦完了。

いざ実行

srcではなく、一つ上の階層で、下記のコマンドを実行します。

npm run start

すると、こんなウィンドウが表示されます。

electron アプリ 開発

とりあえず動きました!同じようにnpm run build-macOSをすると、.appファイルが生成出来ます。

というわけで

今回は内容はしょぼいアプリですが、index.htmlをゴリゴリ書いていけばいろいろなアプリが簡単に作れそうです!お疲れ様でした!

Appendix

30分で出来る、JavaScript (Electron) でデスクトップアプリを作って配布するまで - Qiita

勉強メモ/npmの使い方(node.js=v0.11.16, npm=2.3.0, 2015-03時点) - Qiita

「Androidのメモとか」は、Amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、Amazonアソシエイト・プログラムの参加者です。

このブログは個人的なメモ書きであったり、考えを書く場所であります。執筆者の所属する団体や企業のコメントや意向とは無関係であります。また、このブログは必ずしも正しいことが書かれているとは限らず、誤字脱字や意図せず誤った情報を載せる場合がありえます。それが原因で読者が不利益を被ったとしても、執筆者はいかなる責任も負いません。ありがとうございます。