JP7FKFの備忘録

ヒトは,忘れる生き物だから.

Wi-Fi接続でHTTP APIで制御できる信号灯を自作してみた話

何かに気づきたいとき

日常生活をしている上で,何かに気づきたいことってありますよね.

たとえば...

  • 自宅のSW/RT/SVなどの機器で障害が発生した
  • 温度/湿度/CO2濃度が一定以上になった
  • 緊急地震速報などの警報がきた
  • etc...

こういったとき,どのような手段で通知をうけているでしょうか? Legacyな方法だとメールで受信したり,最近だとslackなどにpostする,などで通知させているケースもあるでしょう.

これらの手段ではpush通知等で気づくこともできますが,より明確に気づかせたいケースもあるでしょう.

こういったとき,便利なのがパトライト社の積層信号灯*1などではないかと思います. 工作機械などの自動機械の状態を示すためにもよく利用されていますね.

www.patlite.co.jp

これらに代表される信号灯は,表示状態を制御する制御端子や電源が独特だったりします(産業機械などに合わせられているケースが多い). そこで,汎用性をもたせたHTTP APIでフルカラーLED,ブザーを制御でき,USB 5Vで動作する信号表示器を自作してみたので紹介します.

信号灯の自作

材料がこちらです. MCUにはESP8266, ESP-WROOM-02を利用しており,2.4GHz帯の無線LAN接続経由で操作できるようになっています. f:id:jp7fkf:20210826204938j:plain

f:id:jp7fkf:20210826204950j:plain

基盤は自分でESP-WROOM-02用の汎用基盤として作成したものを利用しており,ユニバーサル部にLEDやブザーを駆動する回路を付加しています. f:id:jp7fkf:20210826204954j:plain

筐体は3Dプリンタで作成しました. f:id:jp7fkf:20210826204931p:plain

f:id:jp7fkf:20210826204925p:plain

これらのパーツをもりもり組み合わせていきます. f:id:jp7fkf:20210826205017j:plain

f:id:jp7fkf:20210826205020j:plain

スペーサーをいれてタッピングで固定. f:id:jp7fkf:20210826204958j:plain

半透明な頭の部分と本体はネジ山を切ってあるので,締め込んで固定します. f:id:jp7fkf:20210826205004j:plain

f:id:jp7fkf:20210826205007j:plain

f:id:jp7fkf:20210826205010j:plain

f:id:jp7fkf:20210826205014j:plain

f:id:jp7fkf:20210826205030j:plain

六角形にちょうど汎用のスペーサが合うようになっているので,両端ナットになっているスペーサを差し込んで両側からねじ止めして挟む形で止めます. f:id:jp7fkf:20210826205025j:plain

f:id:jp7fkf:20210826205033j:plain

f:id:jp7fkf:20210826205036j:plain

点灯させるとこんな感じになります. f:id:jp7fkf:20210826205039j:plain

APIはHTTP APIで,json形式でやり取りできるようになっています.LEDとブザーを制御できます.
LEDはフルカラーLEDのPWM制御で1024段階,intervalを指定した点滅ができるようになっています.
異なる色を積層させる積層信号灯とは違い,色は何らか1種類しか表現できませんが,フルカラー表示ができるようになっているので,アラート種別灯に応じて,ある程度違った表現をすることができます.
ブザーも同様,ON/OFFの他にintervalを指定してON/OFFの繰り返しリピートができるようになっています.

% curl -X PUT -d '{"red": 2000, "green": 0, "blue": 0, "interval": 100, "flash": true}' 'http://fast.local/indicator' -s | jq .
{
  "red": 1023,
  "green": 0,
  "blue": 0,
  "interval": 100,
  "isOn": true,
  "flash": true
}

% curl -X PUT -d '{"isOn": true, "repeat": true, "interval": 100}' 'http://fast.local/beep' -s | jq .
{
  "isOn": true,
  "repeat": true,
  "interval": 100
}

色相を変化させるとこんな感じ. f:id:jp7fkf:20210131165644g:plain:w600

f:id:jp7fkf:20210131165715g:plain:w600

これらを組み合わせると,トラフィック量に応じて色彩を変化させる(青=低トラフィック,赤=高トラフィック)ことで回線トラフィック状況を可視化できたりします.

また,zabbixのmediaとしてこのAPIをたたくように登録しておくと,zabbixで検知したtrigger種に応じて色を変えて通知することなどに応用できます.

