2024年11月16日土曜日

Tuya スマートプラグを PowerShell で制御する

前回ブラウザからスマートプラグを制御したとき,URL の情報が見えていたので,後は HTTP リクエストを送れさえすれば制御は余裕と思っていたらそうではなかった.
リクエスト送信前に署名鍵を Tuya から取得し,その鍵で送信するリクエストデータの署名を作成し送信しないとだめっぽい.

で探してみたら,すでに Unix shell から制御するコードはあったので,ありがたくこれを PowerShell に変換してみたのが一番下のコード.

ハマったポイントは,

  • UNIX Time を秒数で得る命令 (Get-Date -UFormat %s) はタイムゾーン分の誤差が発生する (PowerShell のバグっぽい) ので,タイムゾーンオフセット分増減が必要.
  • 署名を作るために必要な Client Secret (Tuya developer サイトから取得する) は 16進32桁なので,128bit の数値だと思ったら,これはそのまま文字列データとして 256bit の数値として扱わないと,Tuya 側で有効な署名と認められなかった

でやった結果.Powershell で 10秒毎に消費電力を取得してみた.なかなか安価で消費電力のログ取れる環境は無いので,これはかなり満足度が高いヽ(´ー`)ノ

以下 PowerShell コード.

2024年11月10日日曜日

Tuya スマートプラグを PC から制御する

大昔にスマートプラグ (ネットワーク経由で On/Off できるコンセント) を買ったけど,独自の Android アプリでしか On/Off できなかったので,あまり使い道がなく放置していた.
で,最近これは Tuya という IoT プラットフォームに準拠した製品であることがわかったので,PC から制御してみた.
ところが Tuya のチュートリアル通りにやっても画面が説明と異なる等多々あり進まなかったので,自分でうまく行った手順を以下に記載しておく.

【開発者アカウント作成・デバイスのリンク】

●まずはスマートプラグと,Android の Smart Life アプリとの連携を済ませておく.

Tuya developer でアカウント作成

●Cloud → Create Cloud Project をクリック

●Create Cloud Project 画面で
  • Project Name: てきとう
  • Industry: Smart Home
  • Development: Smart Home
  • Data Center: データが保存されるサーバの場所? よくわからないがとりあえず Western America Datacenter
にして Create クリック

●Configuration Wizard はそのままで Authorize をクリック

●Devices → Link App Accout → Add App Account をクリックすると,QR コードが表示される

●Android の Smart Life アプリ右上の「+」 → QR コードをスキャン,をタップ後,PC の QR コードを読み込む

●Android アプリの「ログインを確認」をタップ

●以下のような画面が出てくるので,そのまま OK.これで Tuya developer アカウントとデバイスがリンクできた.

【デバイスを PC から制御する】

●どんな操作ができるか (コマンドがあるか) 調べてみる.
ここで表示されている Device ID が後々必要なので控えておき,Devices → All Devices → Debug Device をクリック

●Device Debugging をクリック.
Standard Instruction Set を見ると,使用できる設定系のコマンドがわかる.うちのだと,switch_1 / switch_2 で 2個あるコンセントの On/Off, countdown_n は秒数を設定するとその時間経過後に On/Off を反転する.

Standard Status Set を見ると,状態取得系のプロパティがわかる.うちのだとコンセントの On/Off 状態や,現在の電力が取得できる.

●Cloud → API Explorer をクリック

●Device Control の左の▶をクリック,Send Commands をクリック.

  • device_id: 先程調べた Device ID
  • code: switch_1 など
  • value: true, false など
で Submit Request をクリックすると,スマートプラグが On/Off される.
ここで,Request URL / Response をみると,どういうリクエストを送ればいいかが一発でわかるので,後は好きな言語で好きなように制御できる.もう少し手順が必要

●Get the status of a single device を実行すると,上の Standard Status Set で調べたプロパティが取得できる.

【最後に】

このスマートプラグ,電力計が付いていたので買ったものだが,電力見るのも専用アプリだけでログも取れないので放置していたが,これからは PC でログ取りできるので,かなり使えるアイテムになったヽ(´ー`)ノ

