Androidのメモとか

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

enebular + Sonos + 導電糸で 快適テレワーク環境を作ってみた

スワイプできる椅子。

ポキオ enebular + Sonos + 導電糸で 快適テレワーク環境を作ってみた

tl;dr

speakerdeck.com

静電容量センサーと導電糸の組み合わせ

もともと静電容量センサーをつかったユーザーインターフェイスをもったガジェットを作っていました。触ったりすることで、何かのトリガーとなり得るなと確信を得ていたわけです。

relativelayout.hatenablog.com

今回、この静電容量センサーに導電性の糸を組み合わせて、糸を縫い込んだ布をさわることを検知し、普段使っているホームオーディオシステム「Sonos」の曲送りができないか、やってみました。

全体の構成

今回は、テレワークで使っているアウトドア用の椅子をハックしていきます。

ポキオ enebular + Sonos + 導電糸で 快適テレワーク環境を作ってみた

relativelayout.hatenablog.com

この椅子のサイドのポケットに、導電性の糸を縫い付けて、スワイプを検知できるようにしていきます。

ポキオ enebular + Sonos + 導電糸で 快適テレワーク環境を作ってみた

スワイプは静電容量センサーMPR121とマイコンボードESP8266を使って検知します。

ポキオ enebular + Sonos + 導電糸で 快適テレワーク環境を作ってみた

ESPr Developer(ピンソケット実装済)

ESPr Developer(ピンソケット実装済)

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

スワイプを検知したあとは、ESP8266からenebular・IFTTTを経由してSonosスピーカーの制御を行います。

ポキオ enebular + Sonos + 導電糸で 快適テレワーク環境を作ってみた

かんたんに曲送り可能に

テレワークでSonosで音楽を聞きがちなんですが、テレワークで使っている椅子がSonosのリモコンとして使えるようになり、かなり便利になりました。

ポキオ enebular + Sonos + 導電糸で 快適テレワーク環境を作ってみた

また、あえてenebularを経由してIFTTTにアクセスさせることで、急なロジック変更時もマイコンの実装を変えることなく、enebularのフローを変えるだけで変更するだけなので臨機応変に対応することができるのでいい感じです。

FlutterでChrome向けにビルドしようとした時にハマったのでメモ

揚げ物ではないです。

ポキオ Flutter Android Web Chrome

Flutter環境を構築中

前回Big Surの起動メディアを作って、家にある人柱になっても良さそうなMacBook Airにインストールしたわけなんですが。

relativelayout.hatenablog.com

個人的な信条としては必ずクリーンインストールをしないと気が済まないため、せっせと環境を再構築中です。その中でもFlutterの環境を構築しなおした時にハマったのでメモしておきます。

flutter.dev

Flutterっていうのはこれ。これを読んでいる諸兄姉にとっては釈迦に説法かもしれませんが、Googleが開発したクロスプラットフォームなアプリを作れる仕組みです。

flutter.dev

インストール方法も簡単で、ZIPファイルをダウロードして、展開して、パスを通すだけ。

$ cd ~/development
$ unzip ~/Downloads/flutter_macos_1.22.4-stable.zip
$ export PATH="$PATH:`pwd`/flutter/bin"

そして、プロジェクトを作るのもこんな感じ。

$ flutter create fluttertest

これでfluttertestというプロジェクトができちゃいます。

早速Hello, world

あらかじめVS Codeをインストールの上、FlutterとDartプラグインをインストールしておけば、VS Code上で開発ができちゃいます。

ポキオ Flutter Android Web Chrome

さらに、Android Studioがインストール済みで、ADB接続できる実機か仮想デバイスがあればVS Codeからその環境にアプリをインストールして実行することができます。

ポキオ Flutter Android Web Chrome

ここまではいいんですが。問題はここから。

Chromeで実行できない?

クロスプラットフォームの良さみを感じたくて、Chromeで実行しようと思ったわけです。FlutterのオプションでChromeでの実行を有効にしてみます。

$ flutter config --enable-web

これで、ビルド対象をChromeにして実行すれば大丈夫かなぁと思ったんですが・・・。

ポキオ Flutter Android Web Chrome

ビルド対象にChromeが出てきません・・・。

flutter.dev

最初っから本家チュートリアルを見ればよかったんですが、

Flutter has early support for running web applications, but you need to be running the beta channel of Flutter at present.

というわけで、Beta版のFlutterを使わないとChromeで実行できなさそうです。

