あんパン

こしあん派

GLSLで背景を描ける時計を作った

どういうことか分からないと思うので動画を用意した。色が薄すぎて見ても分からないかもしれない。

GLSLで背景を描ける時計

自室は電波時計の電波が入りづらく常に時計が狂っているという問題があり、大変困るのでNTPで調整してくれる時計がほしかった。ついでに自室の温度とか湿度とかいろいろ情報を表示してくれるとうれしい。そういう感じならいろいろ表示してくれるWebページを作ってモニタで表示したらいいじゃん、背景が画像なのもつまらないしフラグメントシェーダーで描けたらいいじゃんと思ったのが始まり。AliExpressで縦長モニタを手に入れて、Raspberry Piから映像を出力することにした。完成したリポジトリはこれ。

github.com

主な機能は……

  • 時計を表示できる
  • 背景をGLSLで描ける
    • 厳密にはフラグメントシェーダのみ対応
  • GLSLã‚’Web経由で編集できる
  • 任意のWebページからHTMLを読み込んできて表示できる

といったもの。

Viteでサーバを起動しており、fragファイルを編集するとHMRで反映してくれる。Dockerでcode-serverを起動しておけばWebブラウザでVS Codeが立ち上がって直接fragファイルを編集できる。

ブラウザからフラグメントシェーダーを編集できる

自分自身めちゃくちゃフラグメントシェーダーを書けますという感じでもないのでChatGPTに依頼しながらちょいちょいいろんなパターンを試している。デスクに置くものの見た目を手軽にカスタムできるのは面白い。

そのほか、いろいろ情報を表示したくなるだろうと思って、外からHTMLを取得してきてそのまま埋め込むだけの機能を作っておいた。本当はiframeとかでやるべきなんだろうけど、どうせ自分で作ったAPIサーバしか叩かないでしょと思ってこのへんは雑。自分はHonoで以下のようなサーバをローカルに立てて、SwitchBot APIから取得した気温湿度・CO2濃度をHTML片にして返している。

gist.github.com

Reactの知識がClass Componentを作っていた時代で止まっていたので最近のものに触れられてよかった(といってもべつに目新しいAPIを触っているわけではない)。あとHonoも初めて触ったけど、こういう手軽なサーバをシュッと立てられて便利だった。

自分の他に使いたい人いないでしょと思っているので、systemdのunitファイルまわりの話題とかRaspberry Piで起動時にキオスクモードでブラウザを表示する話題とか、READMEに書いていないことがいろいろある。丁度これを作っている時期にRaspberry PiのWaylandコンポジタがlabwcに変更になって*1、マウスカーソルを隠せないとかいろいろな問題が発生している。このあたりは追い追いどこかにメモしていきたい。というかこれを作ったのももう2ヶ月くらい前のことだし、ネタは溜め込まずにさっさと放出していきたい。

iOSのヘルスケアアプリに記録された情報をMackerelに送信する

これは はてなエンジニア Advent Calendar 2024 24日目の記事です。

こんにちは、 id:masawada です。30代に突入して早一年、だんだんと健康が気になり始めています。エンジニアたるもの無闇にアクションを取る前にまずは計測、ということでiOSにプリインストールされているヘルスケアアプリの情報をMackerelに送信して傾向を眺められるようにしてみます。

(注意: 株式会社はてなはPHRサービス事業協会に加入している法人ではありません。この記事は健康に関するデータをMackerelに記録することを公式に推奨するものではありません。あくまで個人利用・自己責任の範囲で参考にしてください)

iOSにはショートカットというアプリもプリインストールされています。ショートカットでは「アクション」と呼ばれるブロックを積み重ねることでワークフローを構築することができます。「アクション」にはヘルスケア情報を取得するものや特定のURLにHTTPリクエストを送るものなども用意されているので、これらを組み合わせればMackerelに値を送信できます。

Apple Watchを着用している場合、心拍数や歩数などのメトリックがヘルスケアアプリに自動で記録されます。また、ヘルスケアアプリと連携するサードパーティアプリを利用している場合は、それらに記録されたメトリックも自動で吸い出して集約してくれます。たとえば自分はオムロン製の血圧計、体重計、体温計を利用しており、OMRON Connectというアプリを経由してヘルスケアアプリにメトリックを集約しています。今回は心拍数を送信する例をご紹介します。


