yuchiの日記

キーボード以外の話を書くぞの場所

スマートメーターから電力が取れるHEM-GW26Aを使ってPrometheus+Grafanaで電力を表示する

東芝ホームゲートウェイというものがありました。

https://www.tlt.co.jp/tlt/products/hems/hiroba/hgw-01.htm

スマートホームバイスとして対応したスマートメーター、家電、太陽光パネルコントローラーなどと接続することでブラウザから情報を見ることができる製品です。

メーカーページを見るとHEMSと蓄電池事業は撤退し、家の設備の1つとして使用することが想定されるものだが、発売から10年経ってない(2015年発売)のにアプリなどのサポートはすべて終わってて悲しい状況です。

この製品を少し前に安く中古が販売されていたのを購入してしばらく放置していましたが、久々に出して遊んでみた記録です。

賃貸で今使えるような機能としては電力計(スマートメーター)からの電力を見る程度ですが、セットアップしてブラウザで見るときちんと現在使用している電力量を見ることができました。

わざわざ画像として表示しているので、単純にページ内要素からスクレイピングをして電力の数値は取得するのは面倒そうです。

調べるとcurl経由で電力瞬間値を取得する方法を書いたQiita記事があったのでこれを参考にPrometheus+Grafanaで電力量を取得してグラフにしようと思います。

qiita.com

純粋なcurlで値を取得できれば/etc/prometheus/prometheus.ymlに書けば収集できそうですが、ヘッダ付与や16進数でのレスポンスなどがあるため、今回はGoでPrometheus Exporterを作成しました。

https://prometheus.io/docs/guides/go-application/

コード自体はGitHub Copilotを使ってあっという間に完成です。IPアドレスMACアドレスは適宜読み替えてください。

処理内容としては、特定のIPアドレスに10秒おきにアクセスし、取得できた値を16進数から10進数に変換、それを9091ポートでPrometheusが取れるようにするといったものです。

gist.github.com

これをサーバーのDockerなどで動かしてあげるとPrometheusから見れるようになると思います。

あとはGrafanaダッシュボードからPrometheusをソースにして設定すれば電力量のグラフが出るようになりました。

電化製品を動かしたときに顕著にグラフが跳ねるのが面白いですね。

家にいない時間帯はかなり低い値で変動なく推移するので在宅しているか否かが分かってしまうので防犯面からは取り扱いには注意したほうが良い値だと思います。

PrometheusやGrafanaでほぼリアルタイムの値が取得できているということは、規定の値(消費電力)を超えたらアラートを出してブレーカーが落ちる前に動かしている電化製品を止めるということもできそうですね。

しばらくはこれらの値を使って、「自分が考える最強のお家ステータスダッシュボード」を作ってみようと思います。

OpenTelemetryに入門する

この記事は🎄GMOペパボエンジニア Advent Calendar 2023 17日目の記事です

adventar.org

概要

最近社内やSRE関係のイベントなどでOpenTelemetryの話題を聞くようになったので「雰囲気で話を聞いている」を脱すべく色々調べた記録です。自分用のメモを公開用に編集したので文章がおかしいところがあるかもしれないですがお許しください。

OpenTelemetryは日々開発が進んでいるプロダクトです。最新の情報は各種公式ドキュメントを参考にすることをおすすめします。(この記事は2023年12月の情報を元に記事を書いています)

OpenTelemetryについて知る

OpenTelemetryはログやメトリクス、トレースのテレメトリデータを作成、管理するために設計されたObservability(可観測性)フレームワークおよびツールキットでベンダー依存ではなく共通の規格となっている。

https://opentelemetry.io/docs/what-is-opentelemetry/

Observability(可観測性)とは

ざっくり以下2点 - システムを詳細に分かってなくても何の問題が起こっているかが分かりやすくなる。 - 新たな問題のトラブルシュートが分かりやすくなる。

この状態にするにはアプリケーションコードがトレース、メトリクス、ログを出す必要がある。

https://opentelemetry.io/docs/concepts/observability-primer/#what-is-observability

OpenTelemtryの仕組み

OpenTelemetry対応させたアプリケーション上からOTel Collectorを通してGrafanaやJaegerなどに送るような流れになっている。

今までの各プラットフォームのAgentが担っていた箇所をOTel Collectorで置き換えるようなイメージ。設定次第で併用もできる。

引用: https://opentelemetry.io/docs/