$ flutter channel beta
$ flutter upgrade
$ flutter config --enable-web

こんな感じで、Beta版に切り替えた後に、再度Chromeでの実行のオプションを有効にして、VS Codeを再起動すると・・・

ポキオ Flutter Android Web Chrome

ビルド対象にChromeが表示されました!Chromeを選択してビルドを行うと・・・

ポキオ Flutter Android Web Chrome

無事にChromeでも実行することができましたー。お疲れ様でした(笑)

基礎から学ぶ Flutter

基礎から学ぶ Flutter

macOS Big Surのインストール用USBドライブを作ってみる

ビッグサア。

ポキオ macOS Big Sur 起動ディスク

Big Surでましたねぇ

でちゃいましたねぇ。

www.apple.com

そして、

たまには家でゆっくりクリーンインストールするのも悪くないなと思い、インストール用のUSBドライブを作ってみました。

つくりかた

公式はこちら。

support.apple.com

What you need to create a bootable installer

  • A USB flash drive or other secondary volume, formatted as Mac OS Extended, with at least 12GB of available storage

  • A downloaded installer for macOS Big Sur, Catalina, Mojave, High Sierra, or El Capitan

16GBのUSBメモリがあれば大丈夫そうです。とりあえず、App StoreからBig Surのインストーラーをダウンロードしたうえで、USBメモリ(ここではNO NAMEという名前)をmacに挿して、

$ sudo /Applications/Install\ macOS\ Big\ Sur.app/Contents/Resources/createinstallmedia --volume /Volumes/NO\ NAME/

これを実行。macのパスワードを聞かれるので入力すると、USBドライブが作成されます。

Ready to start.
To continue we need to erase the volume at /Volumes/NO NAME/.
If you wish to continue type (Y) then press return: Y
Erasing disk: 0%... 10%... 20%... 30%... 100%
Copying to disk: 0%... 10%... 20%... 30%... 40%... 50%... 60%... 70%... 80%... 90%... 100%
Making disk bootable...
Install media now available at "/Volumes/Install macOS Big Sur"

完成!

あとは、このメディアをBig Surをクリーンインストールしたいmac挿してから電源オン、からのoptionボタンをホールドするとUSBメモリからBig Surが起動できるようになりますー。

ゲーマーじゃないけどPS5買ってみた話

買っちゃいました。

ポキオ PlayStation5

当たっちゃった

ソニーストアの抽選に当たっちゃいました。

ちなみに、プレイステーション系のハードは買ったことがなくPS5が初めて。そもそもあんまりゲームをやらないタイプで、NintendoのTVにつなぐ系のハードもSwitchが初めてというタイプ。なので、ゲームのことに関してはズブの素人なわけなんだけど、きっと話題だから楽しいに違いないとおもい購入。

というわけで、実際に遊んでみました。

とりあえず設置

こんな感じでテレビ台にインストール。

ポキオ PlayStation5

PS5は横置き。なんか思った以上にデカイけど、まぁいい。SonosのPlaybarで臨場感のある音を期待しつつ、まさかのディスプレイはFHD…。これは4K買わないとなぁ。

ポキオ PlayStation5

あと、PS5の光り方がなんだか妖艶で。起動直後はこんな感じの青。すごくラブホっぽい。(褒めてる)

ポキオ PlayStation5

プレイ中は白くなって、スタンバイ中は黄色くなる。こういうさりげないインジケーターが本当におしゃれ。

ソフトは買ったの?

買ったはいいものの、特にやりたいゲームはなくて、強いて言うなら

  • GTA5がPS5向けにも出るらしので、おいおいそれを買いたい
  • PS4向けだけど電車でGOが出るらしので、それも買いたい

みたいな感じで、別にPS4でもいいんじゃないの?と言われればそれまでなんですが、取り急ぎこれを購入。

Need for Speed:Hot Pursuit Remastered - PS4

Need for Speed:Hot Pursuit Remastered - PS4

  • 発売日: 2020/11/06
  • メディア: Video Game

ゲーム機は持っていなかったけど、小さい頃にPCでやったNFS3 Hot Pursuitが忘れられず、PS4版のNFS Hot Pursuitを購入。これが楽しくて仕方がない。PS4版のゲームも、ディスクを挿入してPS5のSSDにインストールが完了すると、ちゃんとPS5でも遊べるっていうんだから素敵。コンパイルし直してるのかしら・・・。

要はパトカーを振り切ったり、逆にパトカーで追跡したりするゲーム。警察無線の感じとかすごくいい。(語彙力)