2024年8月31日土曜日

人生最大のデータ消失危機

 約 3年前に買った 6TB HDD の WD60EZAZ に突然アクセスできなくなった.症状としては

  • HDD を PC に接続すると,Win 起動中に HDD アクセスに行った時点で進まなくなる
    • OS 自体は別 SSD に入っており,OS が読めないわけでない
    • つまり,HDD を繋いでいるだけで OS が起動しない
  • (あまりおすすめしないけど) 経験的に,OS 起動後に SATA ケーブルを繋いでも HDD は認識するので,それをやってみたら,やはり HDD にアクセスした時点で何も進まなくなる
    • HDD アクセスしない他のアプリは動作可能

つまり,Win 用 HDD 修復ツールは一切使用できないことになる.

ここで GParted Live on USB が非常に役に立った.GParted は Linux 用パーティション操作ソフトだが,Linux が USB から起動できて,さらに testdisk (パーティション修復), photorec (削除ファイル復活) 等の HDD リカバリに有用なツールも使える.また Linux では HDD アクセスエラーになったら適当なところで諦めてくれるので,OS ごと固まることがない.

で色々調べた結果,プライマリパーティションテーブルは物理的に壊れているようだが,バックアップのパーティションテーブルは無事なようなので,ダメ元で Linux で NTFS パーティションをマウントしてみたら普通にマウントできたヽ(´ー`)ノ
今回の学びとしては,Windows でだめでも,Linux ならまだワンチャンアクセスできるということを得た.


最後に,HDD を廃棄する際の伝統儀式を実施.可能な限りバラバラにし,ネオジム磁石を取り出して完了w

自分は,Windows 上で Disk エラーを検出すると通知を出すようにしていて,前回の HDD 異常時はそれですぐに気付けて大事になることはなかったけど,今回はなんの前触れもなく突然壊れて困った.3TB / 4TB / 6TB と立て続けで HDD が壊れたので (それ以前は HDD 異常の経験無し),大容量になるにつれて HDD が脆くなってきたのかなぁ.

2024年4月28日日曜日

懸念していたことが現実になった

冠山峠道路のトンネルが開通したとのことで,林道の方に登るついでにトンネル見に行くか,と徳山ダムに向かって出発.で,現地に着いたら,

おいおいおいー,林道封鎖されとるやんけ(;´д⊂)

トンネルが開通したら林道の方は廃道にされるかも,と懸念していたが,それが現実のものになってしまった.一時的なものかもしれないけど,積極的に林道を修復する理由もなくなったので,走れるチャンスは確実に減ったはず.封鎖を確認したのは岐阜側で,もしかしたら福井側から登れるのかもしれんけど,景色がいいのは岐阜側の道なので,福井側から登っても意味がない.自分の行動範囲ではピカイチで景色が良かっただけに,ここが走れなくなるのは非常に悲しいなぁ.
あと,冠山峠道路のトンネル開通前はここを走りに来るのはドライブ目的の車しかなかったので交通量は少なかったが,今回は結構交通量多かった気がする.

つうわけで本来は通る予定がなかった冠山峠道路のトンネルを通って,能楽の里牧場なる場所に向かった.

実はあんまり期待してなかったんだけど,山頂は,木が一本もない素晴らしい眺め.しかも,360度全周にわたって視界を遮るものが無い絶景.
冠山峠道の林道が走れなくなった代わりに,いい場所見つけたヽ(´ー`)ノ

2024年3月30日土曜日

天神風の道公園で春の訪れを感じながらバイクツーリング


最近,技術的な話題はともかく,日記的な話題の blog を上げるのがだるくなってきて,めっきり更新頻度が減っている当 blog.
ここで,AI に blog 記事書かせてみたらいいんじゃね? と思ってやってみた.

入力した文章はこれ↓
====================================
次の文章を元にblogの記事を書いてください.