実際に触ってみる

公式ドキュメントにはGoの1~6の数字をブラウザ上に出すサンプルコードが示されているのでそれを参考にブラウザでアクセスすると標準出力でトレース情報が吐き出されるようにします。

opentelemetry.io

吐き出されたトレース情報

{
        "Name": "roll",
        "SpanContext": {
                "TraceID": "1b256e3bcf583dcb2f693aa5b9f135be",
                "SpanID": "3314466bc6b8d377",
                "TraceFlags": "01",
                "TraceState": "",
                "Remote": false
        },
        "Parent": {
                "TraceID": "1b256e3bcf583dcb2f693aa5b9f135be",
                "SpanID": "7655ef934c2b3460",
                "TraceFlags": "01",
                "TraceState": "",
                "Remote": false
        },
        "SpanKind": 1,
        "StartTime": "2023-12-08T03:39:46.663242+09:00",
        "EndTime": "2023-12-08T03:39:46.664132+09:00",
        "Attributes": [
                {
                        "Key": "roll.value",
                        "Value": {
                                "Type": "INT64",
                                "Value": 6
                        }
                }
        ],
        "Events": null,
        "Links": null,
        "Status": {
                "Code": "Unset",
                "Description": ""
        },
        "DroppedAttributes": 0,
        "DroppedEvents": 0,
        "DroppedLinks": 0,
        "ChildSpanCount": 0,
        "Resource": [
                {
                        "Key": "service.name",
                        "Value": {
                                "Type": "STRING",
                                "Value": "dice"
                        }
                },
                {
                        "Key": "service.version",
                        "Value": {
                                "Type": "STRING",
                                "Value": "0.1.0"
                        }
                },
                {
                        "Key": "telemetry.sdk.language",
                        "Value": {
                                "Type": "STRING",
                                "Value": "go"
                        }
                },
                {
                        "Key": "telemetry.sdk.name",
                        "Value": {
                                "Type": "STRING",
                                "Value": "opentelemetry"
                        }
                },
                {
                        "Key": "telemetry.sdk.version",
                        "Value": {
                                "Type": "STRING",
                                "Value": "1.21.0"
                        }
                }
        ],
        "InstrumentationLibrary": {
                "Name": "rolldice",
                "Version": "",
                "SchemaURL": ""
        }
}
{
        "Name": "/",
        "SpanContext": {
                "TraceID": "1b256e3bcf583dcb2f693aa5b9f135be",
                "SpanID": "7655ef934c2b3460",
                "TraceFlags": "01",
                "TraceState": "",
                "Remote": false
        },
        "Parent": {
                "TraceID": "00000000000000000000000000000000",
                "SpanID": "0000000000000000",
                "TraceFlags": "00",
                "TraceState": "",
                "Remote": false
        },
        "SpanKind": 2,
        "StartTime": "2023-12-08T03:39:46.663201+09:00",
        "EndTime": "2023-12-08T03:39:46.664580041+09:00",
        "Attributes": [
                {
                        "Key": "http.method",
                        "Value": {
                                "Type": "STRING",
                                "Value": "GET"
                        }
                },
                {
                        "Key": "http.scheme",
                        "Value": {
                                "Type": "STRING",
                                "Value": "http"
                        }
                },
                {
                        "Key": "http.flavor",
                        "Value": {
                                "Type": "STRING",
                                "Value": "1.1"
                        }
                },
                {
                        "Key": "net.host.name",
                        "Value": {
                                "Type": "STRING",
                                "Value": "localhost"
                        }
                },
                {
                        "Key": "net.host.port",
                        "Value": {
                                "Type": "INT64",
                                "Value": 8080
                        }
                },
                {
                        "Key": "net.sock.peer.addr",
                        "Value": {
                                "Type": "STRING",
                                "Value": "::1"
                        }
                },
                {
                        "Key": "net.sock.peer.port",
                        "Value": {
                                "Type": "INT64",
                                "Value": 50016
                        }
                },
                {
                        "Key": "http.user_agent",
                        "Value": {
                                "Type": "STRING",
                                "Value": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"
                        }
                },
                {
                        "Key": "http.route",
                        "Value": {
                                "Type": "STRING",
                                "Value": "/rolldice"
                        }
                },
                {
                        "Key": "http.wrote_bytes",
                        "Value": {
                                "Type": "INT64",
                                "Value": 2
                        }
                },
                {
                        "Key": "http.status_code",
                        "Value": {
                                "Type": "INT64",
                                "Value": 200
                        }
                }
        ],
        "Events": null,
        "Links": null,
        "Status": {
                "Code": "Unset",
                "Description": ""
        },
        "DroppedAttributes": 0,
        "DroppedEvents": 0,
        "DroppedLinks": 0,
        "ChildSpanCount": 1,
        "Resource": [
                {
                        "Key": "service.name",
                        "Value": {
                                "Type": "STRING",
                                "Value": "dice"
                        }
                },
                {
                        "Key": "service.version",
                        "Value": {
                                "Type": "STRING",
                                "Value": "0.1.0"
                        }
                },
                {
                        "Key": "telemetry.sdk.language",
                        "Value": {
                                "Type": "STRING",
                                "Value": "go"
                        }
                },
                {
                        "Key": "telemetry.sdk.name",
                        "Value": {
                                "Type": "STRING",
                                "Value": "opentelemetry"
                        }
                },
                {
                        "Key": "telemetry.sdk.version",
                        "Value": {
                                "Type": "STRING",
                                "Value": "1.21.0"
                        }
                }
        ],
        "InstrumentationLibrary": {
                "Name": "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp",
                "Version": "0.46.1",
                "SchemaURL": ""
        }
}