ショートカットアプリを実際に触る前に、まずはMackerelにどう値を送信するか確認しておきましょう。今回はサービスメトリックとして情報を保存することにします。

mackerel.io

Mackerelで事前にServiceを作成して、curlで以下のようなリクエストを送ると値を投稿することができます。

curl -H 'Content-Type: application/json' \
     -H 'X-Api-Key: <apiKey>' \
     'https://api.mackerelio.com/api/v0/services/<serviceName>/tsdb' \
     -d '[{ "name": "heart_rate.count", "time": 1734966000, "value": 80 }]'

ヘルスケアのメトリックを取得し、それをJSON形式に加工してこのURLにPOSTするのが今回のゴールです。というわけで、まずはヘルスケアのメトリックを取得します。

ショートカットアプリを開いて新規にショートカットを作成し「ヘルスケアサンプルを検索」アクションを配置しましょう。「クイックルック」アクションを接続することで取得した値を表示することができ、デバッグに便利です。Mackerelのサービスメトリックは最大で過去24時間分の値を記録できるので、検索する範囲は過去1日として心拍数を取得してみます。一旦情報を取得できていることだけを確かめたいので1件だけ取得することにします。

これを実行すると結果が表示されます。

酒を飲んだ後だったので心拍数がやけに高いですね。これだけで不健康さがよく分かります。

値を取得できることは分かったので、これを加工してJSONにしましょう。「各項目を繰り返す」というアクションを利用すると、いわゆるmap的な処理を実現することができます。これを配置して入力の引数を「ヘルスケアサンプル」に指定します。繰り返しの中に「ヘルスケアサンプルの詳細を取得」アクションをふたつ配置し、「繰り返し項目」から「開始日」「値」をそれぞれ取得します。「テキスト」アクションを配置すると、開始日と値を変数として埋め込んだテキストをフォーマットできます。テキストの内容として {"name": "hr.count", "time": 開始日, "value": 値} を設定することで、JSONを生成します。

この結果も「クイックルック」アクションで見てみましょう。

それっぽいJSONが表示されました。現段階では、mapした結果のitemがひとつずつ表示されています。また、timeの値がepoch秒になっていません。このままではリクエストボディとして利用できないので修正していきます。

まず結果を結合して配列にします。「テキストを結合」アクションを繰り返しの終了の後に配置し、繰り返しの結果をカンマで結合します。さらに、結合してできた文字列を「テキスト」アクションに埋め込んで [] で囲います。

次に時刻をepoch秒に変換します。繰り返し項目から開始日を取得するアクションの次に「端数を処理」アクションを接続します。数値計算系アクションの引数に日付を入れるとepoch秒(小数部5桁の精度)にキャストされる仕組みを利用しています。四捨五入と表示されますが、常に切り捨てるモードを選ぶことができます。後続の「テキスト」アクション内の「開始日」を「端数処理済の数値」に置き換えましょう。これでepoch秒を挿入することができます。

ここまででMackerelに送信するJSONを生成することができました。うまく構成できていれば以下のようになるはずです。見やすいように直近の3件をサンプリングしていますが、実際に送信する際はヘルスケアサンプルを取得するアクションの項目数を制限するチェックを外しています。

ここからは生成した値をMackerelに送信します。HTTPリクエストには「URLの内容を取得」アクションを利用します。このアクションを最後に接続しましょう。サービスメトリック投稿APIはPOSTでリクエストを送るので、方法(HTTPメソッド)はPOSTです。送信するのはJSONですが、「本文を要求」をJSONにすると値を送ることができません。サービスメトリック投稿APIでは、トップレベルが配列形式のJSONがリクエストボディとして要求されています。しかし「URLの内容を取得」アクションでJSONを送信しようとするとトップレベルが辞書形式のリクエストになります。これを回避するため「本文を要求」は「ファイル」に変更し、引数として生成したJSONのテキストを選択します。また、ヘッダとして Content-Type を application/json に、 X-Api-Key をMackerelから取得したAPIキーにそれぞれ設定します。これらを済ませると以下のような形になっているはずです。