Sonos Playbarのおかげで、いわゆる迫力のある音が楽しめる一方で、警察無線の声とかもはっきり聞こえます。あとはディスプレイさえ4Kにできれば本当に最高なんですけどねぇ。バジェットがががが。

PS5らしさを楽しむ

とまぁ、ここまでは完全にPS4でも良かった話。結局NFS Hot Pursuitも、PS5で遊べるといっても、PS5の良さ味をあまり活かしきれず、タッチパネルとかハプティックなコントローラーのパフォーマンスを試せずにいました。

ちょっと悔しかったので、PS5にプリインされていたAstro's Playroomというゲームで遊んでみることに。

これがまたすごい。震え方が尋常じゃないというか、振動の強弱だけでなく、コントローラーがどこかに持っていかれるような感触を味わえるうえに、トリガーボタンもゲーム内容によって負荷がかかるような感触が味わえる。なんかコントローラーからも音が出てくるし、もう体験がすごい。とにかくすごい。(語彙力)

買ってよかったの?

ここがポイントで、正直まだ良くわからない。Astro's Playroomも、PS5の良さは体験できたものの、好きなタイプのゲームではなかったのが残念。NFSなどのPS4系のゲームをするなら、PS4で良かったといえばそのとおり。あとはこれから出てくるゲームで、好きなやつがあって、それでPS5の良さが体験できれば良いんだけど…。気長に待つとしますかねぇ。PS5版のGTA5がどこまでPS5のハードウェアを使い倒してくれるかが本当に気になるところ。せっかくすごいコントローラーなんだけどなぁ。

あと、単純に動画再生機としても、惜しい部分があり。普段はAmazonのFire TV StickでAbemaとかを見がちなんですが、PS5はAbema非対応っぽく・・・。せっかくYouTubeとかAmazon Prime Videoも見られるので、個人的にはAbemaが見られたらPS5でいろいろ事足りてしまうので良かったのですが…。Abemaに限った話ではないですが、もう少しいろんなストリーミングサービスに対応してほしかったなぁと。

いろいろ文句を言ってますが、確実に僕の時間を溶かしにかかっていることは間違いないです。

静電容量センサーをつかってファファファファーン

またファーンしてます。

ポキオ Raspberry Pi Speaker pHat サンプラー

前回まで

サンプラー買うお金がないので、Raspberry Piで作っています。

relativelayout.hatenablog.com

relativelayout.hatenablog.com

relativelayout.hatenablog.com

誰か買ってください。

ボタンの押下音がうるさい件

やっぱりうるさいんですよね、ボタンを押したときの音が。

ポキオ Raspberry Pi Speaker pHat サンプラー

そこで、ボタンの代わりのインターフェイスを探すことに。で、押してダメならタッチでどうだ、ということで静電容量センサを使うことに。

この投稿をInstagramで見る

導電性の糸で遊んでる(仕事しろ)

pokio(@pokiiiiio)がシェアした投稿 -

モジュールのインターフェイスはi2cになっていて、RPi以外にもArduinoでも使えてしまうやつ。モジュールには10個の入力端子がついていて、触るなどして静電容量が変化を検知できるというわけです。

静電容量センサーでファファファファファーン

というわけで、このモジュールを使ってユーザーインターフェイスを作成。モジュールをブリキの板につないでボタンの代わりにしてみました。

ポキオ Raspberry Pi Speaker pHat サンプラー

こんな感じ。で、これでファファファファーンしてみました。

この投稿をInstagramで見る

ファファファファーン

pokio(@pokiiiiio)がシェアした投稿 -

まぁまぁいいんじゃないですかねぇ。目的であったボタンの押下音はなくなりました。

ただ、今度目立ってきたのは「押したのに音がならないことがある」ということ。一難去ってまた一難。センサーが反応できていないのか、音を鳴らすプロセスが詰まってるのか…?なにはともあれ、本物のサンプラーに近づくのはなかなか難しいものですね。

コードはこちら

静電容量センサモジュールのライブラリ(adafruit_mpr121)がPython3向けだったため、Python3で動作させています。

import pygame.mixer
import time
import board
import busio
import adafruit_mpr121
import threading
 
i2c = busio.I2C(board.SCL, board.SDA)
mpr121 = adafruit_mpr121.MPR121(i2c)

input_state1 = False
input_state2 = False
input_state3 = False
input_state4 = False
input_state5 = False
input_state6 = False