標準出力されるだけではトレースするには難しいため、可視化するために外部のツールへ送信します。 今回はGrafana Agentを用いて先程のトレース情報をGrafana Cloudへ送り可視化してみます。

標準出力で出すコードをOTLPを用いてhttp経由で送信するように変更をします

// otel.go

func newTraceProvider(res *resource.Resource) (*trace.TracerProvider, error) {
    ctx := context.Background()
    traceExporter, err := otlptracehttp.New(
        ctx,
        otlptracehttp.WithEndpoint("grafana-agent:4318"),
        otlptracehttp.WithInsecure(),
    )

Grafana Cloudへ送信するため使用するGrafana Agentの設定ファイルを作ります。 まずはGrafana Cloudのページ(https://grafana.com/orgs/[Organization Name])から今回使用するTempoの情報を確認します。

Password:の欄にあるGenerate now.からAPI Tokenを作成するとRead権限しかないAPI Tokenになって書き込みができないので注意が必要です。気づかず2時間近く溶かしました。

https://grafana.com/orgs/[Organization Name]/access-policiesから新たにTempoへのWrite付きのAPI Tokenを作成しましょう

必要な情報が揃ったらconfig.yamlを作成します。必要な箇所は置き換えてください。

# config.yaml
traces:
  configs:
  - name: default
    receivers:
      otlp:
        protocols:
          http:
            endpoint: 0.0.0.0:4318
    remote_write:
      - endpoint: [tempo-url].grafana.net:443
        basic_auth:
          username: [UserID]
          password: [API Key]

Goで作成したアプリケーションとGrafana AgentをDockerComposeで起動できるようにDockerfileとdocker-compose.yamlを用意します。

FROM golang:1.21
WORKDIR /go-rolldice
COPY . .
RUN go mod tidy
RUN go build -o app .
CMD ["/go-rolldice/app"]
# docker-compose.yaml
version: '3'
services:
  go-rolldice:
    container_name: go-rolldice
    image: go-rolldice
    ports:
      - "8080:8080"
    build: .
    volumes:
      - .:/etc/go-rolldice/
    environment:
      - OTEL_SERVICE_NAME = go-rolldice
      - OTEL_METRICS_EXPORTER = otlp
  grafana-agent:
    container_name: grafana-agent
    image: grafana/agent:latest
    ports:
      - "4318:4318"
    volumes:
      - ./grafana-agent/config.yaml:/etc/agent/agent.yaml
    command: -config.file=/etc/agent/agent.yaml

docker-composeで起動してlocalhost:8080/rolldiceへ数回アクセスし、GrafanaのExploreからTempoを選ぶと届いているトレース情報を確認することができます。

シンプルなアプリケーションなので複雑なトレース情報ではないですが、ちゃんとroll.valueが4のトレースデータが届いて見ることができました。

まとめ

公式のドキュメントを参考にOpenTelemetryの初歩的なところを触ってみました。

OpenTelemetryはどのように動いているか、実際のアプリケーションコードへ導入するにはどのように変えていくと良いかのイメージを少しつけることができました。

なにより使用される単語が少々特殊なものが多い印象だったのでそれらの意味を理解できただけで非常に良かったです(実際CNDT2023へ行く前に調べていたのでセッションを聞きながら「この前調べたやつだ!」と思っていました)

この記事がOpenTelemetryを初めて触る方の参考になれば幸いです。

天下一キーボードわいわい会 Vol.5を支えたハイブリッド配信技術

先月開催された天下一キーボードわいわい会 Vol.5で配信担当をしましたyuchiです。

tenkey.connpass.com

1ヶ月ほど経ってしまいましたが、天キーvol.5は過去最高の物量と規模で配信を行っていたのでその裏側を解説したいと思います。

実際の配信アーカイブは現在もご覧いただけます。

www.youtube.com

天キー配信チーム

天キーvol.5配信チームとして自分、kai4562さん、daihukuさんの3人で配信を行いました。それぞれ機材を持ち寄っていただき、当日オペレーション協力をしていただき無事に事故なく配信を行うことができました。

今回用いた機材は会場で一部お借りしたものを除いてレンタル一切なしのすべて配信チームの私物です。

自分の持ち込んだケーブル類に関しては合計100mを超えていました

加えて全て手搬入をおこなったので同じビルに入っているテレビ局で使われてそうな箱を転がしながら会場へ入りました。

構成図

まずは今回使用した配信システムの構成図を見ていただいて簡単に解説していきます。

ATEM 2 M/E Constellation HD

今回配信機材のコアにATEM 2 M/E Constellation HDを使用しました。 この機材を買った理由などは別エントリーで詳しく書いたので合わせて読んでいただければ。

yuchi51.hatenablog.com

今回入力はカメラが3台、登壇者のスライドのPC、セッション間の幕間に出す写真を出すPCで合計5入力ありました。

機器の出力はHDMIですが、スイッチャーの入力はSDIのためすべてコンバーターを挟んでいます。

自由にルーティングが行える出力端子が今回非常に役に立ちました。 構成図で書かれているのは以下のように使っていました。

  • OUT1 : スライドPC(IN 3)から来た映像を会場画面に出力
  • OUT2: スライドPC(IN 3)から来た映像を登壇者足元に置かれるどのような映像が出ているかの確認モニター(返しモニター)に出力
  • OUT3: カメラ映像(IN 1)からきた映像を録画用にHyperdeck Studio 12Gへ出力
  • OUT4: 配信に使っている映像(M/E 1)をプレビューモニター兼録画としてSHOGUN 7へ出力
  • OUT10: 配信用にスイッチングした映像(M/E 1)をYouTubeへ送るためにWebPresenter HDへ出力

元々自分が使っていたATEM Miniシリーズでこれを行おうとすると入力の前段にHDMIのスプリッターを入れるなどの手段がありますが、配信機材において機材やケーブル接点が増えることが映らないなどの事故リスクがあがることはもちろん、それぞれ出力の切り替えにケーブルの抜き差しや別途スイッチャーが必要など色々大変です。

カメラ

カメラは今回3カメラ体制で行いました。

セッション会場では登壇者の寄りと会場を含めた引きの映像を用意しました。

カメラはkaiさんに用意していただき、それぞれのカメラの上にはkaiさんが開発したタリーランプを載せてATEM Constellationシリーズでうまく動作するかの検証も兼ねて運用してもらいました。

もう1カメラはメイン会場のオープニングとエンディングの様子を撮影してもらい、HDMIのトランスミッターで映像を伝送しました。

2スペースにまたがる会場

今回、DMM.comさんの会場を再びお借りして開催されましたが、1回目~3回目まで使っていた会場に加えて新たにもう1スペース使わせていただけることができ、それぞれで登壇者の様子を映す必要が出てきました。

構成図上だと点線から左側がその今回新たに加わった会場です。非常に広い会場で、それぞれのスペースの間は30m以上開いているため無線か有線どちらの映像伝送を用いるか悩みます。

結論から言うと今回は無線での伝送を選択しました。

SDIケーブルを引く方法は30m以上離れていたため、3CのSDIケーブル*1では伝送できない可能性があり、5Cを用意する必要があります。5Cの50mのケーブルを手で持ち込むのは非常に大変なのが容易に想像できるため不採用でした。

今回の使用したHDMIトランスミッター MARS300は5.2GHz帯を用います。WiFiの5GHz帯と似たように直進性能が高く、天キーのイベント会場のような人が多い場所で使用すると大きく減衰されてしまい、映像が来ないことも考えられます。

今回行った対策は会場にあったライトのスタンドを許可を得てお借りし、クランプでレシーバーを挟んで最大限高さを稼ぐ方法でした。

本番中もちょくちょく映像が来ないことが起こり、その度にスタンドの高さを上げて最終的には2.5m以上になっていたと思います。それほど人による減衰は大きかったです。

やってみての感想

この会場規模、機材量、チーム人数での配信は初めてだったので事前に会場入りの時間から撤収まで含んだオペレーションの進行台本を作ることや自宅での通しテクリハなどなど。それでも当日想定通り進まないのが配信です。

前半は配信を行いつつ、トラブル解消のため配信卓周辺であれやこれやとバタバタしていました。

また、連絡はDiscordを使用していましたが、すぐに気づくことができなかったり、リアルタイム性を求められることもありインカムやトランシーバーの導入は必須だなと感じました。

色々細かいミスや想定外のことがありましたが、終わったあとのビールは最高ですね。

まとめ

ハイブリッド配信かつリアル会場が複数ある場合機材やオペレーション、配信事故に繋がりそうなリスクが高く非常に大変です。

今回は大きな事故なく配信を無事に終えつつ、小さいミスに関しては次は起こさないようにするといった今後必ず役に立つ経験となりました。

また、配信チームとして協力してくださったkaiさん、Daihukuさん、配信画面デザインをしていただいたPekasoさん、天キー主催のゆかりさん他当日も様々な方にお手伝いいただきました。ありがとうございます。

天キーVol.6が開催された際は配信卓に座っていると思うので興味ありましたらお気軽にお声がけください。

*1:SDIケーブルには太さの規格があります。数字が低いほど細くしなやかで軽いですが数字が増えれば太く取り回しがしにくくなりますが、伝送距離が伸びます

Blackmagic Web Presenter HDのフェイルオーバーの挙動を調べた

スイッチャーを乗り換えてから配信はBlackmagic Web Presenter HDを使っています。

www.blackmagicdesign.com

この機材は有線LANだけではなく、USB Type-C端子からスマートフォンテザリング機能を使ってバックアップの回線を用意することができます。

USBテザリング機能があるモバイルルーターも使えるので絶対に落としたくないような現場では回線の冗長化を行っていました。幸いなことに今まで有線LAN側で問題が起こったことなく、実際に問題が発生したときにフェイルオーバーの挙動がどうなるのかが気になったので意図的にLANケーブルを抜いたときの挙動を調べてみました。

検証環境

  • Blackmagic Web Presenter HD
    • バージョン3.3
      • iPhone 13 ProをType-C to Lightningで接続
    • 配信設定

実際に配信中にLANケーブルを抜いてみる

図のようにルータースイッチングハブを繋がっているLANケーブルを抜き、スイッチングハブとBlackmagic Web Presenter HDはリンクアップしている状態にしました。

結果としてはフェイルオーバーされることなく配信がストップしてしまいました

次にWeb Presenter HDに刺さっているLANケーブルを抜いて挙動を確認してみます。

この場合は正しくスマートフォン側にフェイルオーバーされて配信が継続できました。生放送アーカイブを確認すると8秒程度の映像の欠落が発生していました。

Web Presenter HDのコンソールの録画のスクリーンショットです。00:01:00にLANケーブルを抜いてます。

わかりにくいですがON AIRの横のスマホマークが1分3秒ごろに青くなり回線の切り替えが行われたことを表しています。

逆にスマートフォン側で配信が行われている状態でLANケーブルを戻してもスマートフォン側で配信が継続しました。 この点はフェイルオーバー後気づかずに配信継続が行われて通信量制限にかからないように注意が必要ですね。

最後に有線LANが繋がっている状態でスマホ側の接続を切ると4秒程度の映像の欠落が発生しました。スマホ→有線LANの切り替えはすぐに行われるようです。

実際の配信アーカイブです。以下のタイミングで抜き差しを行っています。

  • 00:01:00 有線LAN接続断
  • 00:01:30 有線LAN差し込み(変化なし)
  • 00:02:00 iPhone接続断

www.youtube.com

まとめ

フェイルオーバーされる条件は有線LANのリンクアップが切れたらということが分かりました。 有線LAN側の通信速度が著しく遅くなったり、ルーター側の電源停止やルータースイッチングハブの間のLANケーブルが切断されることが発生しても、Web Presenter HDがスイッチングハブと繋がっているとLANのリンクアップが継続されるためフェイルオーバーにはなりません。物理層レベルで接続が無くなることがフェイルオーバーの条件のように考えられます。

なのでコンソールのキャッシュが急増してすぐに戻らないようであれば有線LANを抜いてスマートフォン側に切り替わるようにする必要がありそうです。

誰かの参考になれば幸いです。

強くて名前が長いスイッチャー(Blackmagic Design ATEM 2 M/E Constellation HD)を買った話

1ヶ月ちょっと前にBlackmagic Design ATEM 2 M/E Constellation HDと言う半業務用みたいなスイッチャーを買いました。製品名が本当に長い。 www.blackmagicdesign.com

ATEM Constellationシリーズは1M/E,2M/E,4M/Eと大きく3つのモデル展開があってその内の松竹梅でいうと竹を購入。
この機械1つで2系統のスイッチングができます。

購入に至るまでの話

元々メインで使っていたスイッチャーがATEM Mini Proで値段やサイズ感ともに非常に導入しやすく、単体でライブエンコーダーやMASTERの外部メディアへの録画機能を有している便利なスイッチャーを使ってました。
オンライン配信/オフラインのスイッチングだけであればこれやOBSがあれば十分事足りる状況ではあったのですが、オフラインとオンラインのハイブリッドイベントが増える中で「複数の登壇者の映像とスライドを写したい」「1つの機材で配信と現地別々の映像を作って出したい」という要求が出てくるとATEM Mini ProではPinP/1系統出力しか行えないので要件を満たさなくなってしまいました。
次に出てくるのがOBSなどのソフトウェアでの選択肢になりますが、動作の信頼性を考えると個人的にはあまり取りたくない手段です。
そうすると4入力を同時にハードウェア上で合成できるSuperSource機能を有しているATEM Mini Extremeの選択肢が上がってきました。

www.youtube.com

懸念点としては3つあります。

  • オーディオインプット
    オーディオのインプットが3.5mmのステレオステレオミニと言う点。

ミキサーなどのバランスXLR出力をアンバランスのステレオミニの入力に入れるには以下のようなレベルコンバーターが必要となるため、躊躇していました。

  • HDMI入力
    ハイブリッドで行う場合、会場が広いとHDMI(~10m)では足りずSDIで引きまわすことが多いのでカメラからのHDMI to SDI、SDI to HDMIの変換器のペアを信号数だけ必要になるといった点もありました。

  • 出力系統
    コンシューマー製品のスイッチャーなので複数入力1出力が当たり前ですが、ハイブリッドイベントだと配信用の画と会場用の画は別々に作りたいわけです。
    会場にPinP付きの映像は要らないですし、配信にスライドだけの画を出すのも雰囲気が全く伝わらないので複数のスイッチャーを用意して映像をスプリッターなどで分割する必要があります。
    個人的には(モノによりますが)HDMIスプリッターの信頼性は低いと思っており、当日映らない/途中で映らなくなったというのは避けたいです。胃とメンタルは強くないので。
    そうすると必然的に2系統スイッチングができる機材が欲しくなります。

朝4時の出会い

ATEM Constellationシリーズの存在は認知していましたが、実売20万円を超えていたため予算オーバー。選択肢にも入っていなかったのですが、夜中機材屋のセール情報を見ていたら16万円で販売しているのを見つけてしまい「安すぎる!!!」と一人で1時間ぐらい悩み、仕様とマニュアルを読み漁って買いました。

1つの機材に入れた映像信号を2系統のスイッチングのソースとして扱えるのはハイブリッドイベントでは心強い機能です。
ハイブリッドイベントでの配信の大変さに関してはこの記事がとても共感できたのでぜひ読んでみてください。

jaco.udcp.info

こうして夜中の勢いで機材をお迎えしました。

買ってからやったこと

SDIコンバーター

この機材はHDMI端子は一切なく、すべての入出力すべてがSDIで行われるため結局コンバーターを買いました。 元々1セット所有していたためHDMI to SDI 3台とマルチビュー用、マスターアウト用にSDI to HDMIを1台買い足しました。

ヘッドホンモニター用の変換アダプター

ATEM Constellationシリーズのヘッドホンモニターはトークバックヘッドセット用のXLR 5Pinです。ステレオフォンとかじゃないです。
モニター出力のために業務用のヘッドセットなんてものは必要ないのと、現場へ持っていく機材量を考えればiPhoneに付いていた白イヤホンでモニターしたいです。

この世の中にはXLR 5Pinからステレオフォンの変換など無く、必然的に自作するしかなくなりました。
5Pinなので1,2はLRの音声、3はGND、4はマイク、5はマイクGND or 通信っぽい と考えれば自作できる気がすると思えます。出てくるのは音声信号なので間違っても火を吹いたりしないので安心ですね。

スピーカーケーブルとステレオフォンコネクタのメスは家に転がっていたのでサウンドハウスの注文のついでに以下のXLR 5Pinコネクタを購入。
みんなだいすきCLASSIC PRO。250円で買えます。

https://www.soundhouse.co.jp/products/detail/item/244367/

出力ピンはインターネットの海を探すと同じことをやろうとしている人がすでにBMDに問い合わせをして聞いてくれたっぽく、それを信じて自作です。

1発で音が出たので完全に満足です。あくまでも自己責任で。

Blackmagic Web Presenter HD

こいつはATEM Mini Proと違って単体では配信できないです。かといってわざわざATEM Miniに信号入れて配信したり、OBSで配信なんてもってのほかです。
もうハードウェアしか信じれないのでSDI入力できるハードウェアライブエンコーダーを買いました。
ステータス情報の画面がかっこいい。これのために買ったみたいなところがあります。
ステータス画面もSDIで出せるので(うれしい) ATEM 2 M/E Constellation HDのInputに入れて1台のプレビューモニターで確認しています。

ラック

ATEM 2 M/E Constellation HDは1Uサイズでラックマウントできる機材です。 Blackmagic Web Presenter HDも高級金属板を買えばラックマウントできます。

この機材単体で複数の現場に持っていきましたが、設営撤収でプチプチでくるんだり背面の接続が大変だったりして「箱を現場の卓に置いて電源とLANとSDI信号を必要なだけ入れたら配信即スタート!撤収もコネクタからケーブル抜いて巻くだけ即撤収!」ができるロマンを求めてラックを作ることにしました。

機材素の状態で持っていて現地で0から設営/接続やると地獄になります。

会場からの電源、有線LAN、XLRのオーディオ、SDI信号、ATEM制御用のMacBookUSB3.0のコネクタに挿せば配信がすぐにできる箱が完成しつつあります。
事前の仕込みとカメラの設営、音周りチェックを同時並行で行えば最短10分とかでOnAir Ready状態までできるはずです。
まだ未完成なので今月中には完成させたい。

運搬手段も忘れずに。 www.monotaro.com www.monotaro.com

SDIケーブル自作環境

スイッチャーから背面パネルのコネクタまで短いSDIケーブルが大量に必要となります。また、長いSDIケーブルも必要になることがわかっていったので思い切って100m巻のSDIケーブルを買いました。
毎回既製品なんて買ってられないですからね。

コネクタはヤフオクなどでたまに出てくるのを落札して圧着はCANARE純正などは買うほど余裕がないのでパチモンを使います。事故っても自己責任というのは認識の上で。

本業は何なの

SREっぽいことをやっています。配信全く関係ないです。
趣味でやってるので休日とかであればご相談いただければ機材担いで配信できますのでお気軽にお声がけ下さい。

C102に売り子で参加した

終わって数日経ってしまったけど記録的に書いています。 コミックマーケット102の2日目に身内でやってるサークルの売り子として参加。 前回の冬コミで初めて同人誌を作って疲れ果ててしまったのでサークルとしては参加しませんでしたが、前述のサークルの新刊に寄稿をさせてもらいました。 自分は最近流行りのChatGPTにVJで使う映像を作らせることができるかの実験的なものをまとめた記事を書きました。

biacco42.hatenablog.com

C102 1日目は日差しがすごかったらしいという情報をTwitterから得ていたのですが、2日目は曇予報だったのでそこまでじゃないだろうと思い暑さ対策の気が緩んでましたね。

初めて壁配置(壁サー)で荷物が置けるスペースに感動しつつ、追加椅子余裕で座れるなと思っていたらすでに貸出終了。9時入場では遅かったです。 開場まではそこそこ空調が効いている感じがしましたが、開会と同時に外と面するシャッターが空き、人の熱気でどんどんと温度湿度が上がっていくのを肌で感じることができるレベル。 寝不足も相まって思った以上に体力が削られてしまって西の中を少し回るだけで疲れ果ててしまったのが完全に今回の反省。

打ち上げも含めてコミケに行くと創作意欲が刺激されるのでC103のサークル申し込みの決済までやった。何を出すか全く考えてないので残り2日の夏休みの間で考えたい。

めちゃくちゃ刺さったポッドキャストを共有 open.spotify.com

#RubyMusicMixin2023 でDJとVJと撮影をやった

RubyKaigi2023のクロージング後、Pixivさん主催のRubyMusicMixin2023でDJとVJと撮影をしたのでせっかくなら書こうと思って書いてます。
キーボードのことしか書いてないブログはあるけど、こういう感じの記事をかけるブログがなかったので新規作成しました。

DJ

トップバッターでDJをやりました。開催したGNUさんはクラブと言うよりもカフェ&バー的なお店だったので、そこで行うイベントのオープニングはゆったり目でやろうと決めていました。RubyKaigi3日目でみんな疲れているだろうし...
しかし始まってみると結構DJブース近くで踊ってくださる方がいたので途中からBPM上げていい感じに盛り上がる感じのダンスミュージックに変えて、いい感じにフロアを暖める状態に持っていって次のDJにバトンタッチしました。
自分が思っていたよりも踊ってもらったり反応があったりで楽しくDJできました!

録音もあるのでどうぞ

www.mixcloud.com

VJ

DJの他にVJもやっていました。VJとはフロアにいい感じの映像を出す人で照明演出とかに近いと思ってもらえればと思います。
今回クラブ備え付けのプロジェクターではなく持ち込みでプロジェクターとスクリーンを設置したのでかなり迫力のあるVJができたと思います。

今回はあやぬんさんさんにもVJやってもらって初めてとは思えない、最高のVJをやってもらいました。ありがとうございます!!!
おかげで写真撮りに行ったりフロアで踊れました。ワンオペVJじゃないイベント、最高。

ayatk.hatenablog.com

最初に「いい感じの映像」と書きましたが、イベント中の半分以上はYouTubeの映像を引っ張ってきてやってました。
unasukeさんのDJ時はunasukeさんが深夜にドライブをしているVLOG?の深夜徘徊シリーズを流してました。DJをやってる人の横でその人が深夜にドライブしている動画、映えますね(本当か?)。

フロアからのリクエストを受けてその場でダウンロードして流したのも中々ウケたので良かったです。

好きな曲はイントロで即映像を出し、フロアに飛び出て踊ることができたので最高

最後の方はかかった曲を思い出してYouTubeで検索するイントロドンゲーム状態でした。
VJ卓の周りは曲が変わるたび「あれだよあれ!!!!」「なんだっけ!!!!」「(アーティスト名)!!!!!」「(曲名)!!!!!!!!!!!」みたいな状態でした

普段はアニソンでVJすることがないので流れている音楽と映像の歌詞や口の動きを合わせるリップシンクはほぼしたことなかったのですが、気合で合わせてました。オタクのこだわりポイントです。
リップシンクに気づいてくれる人も居て、めっちゃ褒めてもらえたの嬉しかったです。
今回の現場はいつも使わないようなVJ力を試されたのと、VJ卓から見えるフロアで踊る人の姿がかなり良かったです。

余談ですが、今回のVJをするためだけにスーツケースの半分がVJ用の機材になってました。
松本までPCスタンドとAPC40 mk2を持ち込むのなかなか気合がいりました。

フォト

VJと並行してイベントフォトもやってました。α7Ⅲ+24-105 F4+ストロボの組み合わせで盛り上がる人々を撮影していました。
すべて最高の写真ばかりなのですが、顔が写ってるものが多いので公開は一部に留めようと思いますが、こんな感じの写真が100枚以上あります。

まとめ

RubyMusicMixin2022でもDJをやっており、その時もとても良いイベントだな〜と思っていましたが、今年はそれを大きく上回る盛り上がりで数日経った今もあの時のお祭り気分が残っています。
来年も開催されるのであれば同じようにDJやVJ、撮影やりたいなと強く思えるイベントでした。
主催のPixivの方々、来場して踊ってくださったRubyistの方々、そして会場のGNUさんありがとうございました。