試しにこれで実際にどういうリクエストが送られるのか確認してみましょう。nc コマンド*1でHTTPリクエストを待ち受けて様子を眺めてみます。

$ ( echo "HTTP/1.0 200 OK"; echo; echo "it works!" ) | nc -l -p 8080
POST / HTTP/1.1
Host: 192.168.0.56:8080
Content-Type: application/json
Connection: keep-alive
X-Api-Key: dummy_api_key
Accept: */*
Accept-Language: ja
Content-Length: 172
Accept-Encoding: gzip, deflate
User-Agent: BackgroundShortcutRunner/3218.0.9 CFNetwork/1568.300.101 Darwin/24.2.0

[{ "name": "hr.count", "time": 1734964612, "value": 141 },{ "name": "hr.count", "time": 1734964603, "value": 140 },{ "name": "hr.count", "time": 1734964598, "value": 139 }]

実際にMackerelに送信したい内容と同等のリクエストになっていることが確認できますね。ということで、あとはURLをMackerel APIのものに置き換えれば完成です。実際に投稿すると以下のようなグラフを眺められるようになるかと思います。

心拍の落ち着いているタイミングを見るに、昨日は5時過ぎに寝て10時ちょっと前に起きているのがよくわかります。来年はこういったメトリクスを駆使して健康になれるようなアクションを取っていきたいですね。

明日の担当は id:yujiorama さんです。

*1:GNU版とBSD版でオプションが違うので注意してください。ここで利用しているのはGNU版です

YAPC::Hakodate 2024にスタッフとして参加した

2024/10/5に開催された YAPC::Hakodate 2024 にコアスタッフとして参加していたので、ややいまさらながら個人の感想などを書いておく。ブログを書くまでがYAPCです。

yapcjapan.org


JPA理事の id:papix さん繋がりで YAPC::Kyoto 2023 ではコアスタッフをしていて YAPC::Hiroshima 2024 でもと思っていたのだけど、ちょうどたてこんでいる時期だったためやむなく断念。ひととおり終わって余裕がでてきたので YAPC::Hakodate 2024 ではスタッフをやらせてくださいとpapixさんにお伝えして参加することになった。ちなみに何故忙しかったというと以下の仕事をしていたから。

masawada.hatenablog.jp

準備面で担当したのは参加者向けの名札の監修と、学生旅費支援に参加する学生さんとのやりとり。名札のデザイン自体は id:mazco さんにお願いしていて、自分は名札に配置する要素だったり文言だったりを考える係だった。大吉祥寺.pmに参加した際に名札のおもてなしがめちゃいいな〜と思っていて、YAPCでもこういう名札ができるといいなと考えていたので自ら買って出たのだった。

最低限必要な要素を運営内でヒアリングして、あとは完全に自由にやらせてもらった。いま見返すと表面についてはほぼ初稿のままで細かい調整が入っているくらいで、 id:mazco さんに助けられまくっている。

検討段階の名札(初稿)

入稿した名札

裏面はいろいろな変遷を経て決定稿に落ち着いた。QRコードからヘルプページに飛べたり、ベストスピーカー賞のフォームに飛べたりという感じ。実は当日向けのヘルプページを作る試みも今回が初めてで、このコンテンツも自分が担当していた。ヘルプページについてはいろいろ反省事項もあるので今後に役立てたい。

もちろん名札以外にも、前夜祭や当日の運営スタッフとしてもいろいろと動いていた。なりゆきで裏方の裏方みたいな動きをしていたので、発表をあんまり見られなかったり参加されていた方々との交流が少なめだったりという感じでこちらもやや反省。発表については後日公開されるであろうYouTubeでの配信を見つつ、次回は余裕をもった動き方をしたい。しかし反省といいつつ、こういうわちゃわちゃした感じが文化祭っぽくて楽しくはあるのだよなあ。


個人的に参加した中で一番よかったことは @deckeye さんと初めてリアルでお会いできたことだと思う。というのも、@deckeyeさんはTwitterでほぼ最初期にフォローしていただいた方なのだった。おそらく1人目か2人目くらいじゃないだろうか? 自分がTwitterアカウントを作ったのは中学の卒業式を終えた直後の2009年3月21日なので、実に丸15年越し。今回 YAPC::Hakodate 2024 の特別企画に登壇されるという話を運営内で聞いてからずっとご挨拶したかったので、お声がけできて本当によかった。今後ともよろしくお願いします。

一方最大の後悔は観光を一切せずに函館を脱出してしまったこと。2年前に妻と函館旅行をしていたこともあり、余市とかにも行きたいしシュッと札幌まで移動してしまうか〜と考えていたのだけど、2日間動き回った反動なのか札幌のホテルで夕方まで寝てしまいなにもできずに破滅。こんなことなら函館に残ってもうちょっといろいろ食べ歩いたらよかった。また近いうちに遊びにいけたらいいな。

と思っていたら、これを書いているいま、妻が社員旅行で函館にいます。なぜ。

Hatena Engineer Seminar #31 「少年ジャンプ+」 サーバーサイド編でオンライン登壇します

2024年10月15日(明日!)に開催される Hatena Engineer Seminar #31 に「10年続くサービスのデータを1日未満のメンテナンスウィンドウで安全に移管する」というタイトルで登壇します。

hatena.connpass.com

3月末まで忙しくしていた理由の一端であり、これまでの自分の仕事の中でもかなりの大玉という感じなのでぜひ見にきてください。配信のみなので自宅にいながら見られます。


しかし、話したいことがありすぎて30分の発表では到底収まらないので、隙を見つけて一般化可能なデータ移行テクをいろいろとアウトプットしていきたい所存。

WU4/H1を購入してArch Linuxをインストールする

2年前に組み立てたThinkPad X270の筐体が割れ始めたので代替PCを探していた。軽量なのがいいと思っていたところ、id:uzullaさんの記事でFCCL(元富士通)の端末がいいというのを見かけて、量販店で触り比べながらWU4/H1という型番のラップトップを購入した。

uzulla.hateblo.jp

ややこしいことに、ほぼ同じ筐体で型番がいくつかあって微妙に仕様が異なる(しかも店頭モデルとWeb直販モデルでも型番が違う)。購入したWU4/H1はバッテリ容量が比較的多めでP系のプロセッサを搭載できてThunderbolt 4が2ポートあるWeb直販モデル。自分はCore i7-1360Pで32GB、SSDは512GBにカスタムして発注した。

最軽量のWU-X/H1は700gを切るが、WU4/H1は900gをギリ切るくらいの重量。とはいえこれまで持っていたThinkPadから比べると300-400gくらい減るのでだいたい缶ビール1本分なくなると考えるとかなり差がある。これでいて画面サイズは16:10の14インチなので驚きがある。

ところでこのシリーズはJIS配列のキーボードしか選べないが、かな刻印がない。バックライトをつけない場合は印字がかなり薄く、一瞬無刻印かのような気持ちになる。なので、違和感なくUS配列として扱うことができている。


WSLを利用するかいつも通りLinuxにするか5分くらい考えて、慣れた環境がいいと思いLinuxを入れることにした。いつも使っているインストールスクリプトで入れた。

github.com

結果、特に何事もなく動いている。sof-firmware をインストールしていなかったためPulseAudioでdummy outputしか存在せず音が出なかったというポカミスはあったがそれくらい。指紋リーダについても fprint を入れることで問題なく動く。なんならmicroSDのカードリーダーもちゃんと動く。まあ令和だしもう動かない方が珍しいのかもしれない。ひととおり動いたのでArch Wikiに動作確認情報を追加しておいた。

あとキーボード関連の細かな話題として以下のような挙動をするようであった。一応忘れないようにメモ。

  • キーボードバックライトはLinuxからは制御できず、fn+spaceで明るさを3段階で制御できる
    • どうもデバイスがないと思ったらOSを介さずに制御することになっていそう?
  • F10を押すとXF86Displayが発火すると思いきやmod+pが発火する
    • xevで様子を確認できる

軽量ラップトップではあるもののキーボードも特に打ちづらいといったことはないし、選べるなかでは一番強いPプロセッサを搭載しているがファンはあまり回らず回っても静音でかなり体験が良い。届いてから1ヶ月弱くらい使って様子を見ていたが特に違和感なく生活に溶け込んでいる。全体的に満足度の高い買い物ができたと思う。