冬は寒かったので全然バイクに乗っていない.
今日は暖かかったので,本年初のバイクのり.
多くのライダーが集まる湖畔の里つきがせはスルーして天神風の道公園に行った.
ここは見晴らしが良く人も少ないのでお気に入り.
桜はあまり咲いてなかった.梅らしきものは咲きかけ.
====================================

出力された記事
===== ここから =================================

天神風の道公園で春の訪れを感じながらバイクツーリング

冬の間は寒くてバイクに乗る機会が減っていましたが、今日は暖かかったので今年初のバイクツーリングに行ってきました。多くのライダーが集まる湖畔の里つきがせはスルーして、見晴らしが良く人も少ない天神風の道公園を目指しました。

公園に到着すると、眼下に広がる景色に感動しました。遠くの山々まで見渡せる絶景は、まさに春の訪れを感じさせてくれます。桜はまだあまり咲いていませんでしたが、梅の花が咲き始めており、春の訪れを告げていました。

公園内を散策していると、気持ち良い風を受けてリフレッシュできました。人も少なく、静かな環境で自然を満喫することができました。

今年のツーリングシーズンは、天神風の道公園からスタートすることができて、とても良い思い出になりました。これから暖かくなるにつれて、色々な場所に出かけたいと思います。

公園情報

  • 天神風の道公園
  • 奈良県奈良市月ヶ瀬梅林
  • 駐車場あり
  • 無料

おすすめポイント

  • 見晴らしが良く、遠くの山々まで見渡せる
  • 人が少なく、静かな環境
  • 春は桜や梅の花が楽しめる

まとめ

天神風の道公園は、見晴らしが良く、静かな環境で自然を満喫できる公園です。春は桜や梅の花が楽しめるので、ツーリングの目的地におすすめです。

===== ここまで =================================

すげえよwww 「春の訪れ」とか自分では絶対書かないしそんな文才無いwww
しかも自己満足な記事ではではなく,公園情報や見どころまでまとめられて,ちゃんと他の人にとって役に立つ記事になっている.しょうもない記事を書くライターは廃業だなこれ.
これ見たら,ソースコード書くだけの人もそのうち淘汰されるだろうなぁ,というのも実感が湧いてくるね.

2024年3月24日日曜日

C++ で構造化アセンブリプログラミング

動機

原始的なアセンブラしか無い原始的な CPU のプログラミングをすることになった.
でアセンブリプログラミングの一番の萎えポイントとして,例えば C 言語だと
if(a == b){
  c = d;
}else{
  e = f;
}
みたいに書けるところが,構造化記述できないアセンブラだと
  cmp a, b
  jnz label0
  mov c, d
  jmp label1
label0:
  mov e, f
label1:
とラベルやら分岐命令やら,自分で生成しないといけないのでめんどくさいし,if がネストすると可読性も悪い.真面目にやるなら bison/flex とかでまともな構造化アセンブリ言語を設計するところだけど,そこまでやるのはなぁ... と思ったところで,C++ のクラス / 演算子オーバーロードをうまいこと使えば,構造化アセンブリプログラミングもどきが出来るのでは? と思った.
例えば,C++ で "r0 = r1;" と書いてコンパイル・実行すれば,"mov r0, r1" というテキストが得られる,みたいなイメージ.

まずは代入演算

//////////////////////////////////////////////////////////////////////////////
// Register

class RegisterObject {
public:
  RegisterObject(const char* szName) : m_szName(szName){}
  const char *Name(void) const {return m_szName;}
  
private:
  const char* m_szName;
};

class GpReg : public RegisterObject {
public:
  GpReg(const char* szName) : RegisterObject(szName){}
  
  GpReg& operator=(const GpReg& src){
    printf("\tmov\t%s, %s\n", Name(), src.Name());
    return *this;
  }
};

//////////////////////////////////////////////////////////////////////////////
// Register インスタンス

