Tumgik
sokosun · 7 months
Text
printf の書式は分かるのに std::cout で桁揃えする方法を思い出せないときに見るエントリ
概要
printf の書式はソラで書けるけど std::cout で同じことをする方法が出てこない俺のためのチートシート。特に std::format が使えない環境のための覚書。
書式
#include <iostream> #include <iomanip> // std::setw, std::setfill #include <bitset> // std::hex #include <format> // C++20
int i = 123;
// Output: "i = 123(0x007b)" printf("i = %4d(0x%04x)\n", i, i); std::cout << "i = " << std::setfill(' ') << std::setw(4) << i << "(0x" << std::setfill('0') << std::setw(4) << std::hex << i << ")" << std::endl; std::cout << std::format("i = {:4d}(0x{:04x})", i, i) << std::endl; // C++20
double d = 12.345;
// Output: "d = 012.35" printf("d = %06.2f\n", d); std::cout << "d = " << std::setfill('0') << std::setw(6) << std::fixed << std::setprecision(2) << d << std::endl; std::cout << std::format("d = {:06.2f}", d) << std::endl; // C++20
補足
左寄せ, 両寄せを使用する場合は #include して std::left, std::right, std::internal を適宜追加
std::showbase を使用すると std::setw の値が読みにくくなるので使わない
std::format は同じ引数を複数回参照できるが読みにくくなるので使わない
空白埋めだけでよいなら std::setfill は不要
末尾の改行なしで即時出力したいなら std::endl の代わりに std::flush を使う
0 notes
sokosun · 10 months
Text
TP-Link L530E controlled by AtomS3 Lite
0 notes
sokosun · 10 months
Text
ESP32 でスマート電球を叩く
概要
ESP32(AtomS3) から TP-Link のフルカラースマート電球 L530E を制御した記録
undefined
tumblr
はじめに
フルカラーのLED電球を一つ持っておくと何かの役に立つかもと思ったので TP-Link P105 と同じように叩ける TP-Link L530E を買って実際に叩いてみました。
プロトコル
スマートプラグ TP-Link P105 と同様。HSBによる色指定と色温度&明るさによる色指定ができる。詳細はサンプルコード。
サンプルコード
https://github.com/sokosun/atoms3_l530e_control/
参考
それ AtomS3 Lite でできたよ
https://github.com/fishbigger/TapoP100
0 notes
sokosun · 11 months
Text
TP-Link TC70 synchronized with M5Stack AtomS3
0 notes
sokosun · 11 months
Text
ESP32 で TP-Link TC70 をコントロール
概要
AtomS3 (ESP32) からネットワークカメラ (TP-Link TC70) のパン・チルトを ONVIF プロトコルで制御した話
はじめに
TP-Link のネットワークカメラは ONVIF というオープンプロトコルに対応していて外部からパン・チルト等の制御が可能です。スマホをVRゴーグルにセットしてスマホの傾きとパン・チルトを同期すれば面白そうな気がしたので動画のもの作ってをみました。
undefined
tumblr
設計
スマホ内蔵の加速度センサを使用して全てスマホアプリで実現することもできるのですが、スマホアプリを作ったことがないストリーミング再生部分の実装が面倒な気がしたので、姿勢検出&パン・チルト制御には AtomS3 を使用することにしました。またスマホと AtomS3 の姿勢の連動には USB Type-C male to Type-C male アダプタを使用しました。
ONVIF
ONVIF で PTZ (PanTiltZoom) を操作するには SOAP (HTTP の POST を使って XML 形式のコマンド・レスポンスをやり取り) を実装すればよいので ONVIF の仕様書を参考に必要なコマンドを探しました。詳細はサンプルコード。
姿勢検出
AtomS3 には6軸加速度センサが内蔵されているので、加速度センサの出力を madgwick フィルタに通して姿勢を取得しました。詳細はサンプルコード。
サンプルコード
https://github.com/sokosun/atoms3_tc70_control/
そのほか
どの XML パーサが Arduino に適していて、かつ XML namespace 対応なのかよくわからなかったので、とりあえず XML namespace 非対応のものを使用しました。そんなわけで他のネットワークカメラは ONVIF 対応でもサンプルコードそのままでは制御できないと思います。
0 notes
sokosun · 11 months
Text
TP-Link P105 controlled by AtomS3 Lite
0 notes
sokosun · 11 months
Text
それ AtomS3 Lite でできたよ
概要
AtomS3 Lite のボタンで TP-Link P105 スマートプラグを操作できるようにした顛末
undefined
tumblr
はじめに
スマートホーム関連商品としてスマートボタンというものが製品化されており、それを使えばスマートボタンを押すとスマートプラグを ON/OFF するといったことは可能なのですが、インターネット不通時に使えないとかインターネット経由で処理するので反応が遅いという問題があります。そこで AtomS3 Lite から TP-Link P105 に直接通信することによって問題を解決してみました。
TP-Link P105
数多く製品化されているスマートプラグのなかから、プロトコルが既知で低価格 (1000円程度) かつ入手性が良い TP-Link P105 を選定しました。
プロトコル
P105 のプロトコルはプロプライエタリなのですが数多くの実装が公開されています。いくつかソースコードを確認してみると http 通信で以下のシーケンスで通信すればよいことがわかりました。比較的簡単ですが、やり取りするデータが暗号化されたり base64 符号化されたりハッシュだったりして平文ではないのでハマるとバグを探すのが面倒だったりします。詳細はサンプルコードを参照してください。
P105 Client | handshake | |<----------| ; key |---------->| ; key, sessionID and timeout | | | login | |<----------| ; username(sha1), password and sessionID |---------->| ; token | | | API calls | |<----------| ; token |---------->| | ... |
実装
試しに拾ってきたコードを使って動作させてみると動かない・遅いといった問題があったので、チューニングして動画くらいの反応時間となりました。また(たまに失敗してリトライが走るので)ボタンを押してから処理が終わるまで LED を点灯させています。
サンプルコード
https://github.com/sokosun/atoms3_p105_control/
そのほか
TP-Link のスマートプラグはあるユーザが使用中に別のユーザが使用しようとするとビジーを返す
terminalUUID はなんでも通るっぽいが、同じ terminalUUID で (キー生成から) 繰り返し通信するとエラーが返ってくる
requestTimeMils に常時 0 を設定するとエラーが返ってくることがある (ファームウェアのバージョン依存らしい)
login で間違った username/password を送ってもエラーなしと返答したりする (API call 時にエラーが返ってくる)
参考
https://gitlab.com/0xSamy/TapoPlug-Rest-API
https://github.com/fishbigger/TapoP100
ESP8266 で Tp-Link のスマートプラグ『Tapo P105』を直接操作する https://guminote.sakura.ne.jp/archives/911
TP-LINK TAPO P100/P105をESP32から直接制御する https://lab.sasapea.mydns.jp/2020/11/26/tapo_esp32/
0 notes
sokosun · 1 year
Text
Joker8 ビルドログ
概要
本エントリは自作キーボードキット「Joker8」のオレオレビルドログです。組立手順説明書と比べて以下の点が異なります。
XIAO RP2040 の代わりに XIAO ESP32C3 を使用
USB 接続ではなく WiFi 接続
ファームウェアは自作
組立手順説明書: https://blog.alglab.net/archives/joker8-build-guide/
完成写真
Tumblr media
はじめに
USB/Bluetooth 接続ではなく WiFi 接続して家電を操作できるマクロパッドが欲しいと思ったので作ってみました。booth で自作キーボードキットを探してみると WiFi マクロパッドに使用できそうな Joker8 をみつけたのでこちらをカスタムすることにしました。
補足: 自作キーボード界隈では Pro Micro というマイコンモジュールがよく使用されるのですが、Pro Micro とピン互換で WiFi 対応のモジュールがみあたらないので、Pro Micro 用のキットを WiFi 接続マクロパッドに仕立てるのは面倒です
組み立て
説明書に含まれないカスタム要素は以下の通り
アンテナのコネクタが穴を通らなかったので着せ替えプレートはなし
アンテナは飛び出したまま(将来的には裏面に両面テープで貼り付け?)
キーキャップを塗装
ファームウェア
以下のエントリで確認した機能をガッチャンコして修正しました。なお電池駆動まではやっていません。
ESP32 で HEOS デバイスを叩く
ESP32 で LG のテレビを叩く
リポジトリ: https://github.com/sokosun/joker8_esp32c3_heos_lgtv
機能
オーディオアンプの入力切替&音量調整やディスプレイの入力切替がワンボタンで動作します。具体的には赤外線リモコンを本体に向けて、入力切替ボタンを押して、カーソルキーで希望の入力を選んで、決定ボタンで入力を切り替えて…ということがボタン一発で可能になります。また外部サービスに依存していないので、家庭内 WiFi さえ生きて入ればインターネット不通でも動作します。
具体的な機能は以下の通り
音量20に設定 (Spotify用)
音量25に設定&入力をUSB-DACに変更 (PC用)
音量30に設定&入力を光入力に変更 (ゲーム用)
HDMI入力1 に設定
HDMI入力2 に設定
HDMI入力3 に設定
HDMI入力4 に設定
そのほか
キースイッチ押下時の立下り割込みを設定すると、スイッチを放すときにも割込みがかかる現象が(5個試してうち3個で)発生しました。原因の詳細は確認できていませんがローレベル割込みに変更することで対処しました。なおはんだづけをやり直したり、ESP32C3 の IO MUX のフィルタ機能も試しましたが効果はありませんでした。
標準の RP2040 マイコンは USB 接続のみ対応ですが、ESP32C3 なら USB/Bluetooth/WiFi 対応なので Bluetooth 接続マクロパッドとしても使えるはずです。
0 notes
sokosun · 1 year
Text
ABS キーキャップの塗装
概要
ABS のキーキャップをガンダムマーカーエアブラシで塗装してみた記録
準備
塗装にあたり以下のものを用意しました。ABS はアルコールで割れやすくなるらしいので要プライマー。
Tumblr media Tumblr media
ABS キーキャップ (未塗装)
プライマー
ガンダムマーカーエアブラシシステム
ガンダムマーカー
完成写真
Tumblr media
塗装時の多少のムラはちゃんと引けて写真で見る限りはそれなりに映えるものになりました。顔料の粒子が大きいらしく平滑性はでておらず触るとざらつきを感じます。
メモ
プライマー -> 2時間乾燥 -> 塗装 -> 2時間乾燥 という流れでそれなりに(待ち)時間がかかる
プライマーは透明なのでキーキャップの塗装前の色の個体差が完成後にも残る
可能なら下地塗りを入れたほうが良い
ガンダムマーカーのペン先がすぐ乾くので、キーキャップ1個噴くたびにペン先を押してインクを出す作業が必要
キーキャップ10個以上の塗装なら普通のエアブラシの方が良さそう
ガンダムマーカー塗装は(クリアーを噴いても)剥げやすいらしいのでキーボード用途には向かないかもしれない
1日数回しか叩かないマクロパッド用途なら十分
ガンダムマーカーエアブラシシステムは普通のエアブラシの代用にはならないけど片付けが一瞬なのは本当に楽
0 notes
sokosun · 1 year
Text
それ AtomS3 でできるよ
概要
M5STACK の AtomS3 Lite を試してみた記録
製品詳細: https://docs.m5stack.com/en/core/AtomS3%20Lite
はじめに
ESP32 を試すのに純正の開発基板を購入したのですが、Amazon Dash Button のようにボタンを押したら WiFi にパケットを送る程度の用途であれば M5STACK の ATOMS3 Lite が使いやすそうなので試しに買ってみました。特徴は以下の通り。
小型
軽量
純正基板より安価
押しボタン・RGBLED内蔵
ブレッドボード・ユニバーサル基板に取り付け可能
Tumblr media
スマホに乗せてもこのサイズ。まさにバッテリーレスな Dash Button です。
使ってみる
ESP32 で HEOS デバイスを叩く
で作成したコードを移植・修正・機能追加して動作を確認しました。どちらも ESP32-S3 なので何も問題なくスルっと動きました。
サンプルコード
貼り付けるには大きくなってしまったので以下にプッシュしました。
https://github.com/sokosun/atoms3_heos_control
0 notes
sokosun · 1 year
Text
JTC を持ち上げてみる
概要
新卒から15年勤めた JTC を辞めたので退職ポエムを書いてみました。よくJTC はクソという文脈で語られることを見かけるので逆に良かったところを挙げています。そもそも悪い会社なら15年も勤めないですし、実際そんなに悪くはなかったはず。
自己紹介
業種は製造業
修士卒(情報科学)
業務は主に組み込みエンジニア・ソフトウェアエンジニア
15年のうち5年はアメリカ赴任
良かったところ
一言でまとめれば超ホワイト。働いている人はいい人が多いし、コミュニケーションも感情ではなく論理で行われる。社内アンケートを取ったら「経営層がクソ」って意見が結構出てくるくらい心理的安全性(報復されない安心感)もる。
肌感覚では男性の9割が30歳までに結婚しているし、バリキャリ女性との結婚も多い。忙しい部門でもあまり気兼ねなく定時上がりできるし、男性が育休取るのも普通。転勤は希望しなければほぼないし、希望すれば海外赴任も含めて(希望者が少ないので)通りやすい。営業拠点の片隅に技術者がいるみたいな融通も利く。
それからエンジニアとしてしっかり経験を積むことも、のらりくらり給料泥棒としてやっていくこともできる。20代で経験を積んで30代で転職するというというのが黄金ルート。中堅がどんどん抜けていくので頭数は余裕があるのに技術者は不足しているという環境。のらりくらりしたい人がブルシットジョブを担当して、やる気のある若手が経験を積める仕事を担当するという好循環で回っている。また優秀な人から辞めてしまうので普通の人でもそれなりに評価される。
技術面では誰が言ったかではなく何を言ったかで判断するみたいな公平性がある。「若手は発言できない雰囲気」みたいなものもほとんど経験したことはない。中間管理職が忙しすぎるせいか、結果を出し続ける人の裁量はどんどん大きくなるので、能力のある人がマイクロマネジメントでストレスを感じるようなこともない。主任がヒラの仕事をして代わりにヒラが主任の仕事をするみたいな運用もあるし、希望次第でかなり多くのことができる。そのせいで私は4回も転勤したんだけど。
ソフトウェアエンジニアとしては大学で計算機科学を専攻していた人が少ないので無双できた。マサカリを投げるという表現があるけれども、そもそもマサカリを持ち上げられる人が100人中5人もいない印象。100人の開発部門で5人のうち1人が辞めたら部門全体のアウトプットが20%減るみたいな感じ。そんな環境だから未経験からソフトウェアエンジニアでも大丈夫だし、アウトプットゼロでも詰められることはないし、5人と95人で賃金も同じ。むしろ仕事が早くて定時上がりの5人より残業多い95人の方が賃金多いまである。リスキリングとかいって非ソフトウェア部門からソフトウェアエンジニアになるための社内プログラミング講習もある。めざせ未経験からソフトウェアエンジニアになって残業代で年収イッセンマン。
いちおう5人の方にも海外赴任という年収を上げるパスがある。アメリカでソフトウェアエンジニアやって年収2~3倍みたいな感じ。5年くらい海外赴任してレバナスに突っ込めば下手な転職よりはるかに割がいい・・・かもしれない。少なくともアメリカでソフトウェアエンジニアって経歴はエンジニアの生存戦略として悪くない。グリーンカード取って現地転職の選択肢もあるし、帰国して新卒カードより強い転職カードを切ることもできるし。子育て中の共働き家庭だと普通に国内で転職先を探す方が面倒ごとが少なかったりするんだけど。
さいごに
本日は4月1日ですよ
0 notes
sokosun · 1 year
Text
ラズパイでパケットキャプチャ
概要
ESP32 の動作確認のためにパケットキャプチャできる環境をラズパイで構築したのでその覚書
目的
ESP32 が期待通りにパケットを出力しているか、および家電・スマホアプリの間でどのような通信が行われているのかの確認
方針
ルーターでパケットキャプチャできれば簡単なのですが、普通の家庭用ルーターにそんな機能は無いので、 代わりにラズパイをWifiブリッジとして動作させてパケットキャプチャすることにしました。 有線接続機器間のパケットキャプチャは必要ないので非対応です。(有線LANアダプタ使えばできますが)
やったこと
SSH/VNC 有効化
USB-Ethernet アダプタ接続 (リモート接続用)
Ethernet 2本ともルーターに接続
eth1 (USB-Ethernet) を固定IP化
wireshark をインストール
hostapd をインストール
公式ドキュメント Setting up a Bridged Wireless Access Point を参考にブリッジ設定
そのほか
固定IPにするには /etc/dhcpcd.conf を修正
/etc/network/interfaces を修正しろとかいう情報は古い
ディスプレイ無しで運用するなら /boot/config.txt にある #hdmi_force_hotplug=1 をコメントアウトしないとVNC接続できても画面が映らない
UltraVNC Viewer では認証不能で VNC 接続できなかった、RealVNC Viewer なら接続できた
hostapd をブリッジが準備できる前に実行すると失敗する
ブリッジを作るのに bridge-utils をインストールしろとかいう情報は古い
参考
Setting up a Bridged Wireless Access Point https://www.raspberrypi.com/documentation/computers/configuration.html#setting-up-a-bridged-wireless-access-point
0 notes
sokosun · 1 year
Text
サンワサプライ 700-AC036W
概要
旅行用にUSB充電器 (サンワサプライ 700-AC036W) を買った覚書
Tumblr media
写真は比較用のスマホに乗せています
充電器選定
最近充電器を持ち歩くことが増えたので自宅用と旅行用を分けるために以下の条件で探しました。
USB 3口以上
プラグが折りたためる
USB-PD で 30W 以上出せる
安宿のコンセントでも干渉しにくい
はじめは Anker の適当なものを買おうかと思って Anker 735 Charger などを検討してみたものの高過ぎるように感じたので、ちょうどセールだったサンワサプライ 700-AC036W にしました。スマホの幅に収まるサイズってのは実にコンパクトです。
比較表
735 Charger 700-AC036W 最大出力 65W 65W セール価格 \6500 \3600 保証 30か月 6か月 重量 132g 105g サイズ 66x38x29 65x37x31
Anker 735 は放熱シリコン充填で重いかわりに放熱しっかり&保証期間が長いのかも
700-AC036W の USB-PD 供給電圧は 5/9/12/15/20V
旧仕様なら 5/9/12/20V、現行仕様なら 5/9/15/20V なのでノーブランド品にありがちな両対応なのかも
3ポート同時充電&大容量機器複数を常用するなら Anker 735 の方が良いかも
700-AC036W は3ポート同時充電時、1ポートのみ急速充電となる
大容量機器複数なら Anker 737 (120Wタイプ) にすべきかも
0 notes
sokosun · 1 year
Text
ESP32 でヤマハのAVアンプを叩く
概要
ヤマハのAVアンプはスマホアプリなどネットワーク経由で操作ができるので、実際に ESP32 を使って wifi 経由での操作を試してみました。
通信プロトコル
公式に仕様書が配布されているところは見つけられなかったのですが "Yamaha Extended Control API Specification" と検索することで仕様書がみつかりました。HTTP で接続して GET (一部コマンドは POST) で操作できるようです。なお未確認ですが現行製品ではプロトコルが違うかもしれません。
用意したもの
Tumblr media
ESP32 開発基板 + 配線 (前回と同じもの)
Yamaha Extended Control API Specification (Basic) (仕様書)
Arduino IDE + esp32
サンプルコード
ボタンを押すたびにミュート on/off を切り替えるサンプル。
YamahaAVR, SSID, PASSWORD は要書き換え
#include <Arduino.h> #include <WiFi.h> #include <HTTPClient.h> const char SSID[] = "ssid"; const char PASSWORD[] = "12345678"; const IPAddress YamahaAVR(192,168,0,20); const String COMMAND_setMute_true = String("http://") + YamahaAVR.toString() + String("/YamahaExtendedControl/v1/main/setMute?enable=true"); const String COMMAND_setMute_false = String("http://") + YamahaAVR.toString() + String("/YamahaExtendedControl/v1/main/setMute?enable=false"); volatile bool g_mute = false; volatile bool g_irq0 = false; void ISR0(){ g_irq0 = true; } void setup() { Serial.begin(115200); pinMode(14, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(14), ISR0, FALLING); WiFi.begin(SSID, PASSWORD); while(WiFi.status() != WL_CONNECTED) { delay(500); } Serial.printf("WiFi connected\r\n"); } void loop() { if(g_irq0){ HTTPClient http; http.begin(g_mute ? COMMAND_setMute_false : COMMAND_setMute_true); int code = http.GET(); String response = http.getString(); Serial.printf("setMute (%d)\r\n", code); Serial.printf("%s\r\n", response.c_str()); g_mute = !g_mute; g_irq0 = false; } }
0 notes
sokosun · 1 year
Text
ESP32 で LG のテレビを叩く
概要
LG のテレビはスマホアプリなどネットワーク経由で操作ができるので、実際に ESP32 を使って wifi 経由での操作を試してみました。
通信プロトコル
詳細は公開されていないのですが WebSocket でポート 3000 に JSON フォーマットでメッセージを送ればいいようです。lgtv2 のソースコードから読み取り&実際に通信して挙動を確認しました。コマンド一覧はあるのにコマンド毎の指定値は不明なので検索するなりしてなんとか。
また lgtv2 の README には You need to allow "LG Connect Apps" on your TV とありますが最近のモデルだと接続するときにテレビにポップアップが出るのでそのときに OK すればよさそうです。
用意したもの
Tumblr media
ESP32 の開発基板 + 配線 (前回と同じ)
Arduino IDE + esp32 + WebSockets
lgtv2 のソースコード (仕様)
サンプルコード
Pin14 につながったボタンを押すと HDMI 1 に入力を切り替えるサンプル。1回しか実行しないので何度も実行したい場合は要リセット。クライアントIDを保持しないので毎回リモコンで OK する必要があります。クライアントIDの扱いに関しては lgtv2 のソースコードを確認してください。
esp32, lgtv, subnet, ssid, password, register_msg は要書き換え
#include <Arduino.h> #include <WiFi.h> #include <WebSocketsClient.h> String switch_msg(R"({"id":"abcdef123457","type":"request","uri":"ssap://tv/switchInput","payload":{"inputId":"HDMI_1"}})"); String register_msg(R"({"id":"abcdef123456","type":"register","payload": /// ここに lgtv2/pairing.json ��中身を貼り付け /// })"); const IPAddress esp32(192,168,0,4); const IPAddress lgtv(192,168,0,5); const IPAddress subnet(255,255,255,0); const char ssid[] = "SSID"; const char password[] = "PASSWORD"; WebSocketsClient webSocket; enum State { STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_REGISTERED, STATE_COMMAND, STATE_DISCONNECTING, STATE_HALT }; State g_state = STATE_DISCONNECTED; void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) { switch(type) { case WStype_CONNECTED: Serial.printf("Connected\r\n"); g_state = STATE_CONNECTED; webSocket.sendTXT(register_msg); break; case WStype_TEXT: Serial.printf("Text: %s\r\n", payload); if(g_state == STATE_CONNECTED){ const char reg_response[] = R"({"type":"registered",)"; if(strncmp((char *)payload, reg_response, 20) == 0){ g_state = STATE_COMMAND; webSocket.sendTXT(switch_msg); } }else if(g_state == STATE_COMMAND){ g_state = STATE_DISCONNECTING; webSocket.disconnect(); } break; case WStype_DISCONNECTED: Serial.printf("Disconnected\r\n"); g_state = STATE_HALT; break; default: break; } } volatile bool g_irq0 = false; void ISR0(){ g_irq0 = true; } void setup() { Serial.begin(115200); register_msg.replace("\r", ""); register_msg.replace("\n", ""); pinMode(14, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(14), ISR0, FALLING); WiFi.config(esp32, esp32, subnet); WiFi.begin(ssid, password); while(WiFi.status() != WL_CONNECTED) { delay(500); } } void loop() { if(g_state == STATE_DISCONNECTED){ if(g_irq0){ g_state = STATE_CONNECTING; webSocket.begin(lgtv, 3000); webSocket.onEvent(webSocketEvent); webSocket.setReconnectInterval(5000); } }else if(g_state != STATE_HALT){ webSocket.loop(); } }
参考
lgtv2 https://github.com/hobbyquaker/lgtv2
GoogleHomeからテレビ(LG製WebOS)をコントロールしてみるをESP32でやってみた https://qiita.com/ainehanta/items/ead336fcd8ba49b77b56
そのほか
WebSocketsClient のライブラリはエラーを吐けない (返り値 void) ので、うまく動作しないときはパケットキャプチャして WebSocket のパケットが飛んでいるか確認したほうが良さそうです。パケットが飛んでないことがよくありました。
0 notes
sokosun · 1 year
Text
ESP32 で HEOS デバイスを叩く
概要
最近のデノンやマランツのアンプはスマホアプリなどネットワーク経由で操作ができるので、実際に ESP32 を使って wifi 経由での操作を試してみました。
通信プロトコル
"HEOS Protocol" と検索すればデノン、マランツ、B&W などのダウンロードページがみつかりました。telnet でポート1255に接続してコマンドを送ると JSON フォーマットで応答が返ってくるようです。
用意するもの
ESP32 の開発基板
ブレッドボード・操作ボタン・ジャンパ
HEOS CLI Protocol Specification (仕様書)
Arduino IDE + esp32 + ArduinoJson
完成写真
Tumblr media
サンプルコード
Pin14 に接続したボタンを押すと Mute on/off 切り替えするサンプル
ssid, password, heosdevice は要書き換え
HEOS デバイスが固定IPであることを前提としているので動的IPの場合は追加のコードが必要
#include <WiFi.h> #include <ArduinoJson.h> WiFiClient self; const char* ssid = "SSID"; const char* password = "PASSWORD"; const IPAddress heosdevice(192,168,1,40); const int heosport = 1255; volatile bool g_irq0 = false; char g_buf[1024]; long g_pid = 0; // 0 is handled as invalid void setup() { Serial.begin(115200); WiFi.begin(ssid, password); Serial.print("Connecting to "); Serial.println(ssid); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.print("\r\nWiFi connected\r\n"); self.connect(heosdevice, heosport); Serial.print("Connecting to HEOS device\r\n"); if(self.connected()){ Serial.print("Connected\r\n"); self.print("heos://player/get_players\r\n"); int len = waitJsonResponse(); if(len>0){ g_pid = getPlayerId(g_buf); } Serial.print("Command: Get Players\r\n"); Serial.print("Response: "); Serial.write(g_buf, len); } pinMode(14, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(14), setIRQ0, FALLING); } // @return length of a json packet. 0 if failed. size_t waitJsonResponse(){ int nestlevel = -1; size_t readlen = 0; while(1){ if (self.available()) { char c = self.read(); g_buf[readlen++] = c; if(c == '{'){ nestlevel++; }else if(c == '}'){ nestlevel--; if(nestlevel < 0){ break; } } if(nestlevel < 0){ // error (Invalid first character) return 0; } if(readlen >= 1024){ return 0; // error (Buffer limit) } } } return readlen; } long getPlayerId(char* buf){ StaticJsonDocument<256> doc; DeserializationError error = deserializeJson(doc, buf); if (error) { Serial.print("deserializeJson() failed: "); Serial.println(error.c_str()); return 0; } JsonObject payload_0 = doc["payload"][0]; long payload_0_pid = payload_0["pid"]; return payload_0_pid; } void loop() { if (self.available()) { char c = self.read(); Serial.print(c); } if(g_irq0){ Serial.print("toggleMute\r\n"); toggleMute(); g_irq0 = false; } } void setIRQ0(){ g_irq0 = true; } void toggleMute(){ if(!self.connected()){ return; } if(g_pid == 0){ return; } auto command = String("heos://player/toggle_mute?pid=") + String(g_pid) + String("\r\n"); auto len = command.length(); if(len>255){ return; } char buf[256]; command.toCharArray(buf, len+1); self.write(buf, len); return; }
0 notes
sokosun · 1 year
Text
IO-DATA UD-CO2S
概要
CO2センサー(I-O DATA UD-CO2S) を購入して非公式な動作確認をした記録
Tumblr media
背景
まともな CO2 センサーは当然のように1万円くらいするのですが、ここ最近になって I-O DATA UD-CO2S が \3480 まで値下がりしてきたので試しに1台購入してみました。そして仕様を確認したところ (公式には Windows 用のアプリケーションしか配布されていないのですが) どうも Virtual COM ポート経由でデータを読み出せるっぽいのでその動作も確認してみました。
コマンド解析
シリアル通信の API は問い合わせると回答してもらえるようなのですが、問い合わせるのも面倒だし、10分もあれば確認できるだろうと思ったのでチャチャっと Vitrual COM ポートを流れるデータを確認したところ以下の通りでした。なお、校正コマンドは面倒だったので確認していません。
STA: 0x53 0x54 0x41 0x0d 0x0a
STP: 0x53 0x54 0x50 0x0d 0x0a
VER: 0x56 0x45 0x52 0x3f 0x0d 0x0a
まんま ASCII ですね (例えば STA は 'S' 'T' 'A' CR LF)
通信確認
みんな大好き TeraTerm で Virtual COM ポートを開いてコマンドを投げると、めでたく結果が文字で返ってきました。
Tumblr media
なお、以下のように send コマンド1行だけの TeraTerm 用マクロファイルを準備しておくと簡単です。
例) STA
send $53 $54 $41 $0d $0a
補足
制御IC は PIC (24FJ64)
7 notes · View notes