pygame.mixer.init()

sound1 = pygame.mixer.Sound("/home/pi/Music/sound1.wav")
sound2 = pygame.mixer.Sound("/home/pi/Music/sound2.wav")
sound3 = pygame.mixer.Sound("/home/pi/Music/sound3.wav")
sound4 = pygame.mixer.Sound("/home/pi/Music/sound4.wav")
sound5 = pygame.mixer.Sound("/home/pi/Music/sound5.wav")
sound6 = pygame.mixer.Sound("/home/pi/Music/sound6.wav")

def play1():
    sound1.stop()
    sound1.play()

def play2():
    sound2.stop()
    sound2.play()

def play3():
    sound3.stop()
    sound3.play()

def play4():
    sound4.stop()
    sound4.play()

def play5():
    sound5.stop()
    sound5.play()

def play6():
    sound6.stop()
    sound6.play()

while True:
    if mpr121[0].value == True and input_state1 == False:
        print('Button1 Pressed')
        input_state1 = True
        threading.Thread(target=play1).start()    
    else:
        input_state1 = mpr121[0].value

    if mpr121[2].value == True and input_state2 == False:
        print('Button2 Pressed')
        input_state2 = True
        threading.Thread(target=play2).start()   
    else:
        input_state2 = mpr121[2].value

    if mpr121[4].value == True and input_state3 == False:
        print('Button3 Pressed')
        input_state3 = True
        threading.Thread(target=play3).start()   
    else:
        input_state3 = mpr121[4].value

    if mpr121[7].value == True and input_state4 == False:
        print('Button4 Pressed')
        input_state4 = True
        threading.Thread(target=play4).start()   
    else:
        input_state4 = mpr121[7].value

    if mpr121[9].value == True and input_state5 == False:
        print('Button5 Pressed')
        input_state5 = True
        threading.Thread(target=play5).start()   
    else:
        input_state5 = mpr121[9].value

    if mpr121[11].value == True and input_state6 == False:
        print('Button6 Pressed')
        input_state6 = True
        threading.Thread(target=play6).start()   
    else:
        input_state6 = mpr121[11].value

Raspberry Piでサンプラーを作ってファファファファーン

ファファファファーン

ポキオ Raspberry Pi Speaker pHat サンプラー

前回まで

サンプラー買うお金がないので、Raspberry Piで作っています。

relativelayout.hatenablog.com

relativelayout.hatenablog.com

誰か買ってください。

ハードボタンがなきゃサンプラーじゃない

とりあえず、Raspberry PiとSpeaker pHatPythonで好きな音を再生・停止できるところまでできました。

あとは、ボタンを複数揃えて、ボタンに違う音をアサインして、ボタンを押して音を出す。これがしたいんですよねぇ。

ポキオ Raspberry Pi Speaker pHat サンプラー

とりあえず、部屋に転がっていた電子工作用のボタンをいくつか用意して、GPIOとGNDをつないでみました。

ポキオ Raspberry Pi Speaker pHat サンプラー

これをRaspberry Piに接続。Python側でプルアップ抵抗を有効化して、ボタン押下を検知。それをトリガーに音を鳴らすコードを書いてみました。ボタンを連打したときのために、再生中の音を止める実装も入れてみました。

いざ演奏

とりあえず、エアホーンだけですが。

こんな感じです。

  • ボタンの押下時の音がうるさい
  • レスポンスが遅い

など、色々思うところがありますが、とりあえず色々な音源で試してみたいですねぇ。

コードはこちら

import RPi.GPIO as GPIO
import pygame.mixer
import time

GPIO.setmode(GPIO.BOARD)

pin1 = 15
pin2 = 11
pin3 = 29
pin4 = 37
pin5 = 18
pin6 = 16