GpReg r0("r0");
GpReg r1("r1");
GpReg r2("r2");
GpReg r3("r3");

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  r0 = r1 = r2;
  return 0;
}
GpReg class は汎用レジスタをイメージしていて,特殊なレジスタがあれば RegisterObject か GpReg を継承する感じ.C++ ソースコード上の変数名 (r0 とか) は実行時には失われてしまうので,m_szName に変数名をセットしておく.
代入演算のキモは言うまでもなく "operator=" で,= が呼ばれたら mov 命令のテキストを出力する.
で実行結果:
        mov     r1, r2
        mov     r0, r1
おお,いい感じ.アセンブラだと r0 = r2 が直接代入できないので一旦 r1 を経由する,みたいなケースが多々あるが,それが 1行で書けるのはありがたい.

比較演算

次に,if-else-endif の構造化をやる前に比較演算子を定義する.
対象 CPU は,== なら cmpeq みたいに比較演算子毎に比較命令があり,その結果をフラグレジスタ f0 にセットする.条件分岐命令は f0 の値をみて分岐するかどうか決める.
class FlagReg : public RegisterObject {
public:
  FlagReg(const char* szName) : RegisterObject(szName){}
};

//////////////////////////////////////////////////////////////////////////////
// Register インスタンス

FlagReg f0("f0");

//////////////////////////////////////////////////////////////////////////////
// global な operator

FlagReg& operator==(const GpReg& a, const GpReg& b){
  printf("\tcmpeq\t%s, %s, f0\n", a.Name(), b.Name());
  return f0;
}

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  r0 == r1;
  return 0;
}
RegisterObject を継承して FlagReg を定義する. operater== で,== が呼ばれたら cmpeq 命令を出力して,== の返り値として f0 を返す.
で実行結果:
        cmpeq   r0, r1, f0
これはなんの問題もない.

if-else-endif

そしてこの取り組みの一番の目的である,if-else-endif の構造化をやってみる.
//////////////////////////////////////////////////////////////////////////////
// 構造化構文

int g_LabelCnt = 0;
std::vector<int> g_Label;

void _if(FlagReg& f){
  printf("\tjnset\t%s, _L%d\n", f.Name(), g_LabelCnt);
  g_Label.push_back(g_LabelCnt);
  ++g_LabelCnt;
}

void _else(void){
  printf("\tjmp\t_L%d\n", g_LabelCnt);
  printf("_L%d:\n", g_Label[g_Label.size() - 1]);
  
  g_Label.pop_back();
  g_Label.push_back(g_LabelCnt);
  ++g_LabelCnt;
}

void _endif(void){
  printf("_L%d:\n", g_Label[g_Label.size() - 1]);
  g_Label.pop_back();
}

//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  _if(r0 == r1);
    r0 = r2;
  _else();
    r1 = r3;
  _endif();
  return 0;
}
_if ではフラグレジスタを受取り,必要な分岐命令を生成する.また if-else-endif はネストするので,分岐先ラベルの情報はスタックに push / pop する必要がある.
で実行結果:
        cmpeq   r0, r1, f0
        jnset   f0, _L0
        mov     r0, r2
        jmp     _L1
_L0:
        mov     r1, r3
_L1:
おおぉ,これこれ! これがやりたかったんだよ.この時点でこのやり方はかなりうまくいく感触を得ていたが,念の為 if がネストするケースをテストしてみたら,
コード:
//////////////////////////////////////////////////////////////////////////////
// アセンブリプログラム

int main(int argc, char **argv){
  _if(r0 == r1);
    _if(r1 == r2);
      r2 = r0;
    _else();
      r3 = r1;
    _endif();
  _else();
    r1 = r3;
  _endif();
  return 0;
}
実行結果:
        cmpeq   r0, r1, f0
        jnset   f0, _L0
        cmpeq   r1, r2, f0
        jnset   f0, _L1
        mov     r2, r0
        jmp     _L2 ←※ここ
_L1:
        mov     r3, r1
_L2:
        jmp     _L3