赤色のボタンを搭載していますが,これは1クリックでブザーが,ダブルクリックでLEDがOFFにになるようになっています.アラートに気づいたらまずうるさいブザーを停止する,などの操作が即座に現地で行えるようになっています.
こういった機能を組み合わせて,我が家ではもっぱらzabbixのアラート通知用として活躍しています.

今回作成した信号灯はFlexible Alerting Signal Tower(FAST)と名付け*2,Opensourceとして3D modelやfirmwareを公開しています.
(まだ完全ではないので,2021/08現在beta扱いです...)

GitHub - jp7fkf/FAST: Opensource signal tower using ESP8266 WiFi-module.

通知ソリューションの自作に興味がある方など,制作してみてはいかがでしょうか.

まとめ

  • 汎用性のあるHTTP APIとUSB電源で動作する信号灯を制作しました.
  • zabbix などの監視システムと組み合わせて"気づく"ソリューションの実現ができました.

謝辞

*1:※ちなみに,パトライト,シグナル・タワーは株式会社パトライト登録商標です.

*2:ネーミングセンスのなさ...

Feed43でRSSフィードが提供されていないwebページをRSS購読する話

RSSとは

RSSとはwebサイトやブログなどのサマリ(見出し,要約)を購読することができる仕組みで,当該サイトの更新情報をwatchする際などに利用されている. RSSという名前はRDF Site Summary(0.9), Rich Site Summary(0.91-), Really Simple Syndication(2.0-)の略語であるようで,面白いことにRSSという同じ略称であるにもかかわらず,バージョンによってこの正式名称が異なるそうである.現在多く利用されているRSS2.0では,Really Simple Syndicationが正式名称とされている*1RSSxmlを用いて記述されている.RSSxmlを見るとどのversionのRSSフォーマットが利用されているかを確認することができる.

<rss version="2.0">

slackのRSS購読機能

ビジネスチャットツールとして知られているslackにはRSSフィードの購読機能が存在する*2. これを用いて自分のwatchしておきたいページのRSSフィードを登録し,更新があったときにはslackのpostで更新を受け取ることができる.

RSS配信がされていないwebページを購読する - Feed43

こういった便利なしくみであるRSSだが,一般にはこのRSSフィードはコンテンツの提供元にて用意され,用意されたRSSを任意の購読希望者が購読する形となっている.つまり,コンテンツの提供元がRSSフィードを配信しなければ購読できないことを意味する.今回私はこの状況に陥り,購読したかったコンテンツにRSSフィードが存在しないという状況であった.これのよい解決策がないかと探ってみると,Feed43 というRSS購読に必要な情報をパースし,RSS配信を構成してくれるサービスを見つけた.これを利用してRSSフィードを構成し,slackでRSS購読を行うことができたので紹介する.

今回題材としてネットワンシステムズ株式会社様の匠コラムを利用させていただく*3.このミニブログ的コンテンツの更新情報をslackで受け取ることを目的とする.

まずFeed43にアクセスし,[Create your first RSS feed] ボタンからRSSフィード作成画面に遷移する. f:id:jp7fkf:20210801193712p:plain

すると下記のような画面に遷移し,購読したいRSSフィードを作るためのconfigurationを行っていくことになる.

Step 1. Specify source page address (URL)

ここではRSSフィードに必要な情報が含まれるページのURLを記述する. f:id:jp7fkf:20210801193858p:plain

今回題材としている匠コラムでは以下のURLでjson形式でコンテンツの情報を得ることができる(ありがたい).これを利用させてもらうことにする.

URLを記述したら右下の[Reload] をクリックしてコンテンツを取得して次のstepへ.

Step 2. Define extraction rules

ここでは取得したコンテンツから正規表現に似たようなものを使って,必要な情報を切り出していく.このsearch patternの書き方は Understanding Search Patterns and Output Templates - Feed43が参考になる. ここではエントリの日付,タイトル,ページのpathを切り出している.正規表現を書いてみたら右下の[Extract]ボタンを押して,自分の思い通りに切り出されいるかを確認しながら勧めていくとよい.うまく切り出せていたら次のステップへ. f:id:jp7fkf:20210801194458p:plain

Step 3. Define output format