GPIO.setup(pin1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(pin2, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(pin3, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(pin4, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(pin5, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(pin6, GPIO.IN, pull_up_down=GPIO.PUD_UP)

input_state1 = True
input_state2 = True
input_state3 = True
input_state4 = True
input_state5 = True
input_state6 = True

pygame.mixer.init()

sound1 = pygame.mixer.Sound("/home/pi/Music/sound1.wav")
sound2 = pygame.mixer.Sound("/home/pi/Music/sound2.wav")
sound3 = pygame.mixer.Sound("/home/pi/Music/sound3.wav")
sound4 = pygame.mixer.Sound("/home/pi/Music/sound4.wav")
sound5 = pygame.mixer.Sound("/home/pi/Music/sound5.wav")
sound6 = pygame.mixer.Sound("/home/pi/Music/sound6.wav")

while True:
    if GPIO.input(pin1) == False and input_state1 == True:
        print('Button1 Pressed')
        input_state1 = False
        sound1.stop()
        sound1.play()
    else:
        input_state1 = GPIO.input(pin1)

    if GPIO.input(pin2) == False and input_state2 == True:
        print('Button2 Pressed')
        input_state2 = False
        sound2.stop()
        sound2.play()
    else:
        input_state2 = GPIO.input(pin2)

    if GPIO.input(pin3) == False and input_state3 == True:
        print('Button3 Pressed')
        input_state3 = False
        sound3.stop()
        sound3.play()
    else:
        input_state3 = GPIO.input(pin3)

    if GPIO.input(pin4) == False and input_state4 == True:
        print('Button4 Pressed')
        input_state4 = False
        sound4.stop()
        sound4.play()
    else:
        input_state4 = GPIO.input(pin4)

    if GPIO.input(pin5) == False and input_state5 == True:
        print('Button5 Pressed')
        input_state5 = False
        sound5.stop()
        sound5.play()
    else:
        input_state5 = GPIO.input(pin5)

    if GPIO.input(pin6) == False and input_state6 == True:
        print('Button6 Pressed')
        input_state6 = False
        sound6.stop()
        sound6.play()
    else:
        input_state6 = GPIO.input(pin6)

    if not (input_state1 and input_state2 and input_state3 and input_state4 and input_state5 and input_state6):
        time.sleep(0.05)
        print('block')

ファーンだけじゃなくファファファファファーンができるようになった

ファーン。

ポキオ Raspberry Pi Speaker pHat Air Horn

ファーン?

前回はこちら。

relativelayout.hatenablog.com

要はエアホーンの効果音をRaspberry Piで鳴らしたいよっていうお話なんですが、前回のNode-REDのノードの場合、音声ファイルをノードで再生中に、更に音声ファイルをノードに対して再生させようとすると、正しく再生されなくなってしまいます。つまり、エアホーンのファーンという音は鳴らせても、それを連続して再生してファファファファファーンみたいな鳴らし方はできませんでした。

Pythonで再生してみる?

Node-REDではノードで再生中の音楽を途中で止めるすべがなさそうだったので、Pythonを使って愚直にコーディングしてファファファファファーンしてみようと思います。

Pythonではpygameというゲーム用モジュールを使うと簡単にMP3を再生できそうだったので、それを使って実装してみます。

$ pip list

手元のRaspberry PiRaspberry Pi OS)にはプリインされてるようで、上記コマンドでモジュール一覧を表示したところ、

Package           Version    
----------------- -----------
(中略)
pygame            1.9.4.post1

pygameは入っていました。良かった良かった。これを使ってMP3を連続再生してみようと思います。

import pygame.mixer
import time

def main():
    pygame.mixer.init()    
    time.sleep(1)  

    pygame.mixer.music.load("./Music/airhorn.mp3")    
    pygame.mixer.music.play(1)          
    time.sleep(0.2)                   
    pygame.mixer.music.stop()   

    pygame.mixer.music.load("./Music/airhorn.mp3")    
    pygame.mixer.music.play(1)          
    time.sleep(0.2)                   
    pygame.mixer.music.stop()   

    pygame.mixer.music.load("./Music/airhorn.mp3")    
    pygame.mixer.music.play(1)          
    time.sleep(0.2)                   
    pygame.mixer.music.stop()

    pygame.mixer.music.load("./Music/airhorn.mp3")    
    pygame.mixer.music.play(1)          
    time.sleep(0.2)                   
    pygame.mixer.music.stop()

    pygame.mixer.music.load("./Music/airhorn.mp3")    
    pygame.mixer.music.play(1)          
    time.sleep(2)                   
    pygame.mixer.music.stop()

if __name__ == '__main__':
    main()

便利なことに、再生だけでなく、再生中の音楽を止めたりもできるので、まずはsleepで時間を少しずつづらしながら、再生中のファーンを停止し、そのまま再度ファーンを再生させながら、ファファファファファーンをしてみました。

この投稿をInstagramで見る

Pythonでファファファファファーンできたお

pokio(@pokiiiiio)がシェアした投稿 -

おーーー。いい感じ。あとは、これをサンプラーみたいにボタン操作でファファファファファーンしたいところ。

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

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