_L0:
        mov     r1, r3
_L3:
んー,間違いではないんだけど,jmp _L2 の飛び先は jmp _L3 しか無いので,最適化の観点では「ここ」で jmp _L3 にすべき.
この最適化をやるためには,直接アセンブリテキストを出力するのではなく,一旦中間言語とかでメモリ上に溜めておき,最後に最適化フェーズを流す,等しないといけないということがわかった.
それを解決して,あとはメモリアクセスとかラベルへのサブルーチンコールとかを実装すれば,普通に使えそう.

2024年2月12日月曜日

DualShock3 アナログ修理

DualShock3 (PS3 コントローラ,以下 DS3) のアナログ入力が変 (入力してなくても,入力がプルプルぶれる) になってきたので,ジョイスティックセンサを交換することにした.
事前情報ではジョイスティックセンサは基板にハンダ付けなので,めんどくせぇと思って分解したら,


フィルム基板をゴムでジョイスティックセンサの端子に押し付けてあって,端子部分のハンダ付けは無し.固定はセンサの一部を爪のように折り曲げて固定.これは修理容易だしこの方式が流行って欲しいと思ったが DS4 では基板ハンダ付けにのようなので,残念ながら流行らなかったらしい.
ちなみに DS3 でも基板ハンダ付けバージョンもあるらしい.自分の DS3 の型番は CECHZC2J-A2.

で,交換自体はサクッと終わって,試しに使用してみたらほぼ問題なく使えるものの,センサの入力特性に違和感が.具体的には,標準のセンサに比べて,スティックの倒し量が半分くらいで入力 100% になってしまって,要は微妙な入力が非常にやりにくくなった.

これは,センサに使われている可変ボリューム? ポテンショメーター? の特性によると思うけど,買い直すにしても販売ページにそんな事書いてないし,標準部品の特性に近いセンサの選定は難しそう.

で我慢してこのまま使い続けるかしばらく悩んだが,ダメ元で元のおかしくなったセンサの可変ボリュームを分解清掃してみることにした.更に接点が接する部分に注油して,組み直して動かしてみたところ…