ここでは,切り出した要素を使って実際のRSSフィードの中身を定義していく.書かれているとおりfeedのタイトル,リンク,説明や,RSSアイテムのタイトル,リンク,コンテンツを記述することができる.Step2で切り出した要素を自分の好きなように組み合わせてRSSフィードを構成しよう. 構成できたら[Preview[を押して実際のRSSフィードを見てみよう.うまくpreviewできると Your feed is ready! という要素が現れる.RSSフィードの作成はこれだけで完成だ.表示されている購読用のリンクを用いて購読することができる. f:id:jp7fkf:20210801194850p:plain

SlackでのRSS購読

slackのRSSフィード購読機能はとてもかんたんに利用することができる.購読をポストしたいチャンネルで

/feed subscribe <rss-feed-url>

と投稿するだけである.これだけで購読は完了だ.先程作成したFeed43のRSSフィードURLを使って購読しよう.

うまく購読できていると,更新があった場合に下記のような形で更新がポストされる.非常に便利だ. f:id:jp7fkf:20210801193719p:plain

まとめ

  • RSSのおさらいをした,
  • Feed43をつかってRSSフィードが提供されていないコンテンツのRSS購読をする例を紹介した.

References

*1:RSS 2.0 specification - W3C

*2:Slack に RSS フィードを追加する | Slack

*3:この方式のRSSフィード作成ではどうしても定期的にwebコンテンツにアクセスする必要性があることから,多少なりともwebサーバ側に負荷をかけることになることに十分注意をする必要があります.もしもネットワンシステムズ株式会社様がこの行為の停止を求める場合には速やかに従うことを約束します

ANSI escape sequenceを使ったterminal文字色変更をサクっとやるためのヤツ

題の通りのやつをサクっとできるようにscriptにした.echoしているだけで工夫が全然無いけど事足りるっぽい.
zshrcとかに書いておくなどする.

######### shellcolors ############
function shellcolors () {
  echo -e "\033[1m# Basic\033[m"
  echo -e "Set   color: \"\\\033[<attribute>;<foreground>;<background>m\""
  echo -e "Reset color: \"\\\033[m"\"

  echo -e "\033[1m# Attributes:\033[m"
  echo -e "\\\033[0m\033[0mReset\033[m\\\033[m"
  echo -e "\\\033[1m\033[1mBold\033[m\\\033[m"
  echo -e "\\\033[2m\033[2mLowLuminance\033[m\\\033[m"
  echo -e "\\\033[3m\033[3mItalic\033[m\\\033[m"
  echo -e "\\\033[4m\033[4mUnderline\033[m\\\033[m"
  echo -e "\\\033[5m\033[5mBlink\033[m\\\033[m"
  echo -e "\\\033[6m\033[6mHighBlink\033[m\\\033[m"
  echo -e "\\\033[7m\033[7mInvert\033[m\\\033[m"
  echo -e "\\\033[8m\033[8mHide\033[m\\\033[m"
  echo -e "\\\033[9m\033[9mStrikethrough\033[m\\\033[m"

  echo -e "\033[1m# 16 foreground colors:\033[m"
  echo -e "\\\033[30m\033[30mBLACK\033[m\\\033[m\t\\\033[90m\033[90mLIGHT BLACK\033[m\\\033[m"
  echo -e "\\\033[31m\033[31mRED\033[m\\\033[m\t\\\033[91m\033[91mLIGHT RED\033[m\\\033[m"
  echo -e "\\\033[32m\033[32mGREEN\033[m\\\033[m\t\\\033[92m\033[92mLIGHT GREEN\033[m\\\033[m"
  echo -e "\\\033[33m\033[33mYELLOW\033[m\\\033[m\t\\\033[93m\033[93mLIGHT YELLOW\033[m\\\033[m"
  echo -e "\\\033[34m\033[34mBLUE\033[m\\\033[m\t\\\033[94m\033[94mLIGHT BLUE\033[m\\\033[m"
  echo -e "\\\033[35m\033[35mMAGENTA\033[m\\\033[m\t\\\033[95m\033[95mLIGHT MAGENTA\033[m\\\033[m"
  echo -e "\\\033[36m\033[36mCYAN\033[m\\\033[m\t\\\033[96m\033[96mLIGHT CYAN\033[m\\\033[m"
  echo -e "\\\033[37m\033[37mWHITE\033[m\\\033[m\t\\\033[97m\033[97mLIGHT WHITE\033[m\\\033[m"

  echo -e "\033[1m# 16 background colors:\033[m"
  echo -e "\\\033[40m\033[40mBLACK\033[m\\\033[m\t\\\033[100m\033[100mLIGHT BLACK\033[m\\\033[m"
  echo -e "\\\033[41m\033[41mRED\033[m\\\033[m\t\\\033[101m\033[101mLIGHT RED\033[m\\\033[m"
  echo -e "\\\033[42m\033[42mGREEN\033[m\\\033[m\t\\\033[102m\033[102mLIGHT GREEN\033[m\\\033[m"
  echo -e "\\\033[43m\033[43mYELLOW\033[m\\\033[m\t\\\033[103m\033[103mLIGHT YELLOW\033[m\\\033[m"
  echo -e "\\\033[44m\033[44mBLUE\033[m\\\033[m\t\\\033[104m\033[104mLIGHT BLUE\033[m\\\033[m"
  echo -e "\\\033[45m\033[45mMAGENTA\033[m\\\033[m\t\\\033[105m\033[105mLIGHT MAGENTA\033[m\\\033[m"
  echo -e "\\\033[46m\033[46mCYAN\033[m\\\033[m\t\\\033[106m\033[106mLIGHT CYAN\033[m\\\033[m"
  echo -e "\\\033[47m\033[47mWHITE\033[m\\\033[m\t\\\033[107m\033[107mLIGHT WHITE\033[m\\\033[m"

  echo -e "\033[1m# 256 colors:\033[m"
  echo -e "Foreground: \"\\\033[38;5;<color number>mCOLOR\\\033[m\""
  echo -e "Background: \"\\\033[48;5;<color number>mCOLOR\\\033[m\""
  seq 0 255 | xargs -I {} printf "\033[38;5;{}m{}\033[m "
  echo -e ""

  echo -e "\033[1m# 24bit colors\033[m"
  echo -e "Foreground: \"\\\033[38;2;<red(0-255)>;<green(0-255)>;<blue(0-255)>m\\\033[m\""
  echo -e "Background: \"\\\033[48;2;<red(0-255)>;<green(0-255)>;<blue(0-255)>m\\\033[m\""
}

実行するとこんな感じ. f:id:jp7fkf:20210617022851p:plain

References

CLIでサクっとimage名を指定してdocker tagの一覧を取得する話

dockerを使っているとpullするときにdocker tagを取得したくなることがよくある.どのversionのimageがdocker hubにあがっているのかをみてそれをversion指定してpullしたくなる時とか.

今回はimage名を指定してdocker tagの一覧を取得するようなzsh functionをつくってzshrcに記述し,CLI command的に利用できるようにしてみたので紹介する.なおこの内容はほぼ下記の内容を踏襲させてもらって,一部工夫をいれたものである.

su-kun1899.hatenablog.com

早速だが,モノは下記の通り.これを ~/.zshrc とかに書いておく.書いたあとに適当にshellを再起動するか, source ~/.zshrc とかをして読み込めば使えるようになる.

function docker-taglist (){
  local image=${1}
  local limit=${2:=1}

  # official image exists under /library path
  if [[ ! "${image}" =~ ^.+/.+$ ]]; then
    image="library/${image}"
  fi
  local next="https://registry.hub.docker.com/v2/repositories/${image}/tags"
  local names
  while [[ ${limit} -gt 0 && ${next} != "null" ]]
  do
    response=$(curl --silent --show-error "${next}")
    names="${names}\n$(echo ${response} | jq -r ".results|map_values(\"${image}:\"+.name)|.[]")"
    next=$(echo ${response} | jq -r .next)
    limit=$((${limit}-1))
  done
  echo -e "${names}"
}

やっていることは見ての通り簡単なもので,https://registry.hub.docker.com/v2/repositories/${image}/tagsを叩いて帰ってくるjson dataからほしいデータをjqで抜いて適当にくっつけているだけである.たとえばmysqlをimageを指定してを叩くと

% curl https://registry.hub.docker.com/v2/repositories/library/mysql/tags
{"count":119,"next":"https://registry.hub.docker.com/v2/repositories/library/mysql/tags?page=2","previous":null,"results":[{"creator":7,"id":20021,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:bbeff35b63bf28aeb024de309aab2d501f8aa30e94664d3840d55b36c8db53c8","os":"linux","os_features":"","os_version":null,"size":161997667,"status":"active","last_pulled":"2021-05-06T04:22:19.161759Z","last_pushed":"2021-04-19T19:14:41.194888Z"}],"last_updated":"2021-04-19T19:14:50.332131Z","last_updater":1156886,"last_updater_username":"doijanky","name":"latest","repository":21179,"full_size":161997667,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:22:19.161759Z","tag_last_pushed":"2021-04-19T19:14:50.332131Z"},{"creator":1156886,"id":146193135,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:bbeff35b63bf28aeb024de309aab2d501f8aa30e94664d3840d55b36c8db53c8","os":"linux","os_features":"","os_version":null,"size":161997667,"status":"active","last_pulled":"2021-05-06T04:22:19.161759Z","last_pushed":"2021-04-19T19:14:41.194888Z"}],"last_updated":"2021-04-19T19:14:47.441552Z","last_updater":1156886,"last_updater_username":"doijanky","name":"8.0.24","repository":21179,"full_size":161997667,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:22:19.161759Z","tag_last_pushed":"2021-04-19T19:14:47.441552Z"},{"creator":621950,"id":5471601,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:bbeff35b63bf28aeb024de309aab2d501f8aa30e94664d3840d55b36c8db53c8","os":"linux","os_features":"","os_version":null,"size":161997667,"status":"active","last_pulled":"2021-05-06T04:22:19.161759Z","last_pushed":"2021-04-19T19:14:41.194888Z"}],"last_updated":"2021-04-19T19:14:44.794422Z","last_updater":1156886,"last_updater_username":"doijanky","name":"8.0","repository":21179,"full_size":161997667,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:22:19.161759Z","tag_last_pushed":"2021-04-19T19:14:44.794422Z"},{"creator":621950,"id":5472027,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:bbeff35b63bf28aeb024de309aab2d501f8aa30e94664d3840d55b36c8db53c8","os":"linux","os_features":"","os_version":null,"size":161997667,"status":"active","last_pulled":"2021-05-06T04:22:19.161759Z","last_pushed":"2021-04-19T19:14:41.194888Z"}],"last_updated":"2021-04-19T19:14:42.993272Z","last_updater":1156886,"last_updater_username":"doijanky","name":"8","repository":21179,"full_size":161997667,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:22:19.161759Z","tag_last_pushed":"2021-04-19T19:14:42.993272Z"},{"creator":1156886,"id":146193124,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:9f768489d306402ea11243f1b96aeaa4696adb9ed7c1bb0318724759b9cbd1a6","os":"linux","os_features":"","os_version":null,"size":154430588,"status":"active","last_pulled":"2021-05-06T04:23:02.792412Z","last_pushed":"2021-04-19T19:14:07.955061Z"}],"last_updated":"2021-04-19T19:14:31.26934Z","last_updater":1156886,"last_updater_username":"doijanky","name":"5.7.34","repository":21179,"full_size":154430588,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:23:02.792412Z","tag_last_pushed":"2021-04-19T19:14:31.26934Z"},{"creator":7,"id":20000,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:9f768489d306402ea11243f1b96aeaa4696adb9ed7c1bb0318724759b9cbd1a6","os":"linux","os_features":"","os_version":null,"size":154430588,"status":"active","last_pulled":"2021-05-06T04:23:02.792412Z","last_pushed":"2021-04-19T19:14:07.955061Z"}],"last_updated":"2021-04-19T19:14:26.36101Z","last_updater":1156886,"last_updater_username":"doijanky","name":"5.7","repository":21179,"full_size":154430588,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:23:02.792412Z","tag_last_pushed":"2021-04-19T19:14:26.36101Z"},{"creator":1156886,"id":133913292,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:4d3ef8034652ee13d7db73eafeb783440a2f10f2dd54e4f8808718b0748cc053","os":"linux","os_features":"","os_version":null,"size":102980915,"status":"active","last_pulled":"2021-05-06T04:35:45.82737Z","last_pushed":"2021-04-19T19:14:17.44793Z"}],"last_updated":"2021-04-19T19:14:22.28644Z","last_updater":1156886,"last_updater_username":"doijanky","name":"5.6.51","repository":21179,"full_size":102980915,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:35:45.82737Z","tag_last_pushed":"2021-04-19T19:14:22.28644Z"},{"creator":7,"id":19961,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:4d3ef8034652ee13d7db73eafeb783440a2f10f2dd54e4f8808718b0748cc053","os":"linux","os_features":"","os_version":null,"size":102980915,"status":"active","last_pulled":"2021-05-06T04:35:45.82737Z","last_pushed":"2021-04-19T19:14:17.44793Z"}],"last_updated":"2021-04-19T19:14:17.836259Z","last_updater":1156886,"last_updater_username":"doijanky","name":"5.6","repository":21179,"full_size":102980915,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:35:45.82737Z","tag_last_pushed":"2021-04-19T19:14:17.836259Z"},{"creator":7,"id":19969,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:9f768489d306402ea11243f1b96aeaa4696adb9ed7c1bb0318724759b9cbd1a6","os":"linux","os_features":"","os_version":null,"size":154430588,"status":"active","last_pulled":"2021-05-06T04:23:02.792412Z","last_pushed":"2021-04-19T19:14:07.955061Z"}],"last_updated":"2021-04-19T19:14:10.182408Z","last_updater":1156886,"last_updater_username":"doijanky","name":"5","repository":21179,"full_size":154430588,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:23:02.792412Z","tag_last_pushed":"2021-04-19T19:14:10.182408Z"},{"creator":1156886,"id":133747539,"image_id":null,"images":[{"architecture":"amd64","features":"","variant":null,"digest":"sha256:355617769102e9d2ebb7d5879263a12d230badb7271c91748b2c7b0ac6971083","os":"linux","os_features":"","os_version":null,"size":159323709,"status":"active","last_pulled":"2021-05-06T04:53:14.908711Z","last_pushed":"2021-04-10T07:42:48.565852Z"}],"last_updated":"2021-04-10T07:42:55.155529Z","last_updater":1156886,"last_updater_username":"doijanky","name":"8.0.23","repository":21179,"full_size":159323709,"v2":true,"tag_status":"active","tag_last_pulled":"2021-05-06T04:53:14.908711Z","tag_last_pushed":"2021-04-10T07:42:55.155529Z"}]}

このような応答が帰ってくる.このうちそれぞれのエントリについてのtag name情報をjqで抜いている.抜いたtag nameを適当にimage名とコロンでくっつけて,コピペしてdocker pullにそのまま入れれるように加工してある.

実際に使ってみるとこのような感じ

# official image(library/mysql等library配下のもの)
% docker-taglist mysql

library/mysql:latest
library/mysql:8.0.24
library/mysql:8.0
library/mysql:8
library/mysql:5.7.34
library/mysql:5.7
library/mysql:5.6.51
library/mysql:5.6
library/mysql:5
library/mysql:8.0.23

# unofficial image
% docker-taglist mysql/mysql-server

mysql/mysql-server:latest
mysql/mysql-server:8.0.24-1.2.2-server
mysql/mysql-server:8.0.24
mysql/mysql-server:8.0
mysql/mysql-server:8.0.24-aarch64
mysql/mysql-server:8.0-aarch64
mysql/mysql-server:8.0.24-1.2.2-server-aarch64
mysql/mysql-server:latest-aarch64
mysql/mysql-server:8.0.24-1.2.2-server-amd64
mysql/mysql-server:8.0-amd64
%
% docker-taglist gitlab/gitlab-ee

gitlab/gitlab-ee:latest
gitlab/gitlab-ee:nightly
gitlab/gitlab-ee:rc
gitlab/gitlab-ee:13.11.3-ee.0
gitlab/gitlab-ee:13.9.7-ee.0
gitlab/gitlab-ee:13.10.4-ee.0
gitlab/gitlab-ee:13.11.2-ee.0
gitlab/gitlab-ee:13.11.1-ee.0
gitlab/gitlab-ee:13.11.0-ee.0
gitlab/gitlab-ee:13.10.3-ee.0

ページネーションも可能で,一度に多くのtagを取りたい場合は第二引数に取得ページ数を指定する.今回の実装では指定したページのみを取得するのではなく,指定されたページ数分全部を取得する.

% docker-taglist gitlab/gitlab-ee 2

gitlab/gitlab-ee:latest
gitlab/gitlab-ee:nightly
gitlab/gitlab-ee:rc
gitlab/gitlab-ee:13.11.3-ee.0
gitlab/gitlab-ee:13.9.7-ee.0
gitlab/gitlab-ee:13.10.4-ee.0
gitlab/gitlab-ee:13.11.2-ee.0
gitlab/gitlab-ee:13.11.1-ee.0
gitlab/gitlab-ee:13.11.0-ee.0
gitlab/gitlab-ee:13.10.3-ee.0
gitlab/gitlab-ee:13.9.6-ee.0
gitlab/gitlab-ee:13.8.8-ee.0
gitlab/gitlab-ee:13.10.2-ee.0
gitlab/gitlab-ee:13.8.7-ee.0
gitlab/gitlab-ee:13.9.5-ee.0
gitlab/gitlab-ee:13.10.1-ee.0
gitlab/gitlab-ee:13.10.0-ee.0
gitlab/gitlab-ee:13.7.9-ee.0
gitlab/gitlab-ee:13.8.6-ee.0
gitlab/gitlab-ee:13.9.4-ee.0

これでいちいちdocker hubを見に行ってtagを確認したりせずにCLIからサクサクdocker pullできている.いい感じだ.

References

2x4突っ張り方式で本棚を作った話

一人暮らしでそこまで広くない部屋に住んでるとどうしても気軽に本棚だとかの大型の家具を置いたりする決断ができずにいた.置いても場所を取るし,引っ越すときに次の家で活用できるかわからないし,結局買えない.

ところが最近は2x4などの木材を使って突っ張る方式で柱を立てて簡易的な家具を作ることができるものがある.ちょうど自宅に収納スペースがなくなってきていて困っているところだったので,この方式でDIYしてみようと思った.

突っ張り方式にもいろいろあるようでバネ圧を利用する方式(ディアウォールなど)や,一般的な突っ張り棒のようなネジを利用する方式(今回使うもの),あとはジャッキのような方式(突っ張りジャッキとかいう商品名で販売されている)があるらしい.突っ張りの強さによって使い分けたりすると良いようで,バネ<ネジ<ジャッキの順で強く突っ張れる傾向にあるよう.強く突っ張れればもちろん耐荷重等の制限もより幅広くなるようだ.

今回は手始めに下記のようなネジを利用した突っ張り方式でやってみることにした.

近くのホームセンターで2x4材と1x4材を調達し,所望の長さに加工してもらった.今回は加工してもらって自宅までハンドキャリー.2mくらいあったのでちょっと大変だったが近距離だったのでなんとかなった.一本物のほうが強度的に強そうな気がしたので一本にしてみたが,下記のようなパーツを使えば分割して持ち運んで構築時につなぐことも可能である.正直強度はあまり変わらない気もする.ちゃんと平面が出ていて合わせてあれば,2x4の縦方向であれば7割以上強度は保たれるような気がする.完全に勘だけど.
// もちろん切断下方向と同方向のせん断,曲げ応力は全然もたないだろうが,2x4を突っ張る場合切断面に垂直に圧縮応力がかかる形になるので,よほど条件が悪くない限りそれなりに強度が出そう,ということである.

あとは適当に2x4と1x4をつなぐ金具や,落下防止に使うようなパーツを揃える.今回は初手としてワイヤの張力を利用する方式を試してみた.ただしこれは実は失敗で,ワイヤを張り出すためのバーの強度が不足しがちになってしまった.後ほど画像で紹介するが,ワイヤ張力を利用するのは文庫本などの奥行きが小さいものだけに採用し,奥行きがあり張り出しが大きいものはLアングルに1x4をネジ止めして落下防止を施した.

これらを適当に組み合わせてつくった.

手順に従って2x4を2本使って柱を立てるが,かんたんにできた.垂直を見ておいたほうがいいので,水準器を使って垂直を見た.Tjimaの水準器をしばらく前に買っていたけど,活躍してくれた.Tajimaの製品はモノがよくて助かる.コンベックスメジャーとか,カッターナイフとか,電工ナイフとかもTajimaのやつを使ってるけど,全部気に入っている.

2x4自体が多少反っていることもあるが,そこは中央部付近で垂直を見るなどする. 続いて1x4をためしに止めて,強度の確認や本を実際に載せて張り出しのイメージをしていく. f:id:jp7fkf:20210503021631j:plain

見ていただけるとわかると思うが,空間を有効利用するために棚自体は天井付近に構成している.これで下の部分はまた違う用途に拡張して利用できるし,ロボット掃除機フレンドリーになるのもいいところ.下が狭いと空間が狭く感じるので足元は広いほうがいい. これでイメージが付いたら一気に仕上げていく.2x4, 1x4にタッピングをバシバシ打っていく.Makitaのペン型インパクトを持っていたので,これで.ペン型は小回りがきいていい.

ワイヤはそこまで張力をかける気はないので,電線用の丸型端子を圧着してネジ止めした.そんなこんなで完成. f:id:jp7fkf:20210503021731j:plain

棚板が1x4だと重たい技術書をたんまり載せた際の強度が心配だったが,やや歪みがあるものの,まだ余裕がありそうなくらいであった.もし今後湿度とかの影響で顕著に反ってきたりして危険性を感じたら1x6にするとかして強度をあげようかと思う(実は棚板を1x6にするか悩んだものの,価格が1x4の2倍以上したので1x4を選んでいた). 柱自体の強度については全然余裕がありそう.棚板自体も構成物の一部なので,これも強度を増加させる要因になっている.柱自体が歪んだりするのを抑えてくれていていい感じ.

落下防止のワイヤも板も,十分に効いていていいかんじである.手が滑って意図せず手前に本を倒してしまってもワイヤや板が受けてくれて落下が防げている.ワイヤについては全部の重量が一気にワイヤにかかったりすると不安があるが,そういうシチュエーションは常用する上ではあまり考えられないのでいいかと思っている.地震のときはどうなるかわからないが,たぶん持ってくれる気がしている. 落下防止のワイヤや板があるが,奥行きにやや余裕をもたせている(2-3cm程度?)ことや,高さにも余裕をもたせているので,本の背表紙側を軸に回転させてやる感じで出し入れができるようになっている.収納する本のうち一番大判な本をあてて現物合わせで位置決めをしているので,ピッタリである.

というわけで,いい感じに本が収納できるようになった.めでたし.

机の裏の地獄のケーブルを配線ダクトを使って整頓する話

前々からなんとかしないとと思っていたのだが,机の裏の配線類が地獄の形相を呈していた.Mac miniを自宅に導入してからますます配線も増えてしまっていた. f:id:jp7fkf:20210503021954j:plain

机の裏の配線類をなんとかできるものがないものかと色々amazonで調べてみたりしていて,下記のようなものならばたくさん見つかったが,どうやって机の裏にマウントしようとか,机の端から端までカバーできないとか,完全にきれいにできなさそうで導入できずにいた.

しかしなんとかしたいと思っていろいろとみっちり調べてみていたところ,下記のような商品を発見した.たしかにこれこそが私の望んでいたものだった.机の裏の端から端までがカバーできて,マウントもできる.ただし価格がネックだった.

これを見てうーんと考えていたところ,ケーブルをまとめるようなダクトは電気配線等で普通に使われているだろうという想定し,色々と調査してみたところ,「配線ダクト」と呼ばれるものがマッチした. 様々な会社の製品が配線ダクトというワードでヒットする.配電盤や,通信線などの集約をしているところでよく用いられるもののようだ.

amazonだと送料もついてしまってやや割高になってしまっているが,東京・秋葉原の愛三電気さんで同様の製品を扱っており,1本単位から購入できる.

星和電機 カッチングダクトBDR-682 1,830円 カッチングダクト・エスシーロック

愛三電気で手頃な価格で調達できるし,今回はこれを活用して自作してみることにした.

早速仕事終わりに愛三電気に行って調達してきた.今回使うカッチングダクトは60x80の幅と高さのものを採用した.OAタップとかACアダプタとかを入れたくなった時にも対応できるくらいのサイズとしてこれをチョイス.いい感じである. カッチングダクトと言う名の通り,スリットはニッパー等を使って簡単に切断できるようになっていて,自由にケーブルを出せるようになっている.便利. f:id:jp7fkf:20210503022047j:plain

カッチングダクトは図面が公開されていたので,これをもとに自分の机にマウントするためのアダプタを3Dプリンタを使って作る. f:id:jp7fkf:20210503022028j:plain f:id:jp7fkf:20210503022033j:plain f:id:jp7fkf:20210503022038j:plain

いい感じである.

アダプタができたら机にアダプタを付けるために穴あけをして,ネジ止めする. f:id:jp7fkf:20210503040546j:plain

ネジ止めしたアダプタにダクトを載せてみて,位置を見ていく. f:id:jp7fkf:20210503022232j:plain

机との隙間の感じとか,机とダクトの高さ関係や,まわりとの干渉がないかも確認.よさそうである. f:id:jp7fkf:20210503022227j:plain f:id:jp7fkf:20210503022252j:plain

よさそうであればダクトとマウントアダプタをネジ止めして,ごちゃごちゃだったケーブルをダクトの中に収めていく.絡まっているものはほどいて再配線.みるみるきれいになっていく. ケーブルを出す部分はニッパで切断して出してやる. f:id:jp7fkf:20210503022302j:plain

ケーブルをあらかたダクトに入れて整頓し,上のカバーをはめる.ごちゃごちゃだったケーブルがダクト内にまとまって見違えるようにスッキリした. f:id:jp7fkf:20210503022332j:plain

これで見た目もスマートになり,ケーブルも不意に絡まったりもすることなく快適に過ごせそうである.めでたし.