ビンゴヽ(´ー`)ノ 無事無入力時のブレも治った.
結局アリエクのジョイスティックセンサいらんかった.買ったのはこれで,少なくともこれを買うのはおすすめしない.

2024年2月10日土曜日

6年越しの夢が叶う

遡ること 6年前,Ace Combat 7 (以下AC7) が PSVR 対応するということで,「コックピットに乗って空中戦,の疑似体験」ができると思って,PSVR を買った.感想としては思ったとおり「乗り物に乗ってる感」がすごくて,それまでのゲーム体験とは一線を画すものだった.
ただし,ゲーム本編は VR 非対応で,おまけみたいな VR 専用ステージ 3面が遊べるだけ,という大変残念な仕様.本編が VR 対応してれば神ゲーだったのに.しかも PSVR 自体が失敗気味で,その後遊びたいと思えるゲームが全く発売されず,大爆死(;´д⊂)
# 今から思えば,PS4 では性能が足らなくて普通のクォリティで VR ゲーム作れなかったんじゃないかと思う

そして時は流れて現在,PC 版の AC7 と UEVR というフリーソフトで,強制的に VR 化できるという情報を得たので,PICO4 を \41,640 で get.

6年間これを待ってたんだよ(゜ーÅ)ほろり
実際に遊んだ感じでは PSVR での VR 専用ステージとほぼ変わらず,ゲームとして普通に成立している.PSVR では遊べなかった本編を VR で遊べて,なおかつ PSVR よりも高解像度ということで,非常に満足度が高い.

これは大抵の非 VR ゲームに言えることだけど,特に「乗り物に乗る系」は,画面の描画範囲が現実に比べとても狭い.例えば敵機がジグザグに逃げているのを追っているとき,敵機は画面外で切り返しても自分はそれが見えず,追うのに失敗することが頻繁に起こってストレスが溜まる.
VR だと,首が動く範囲である限り敵機を視線で追い続けることができるので,敵機の切り返しにも対応できてドッグファイトが非常にやりやすい.

あと,車運転するときを思い出してもらえればわかると思うけど,現実世界で左右に曲がりたいとき,視線は真正面を見続けているのではなく,曲がる先を見ている.非 VR だとこれも描画範囲外だが,VR は首をそっち方向に向けて曲がるという自然な動作が可能で,こういうところの「実際に乗っている感」が非常に高い.

ただし,元々 VR ゲームでないもの無理やり VR 化している事から,問題点もいくつかある.
・ターゲットマーカー以外のHUD表示がされないのが最大の問題.
 ・レーダーが表示されない(PAUSEすれば見れる)
 ・残弾が表示されない
 ・機銃レティクルが表示されないので機銃当てるのは至難レベル
 ・機体姿勢・速度・高度が表示されない
・コックピット視点が使えない
 ・首の動きにコックピット描画が張り付いているので,コックピット視点は使えないので,「乗り物に乗ってる感」は大分そがれる.

そこは割り切りが必要だけど,上記を改善する MOD も開発されているっぽいので,今後に期待.


2024年1月21日日曜日

JOG 3KJ エンスト修理

 足車の JOG 3KJ が走行中にエンストするようになった.症状としては
・ガス欠の症状に非常によく似ていて,走行中に突然アクセルを抜いたかのようにエンジン回転が下がり,アクセルを開けるとわずかに回転が上がろうとするが,そのままエンストする.
・停車後しばらくセルを回すと,エンジンがかかり普通に走れる.

先人の症例を調べてみると,考えられる原因としては
(1) 燃料タンクに水が混入した
(2) 燃料系統 (キャブとか) が汚れで詰まっている
(3) 点火系が壊れた

あたり.(3) だとすると再現性が低く,プラグの火花見てもわからんだろうな,と思ったので,まずは (1) から順番に可能性を潰そうと思った.

まずは燃料タンクからガソリンを抜いて,抜いたガソリンを観察してみたが,見た感じ水は入ってなさそう.

次にキャブ掃除すっか,とキャブを外したところ,負圧燃料コックに負圧を伝えるホースが割れていることを発見.この時点で勝利を確信したwww

念のためキャブ・負圧コックを分解してみたけど,特に詰まり等はなかった.

ということで負圧燃料コックのホースを交換して完了.
今回はわかりやすい故障で良かった.

2023年9月14日木曜日

グラボ + GPU 内蔵 CPU で省電力化する

ここ最近はグラボが買い時だそうで,現に Radeon RX6600 XT の最安値が ¥54,800→¥31,800 に値下げしてたのでぽちっとな,してゲーミング PC (光るとは言っていない) 爆誕.多分 PlayStation4.8 くらいの性能はあるはず.

で,Ryzen5 5600G の内蔵 GPU (IGPU) が無駄になったなぁ,と思ったところで,
・グラボと IGPU を同時に有効化できる (IGPU Multi-Monitor)
・IGPU 側の DP 端子 (つまりマザボの DP 端子) から,グラボ側の映像も出力できる.これは,アプリごとにどちらの GPU を使うかを選択可能.

つまり,3D ゲーム以外では IGPU を使うことによって消費電力を下げられるのでは? と思って実験してみた.設定は,
・BIOS で IGPU Multi-Monitor を有効化
・Win11 上で,デフォルトを IGPU にして 3D ゲームだけグラボに設定→参考

この状態と,IGPU を無効化してグラボだけを生かした状態,のそれぞれで,YouTube を再生したときの消費電力をワットチェッカーで観測してみる.その結果は,

●グラボのみ: 70W
●IGPU + グラボ: 51W

グラボにも省電力機能はあるだろうから,あんま変わらんだろうと思っていたが,意外にも大差がついた.当然のことながら 3D ゲームでも性能ペナルティ的なものはなく,IGPU が問題なく活かせるヽ(´ー`)ノ