ノートパソコンの電源アダプタから5Vを取り出す

電子工作をしていると、5V電源をよく使うのですが、これは乾電池2個だと足りなくて昇圧するか電池3個を使う。同時にサーボモータやモニタを繋げるときは9Vが欲しくて、高価な500円の9V乾電池を買ってくるか、電池6個を使って9Vを取り出すか、ということをやっている。

電池だと消耗してしまうので(充電タイプを使うけど、連続運転という訳にはいかない)、5V のほうはスマホの充電器をつかうのはいいとして、9V はなんとかしたいところであった。

ふと、手元にあるあまりのノートパソコンの電源アダプタが使えるのでは?と、探してい見ると 【ACアダプタを減らしたい】デスクLED照明のACアダプタを減らす | Beヨンド なところがある。これはパソコン電源をつかっているけど、ノートPC のアダプタも直流で16V や 19V のものがあるので、適当に降圧してやれば 5V なり 9V なりが取り出せるだろう。

アダプタを加工し、降圧回路で下げる

ノートPC のアダプタは、各社様々でなんで統一しないのだろうか?ってほどたくさんある。勿論、それにはそれなりの理由があるのだが(これは後述する)、電圧も電流も様々である。高最近のノートPCだと、19V あたりが主流かもしれないが、手元にあるパナソニックの16Vの電源アダプタ―を加工する。このアダプタはノートPCを廃棄に出したときに、出し忘れてしまったものである。秋葉原とかで適当なのを中古で買っても同じことができると思う。

image

電源アダプタのコネクタは外形と内径が様々で、これにあったレセプタ(メスのほう)を秋月とかでかってくるのが正統なんだけど、どうせ使えるノートPCも捨ててしまったことなので、コネクタ部分を切ってしまう。コネクタは大抵の場合はセンターがプラスになっているが、逆のこともある。これはアダプタの裏に書いてあるので、それに注意して配線する。

降圧回路って、昇圧と違って比較的安い。Amazon.co.jp: zmart DC1.3-37V 2A 可変 DCDCコンバータ 5個セット LM2596 レギュレータ ステップダウン: おもちゃ 思い立ったが吉日ということで、amazon の御急ぎ便で届けてもらう。aliexpress で買うと100円/個ぐらいなのだが、早くためしたいので。ちなみに、降圧回路のいくつかのレビューを見ると、「壊れる」とか「不良品が」というのが頻発するので、予備を持ったほうが良いらしい。

あと大電流を流したいときは、ヒートシンク付きとかを買わないと熱くなりすぎるのだろうけど、電子工作の場合はせいぜい1,2A程度しか流さないので、これで十分。

可変抵抗をドライバーで反時計回りに回して降圧する。テスターで測って、だいたい9V になるようにしておく。これで、16V から 9V への降圧が完了する。

降圧、昇圧について解説はこっち
DC/DCコンバータ回路設計ガイド(1/10) | 電源ICのトレックス・セミコンダクター(TOREX) https://www.torex.co.jp/technical-support/application-note/design-guide-for-dcdc-converter/whats-dcdc-converters/

パルスでちびちび電流を流してやって、コイルで平滑化というパターンで、ここで時間差が発生するのがミソ。電子回路はやってないけど、電磁誘導とか電磁学を学んでいると解るんだけど、話は別だがオブジェクト指向のメッセージングに関係するときの「時間」絡みもここがポイントになる。設計時にはメッセージングって時間0で伝達するものと考えるけど(特に、MVVM のプロパティとかリアクティブとか)、実際はタイムラグがあるわけで、その時に DB 的なデッドロックとか遅延評価とかが関係してくる。なので、シーケンス図は必至なのだ、という話に繋がる。

16V から 9V と 5V を利用する

せっかくなので、降圧回路を2つかって、モニタ用の9V電源と、Pine64などの基板のための5V を同時に出すようにしてみる。

image

このモニタのバックライトに9Vが必要なのと、Pine64上で Android 7.x を動かすのに 5V2A が必要になる。程よく、戦闘少女R が動いているので大丈夫そうな感じ。

ラズパイ + Android Things を動かしても大丈夫。こっちは、5V 一本でいける。

image

これで、電源アダプタから 9V と 5V が長時間に取り出せるようになったので、電池のように電池切れの心配がなくなる。当然、モバイルにする場合はモバイルバッテリにすればよい。

手元のロボットアームも 9V 電源が必要なので後日試してみることにする。

何故コネクタの形状が異なるのか?

これ、5V と 9V を同時に作ってみて分かったのだけど、電源供給自体は両方とも micro USB なので、間違って 9V のほうを基板に差してしまうと基板が壊れてしまう、というミスが発生する。いくら気を付けても、コネクタの形状が同じだと間違って差してしまうことは避けれられない。

この対策としては、基板のほうに保護回路を入れるのもよいのだが基板のコストが高くなってしまう、ならば、間違えないようにコネクタの形状を変えてしまえばよい、ってのがノートPCアダプタの乱立というところだろうか。実は、同じ会社のものであれば同じ電圧のアダプタは同じ形状をしていたりする。また、ものによっては、IBM の電源アダプタが VAIO で使えたりする(同じ電圧であれば)。完全に互換性があるとはいえないけど、相互に似た電圧/電流であれば、同じ形状を使っていたりする。逆に、16V アダプタと、19.5V アダプタの形状は外径と内径が異なり、間違って刺し込めないようになっている。

と、これが理由だと思うんだけど、実際のところはどうなんでしょう?

おまけ、USB ハブに 5V 供給する

上記では、USB ケーブルの micro USB のコネクタだけを残して、反対部分はコネクタに変えていたのだけど、これを基板の数分作るのは面倒くさい、じゃあ、USB ハブに 5V 流してしまえばいいんじゃないか?と思って作ったのがこれ。

image

USB ハブのオスコネクタのほうを切り取って、ブレッドボードに差し込めるように加工してしまう。プラスマイナスは、あらかじめテスターで調べておく。

で、USB ハブのほうに、通常の USB – micro USB のケーブルを刺し込めば基板(ラズパイや Pine64など)への電力供給が楽になるのでは、ひょっとしたら4つ同時に供給できるかもしれない、と思って造ってみたのだが。

残念ながら、ラズパイ+Android Things の場合、立ち上げりのところで電流が足りなくて落ちてしまう。これはハブの定格を超える電流を流そうとしているからじゃないかなと思う。普通は500mA しか流れないので、ラズパイのように 2A 程度使う場合は無理なのだ。それでも Arduino を連結するときにはまくできるんじゃないかな、と考えたりするのだが。配線の太さが非常に細い(8本ぐらいしかない)ので、あまり大電流を流すと焦げてしまうかもしれない。

そのあたりは注意して。

カテゴリー: 組み込みボード | ノートパソコンの電源アダプタから5Vを取り出す はコメントを受け付けていません

2年目のプログラミング教室

上板橋あいキッズで、去年(2017年4月)から隔週でプログラミング教室を担当している。板橋の「あいキッズ」というのは、いわゆる「学童」で共働きの家の子供が親が帰ってくるまで「預け」られる場所になっている。預けられるとはいっても、昨今では小学生の半分の親は共働きなので、当然のことながら児童の半分はあいキッズにやってくる、ってなわけで、昔とは違ってかなりの人数が集まってくるわけだ。板橋区の「あいキッズ」制度は、学童単位でそれぞれの民間業者に委託しているので、小学校によってあいキッズ内で行う「プログラム」に差がある(それぞれの業者が何らかを企画するためだ)。そんな中で、上板橋あいキッズを担当している放課後NPOさんから話を請けて「プログラミング教室」ってのを隔週で1時間ほどやっている。

ちなみに無償ではなく報酬は貰っている。「子供のためだから」といってボランティアでは続かないと思われたのと(続く人もいるんだけど、どうも私は続かない)、実際なにがしかの時間が掛かっているためだ。十分とは言えないし、半分ボランティアな感じなんだけど、持ち出さないようには注意している(苦笑)。

以下、いくつか去年の話を書き留めておこう

ノートパソコンを用意して貰う

特に Scratch がという訳でもなかったのだが、念頭にはあったのと、できれば Python とかを教えたかったのでノート PC を用意して貰うことにした。ひとり1台が望ましいのだが、最低限でも2人で1台が使えるようにしたい。募集人数もそれに絞って欲しい旨を伝えて、中古のノート PC を購入して貰う。予算が潤沢にあれば(都なり区なりから出して欲しいよね)新品とかを買えるんだろうが、そうもいかないので、中古で1.5万円程度の Windows 7 を購入して貰う。これ、こちらで代理で探してもいいのだけど、その費用は貰っていないのであいキッズ側で探して購入して貰っている。

最初は8台からスタートしたと思う。機種はばらばらだが、ほどよく大き目のノートPCが用意できて、無線LANを使えるようにする。…が、ここで問題があって、プログラミング教室をやる部屋があいキッズ内の無線が届かない位置にになっていて、一応ブースターを購入&設定して貰ったものの、あまり接続状態がよくない。なので、初めの2回はブラウザでの Scratch だったが、急遽ダウンロード版の Scratch を使うことにする。学校の教室で Scratch をするときも同じ問題が発生するし、無線ルータの状態によっては人数分(ひとクラス30名とか)一斉に繋げると接続状態が確保できなかったりするので、今後も課題になる。

ただし、ネットワークが全然駄目というわけではなくて、個人持ちの無線ルータの設定をしているので本家の scratch.mit.edu に繋げないこともない。ただし、一斉に繋げたり大量にダウンロードするとパンクしてしまうので、「スクラッチのサイトだけ」という限定にしている。つまり、Youtube とかは駄目。即座に、プチンと切ることにしている。そこはルールだからね。

実に騒がしく統率できない

あいキッズなので、3年生から6年生までを対象にしている。初年度ということ双方ノウハウがないので、半年ぐらいは様子見な感じで進めていた。ちなみに、本来は1年単位の契約なんだけど、撤退しやすいように半年契約にして貰っている。

私自身、社内研修とか勉強会での発表とかをこなしているので、解説とか講師っぽいところは慣れているのだけど、蓋を開けてみれば小学生3-6年生には通用しなかった。というか、学校の教室で教えるようにはいかんわ、これは、な感じなスタートであった。これにはいくつか理由があるのだけど、いわゆる発達障碍児が3人ほど含まれていたのと、プログラミングのような「面白そうな興味のあるもの」だと騒がしくなるのは当然で運動部のようにはいかない。授業っぽくやろうかという話もあったのだが、到底無理なことがわかったので、それぞれで自由にやらせる/やってもらうことにした。

最初の思惑としては、プリントを配って解説をして、それに沿ってスクラッチで作ってみる、そして半分は遊びとか思っていたものの、無理無理。たぶん、中学生か高校生ならば「学習するスタイル」ができているのだが、小学生ではまだまだで、騒がしいことこの上ない。

実はプログラミング教室に参加する場合には何がかのお金を取ることになっている(300円ぐらいだったか)。印刷物の問題もあるけど、参加人数を制限したかったのと、なにがしかのお金が払って「プログラミング」するならば、親もなんらかの形で真剣になるだろうという思惑であるが、そうなったかどうかは定かではない。ちなみに、ひとり300円何某の分は私は貰っていない。印刷物のプリントアウトはあいキッズ側に任せたかったのと、講師料がちょっと増えたぐらいでは半分ボランティなのは変わらないからだ。まあ、気分的にも楽なので。

そんな訳で、プログラミング教室に出席させるにはなにがしかのお金を払っているので、プリント代として返そうという訳である(これは、区への申請を通すためでもある)。スクラッチの説明やらブロックの説明やらを書いたプリントを私が2,3枚で作って、隔週で印刷して貰っている。

半年過ぎたら、人数が半減した

前期(10月頃)までは、16名体制だったのだが、後半になって8名位に減った。いわゆる、面白くないからやめたのだが(途中でおもしろくないから来なくなった子もいる)…まあ、営利業務ではないので、半分に減ってちょうどパソコンの台数と子供の数が等しくなったので結果オーライというところである。

おもしろくないの理由のひとつとして、課題が簡単すぎて何をやっていいのかわからない子と、課題をほっぽっといて絵とか好きにやっていきた子が、混在している。16名は抱えきれない(補佐で1人ついて貰っているけど)のと、本格的なプログラミング教室(月謝が1万円ぐらいのやつとか)や CodeDojo とは違うので、子どものモチベーションは様々だ。そして、あいキッズ側の主目的としては「プログラミングを学ぶ」のではなく、「安全に子供を預かる」なので、それに沿うことにしている。ほかにも、将棋教室とか音楽教室とかサッカー教室なんてのもあるので、プログラミングだけではないのだから、気に入らなかったら他のところで遊べばよい。

と割り切ることにして、後半は

  • 20分ぐらいだけ課題をやる
  • 残りの時間は、Scratch で遊ぶ

ことにした。ちなみに、課題は Scratch の簡単なプログラムをあらかじめ私が書いておいて、それ改造するという手順にしていた。いわゆるリミックスという奴なのだけど、今年はサンプルを作ることをやめている。というのも、サンプルを作るとそれを動かすだけで満足しちゃうんだよね。まあ、ゲームを動かすとかそれはそれでもパソコンに触れる(キーボードを打つ、マウスを動かす)こと習熟できるのだけど、もうちょっと自分だけでやってほしいのと、個々人で学習度合いは異なるのだが、子ども同士で教えあうほうが良いみたいだから。

今年は課題シートを作った

なんやかやと、去年はサンプルコードを作っていたので、かなり蓄積ができた。遊ぶ子はそれを眺めて貰うとして、自分で学習したい子のために課題シートを作ってみた。プールとか縄跳びの級みたいに、ちょっとずつ目標をこなしていく感じ。

image

これも、集まった子たちの性格にもよるんだろうけど、男子は完全無視というか適当にぱらぱらやって飽きてしまって Scratch ゲームを探してやっている(野球とバブルを消すゲームがブームだ)が、女子3名が熱心に課題をこなしているという具合だ。そこは男女の性格があるのかどうかわからないし、5年生の男子はプログラムが初めてなので熱心にブロックを積み上げているし、4年生の子は既に Scratch を知っているので勝手に拡張してあれこれやっている。まあ、それはそれでよい。

ちなみに、プログラミング教室の子ども面子はごっそりと入れ変わっていて、また最初から Scratch でということにしている。まあ、隔週だし、ほどよく出来たら家でもできるしね。あと、6年生は卒業してしまうし、5年生は中学受験があってというパターンもある。なので、1年周期で考えるといいんじゃないかと思う。

ちなみに、去年と今年のサンプルは 1-1 矢印キーで上下左右 な感じで作っている。去年の一番人気は いらいらボール だった。

Scratch 以外を導入したい

去年からずっとタイミングを見計らっているのだけど、Arduino か Python を導入したいとは思っている。のだが、それは「大人の都合」でしかなくって、子どもの興味/楽しみからしたら隔週でノートPC使って Scratch ゲームで遊ぶほうが楽しいかもしれない。

と、去年の最後に Arduino とサーボモーターを使った電子工作モノを持っていたところ、6年生の子が Arduino IDE でバシバシとコードを打っていたんだよね。一度、書いてあるものを写経っぽくキーボードで打ち込むのは、それはそれで楽しい作業らしい。そう、昔 BASIC マガジンからマシンコードを打ち込んだ感じとか、N88Basic のゲームを雑誌から打ち込んでいる感覚なのかもしれない。

なので、1,2台に Arduino IDE を入れて、電子工作ができるコーナーを作るのもよいだろう。手元には Aliexpress で購入した互換 Arduino があるし、ブレッドボードとかLEDとか妙に大量に手元にあるので。

カテゴリー: 雑談 | 2年目のプログラミング教室 はコメントを受け付けていません

アズルレーンを PINE64 で動作させるまで

艦これ系のスマホアプリとしては、(Android の動作確認ができそうなのが)戦艦少女R か アズルレーン な訳ですが、ボトムズコラボということで、アズルレーンを入れてみます。ちなみに、大陸版の碧蓝航线を使ってもいいのだけど、biiibiliや百度のIDが必要であったりあれこれとややこしいので、日本語版のアズールレーンを使う。

ちなみにボトムズは本放送を中学生の頃に見ていた世代なんだけど、アズレンのユーザーとしては何処にいるのかは分からないw ターゲットは謎だ。ちなみに↓はボトムズではない。

Pine64 + Android 上でアズレンが動くと↓なように HDMI 接続で液晶モニタに表示できるようになる。操作はマウスなんだけど、WiFi でのキャストと違って映像が直結するのでスマホ画面との遅延は皆無になる。まあ、なったところで何か意味がある訳ではないけど、もっと大き目の TV に繋げばデモ的には面白い?

PINE 64 とは?

組み込みボードだとラズパイが有名なのところだけど、いくつか互換機がある。互換機とはいっても、本家?ラズパイよりも性能が良かったり、様々な拡張が為されていたりして使いようによっては面白いことができる。手元にあるのは「PINE A64」で、個人輸入したものなんだが(普通に本家からクレジットカードで買うだけなんだけど)、最近は秋月でも売っている。ラズパイは5,000円位かかるのだが、PINE64 はモノによっては3,000円位で安く購入ができる。

Android 6.0 を PINE 64 に入れる

Pine A64 Software Release – PINE64 から、Android 6.x の image をダウンロードする。最新版は、Android 7.1 なんだけど、手元の実機が 6.0 なので、それにあわせる…と思っただが、6.0 だと動きがいまいちなので Android 7.x に切り替える。

Win32DiskImager を使って microSD カードに焼いたら、PINE 64 のボードに入れて起動させれば ok. ちっとばかり、起動に時間がかかるが、↓な感じで起動できれば大丈夫。

Android 6.x のディスクイメージは 8GB、16GB 等と揃っているのだが、16GB を使っている。8GB だとなんやかやとアプリをインストールすると足りなくなってしまうのと、最近のラズパイでも 8GB だと足りなくて 16GB を使うことが多くなっているので。PINE 64 には USB が付いていて、USB メモリを差し込むこともできるから、大き目のアプリ(*.apk)は USB メモリからインストールすると楽だったり。

Google のアカウントを登録すれば Google Play からもダウンロードができる。

PINE 64 へ adb で接続する

この手の組み込むボードで Android を動かす目的のひとつとして、root が簡単に取れるというのがある。実機の Android だと root を取るのにあれこれやらないと駄目だし、復帰させるのも結構大変なのだが(実機は実機で便利なのだけど)、組み込みボードに Android を入れたときには、microSD カードを直接除くとか、動作時に既に root 化されている(Android Things も含めてそういう目的なので)のが普通だったりする。そうそう、エミュレータを利用して、〇〇を抜き出すというのもあるのだが、そういうこともできる。microSD カードを直接除けばいいわけだし。

この画像は「戦艦少女R」の場合

以下は、Android 6.0 の時の場合。7.x の場合は、最初から adbd が立ち上がっているので、起動直後から adb connect できる。Android 7.1 Community Image [v0.3.10-r66] をインストールしている。

~~~

root 化はさておき、vysor を使って画面をリモートで操作したり、アプリを adb 経由で入れたいときになどには、なんとかして PINE 64 に接続しないといけない。が、PINE 64 ボードに差し込む micro USB や電源供給だけなので、実機の Android のように OTG できない。なんじゃこりゃ?ってことになるので、↓のようにシリアルケーブルで接続する

Cubieと過ごす日々: PINE64にadbで接続
http://donadona-memo.blogspot.com/2016/07/pine64adb.html

ことになる…のだが、別な方法があった。SSHDroid をインストール&起動させた後に、Tera term の SSH から root/admin で接続。その後に

# setprop service.adb.tcp.port 5555
# stop adbd
# start adbd

する

image

この後、PC から adb connect <AndroidのIP> すれば ok.

image

ただし、Android Things のように、初めから adbd が start しているものもあるので、Android 側の init.rc を書き替えれば起動時に adb connect を受け入れるようになるはず。これは後から試してみる。

~~~

Google Play からインストールして起動

あとは、Google Play からインストールするか、あらかじめ *.apk ファイルをダウンロードして adb install でいれるか、USB メモリを使って入れるか、いくつかのパターンがある。

タッチパネルな機能は使えないので、あらかじめ実機でアズレンのチュートリアルをすました後に、PINE64 側で ID の引き続きをすればよいだろう。

Android 7.1.2 の場合は、有線LANが使えるのでコネクタにLANケーブルを挿し込んで高速にダウンロードができる。

image

アズレンの場合、自動的な戦闘(自律戦闘)が可能なので、戦闘中は眺めているだけでいい。マウスを使うのは、途中で何かを選択するときになる。

image

GPU の動きはちょっとぎこちないので、3Dアクションゲームみたいなのは難しいかなと思う。パズルゲームとかカードゲームならば大丈夫じゃないだろうか。

あと、CPU がかなり熱くなって熱暴走するので、ヒートシンクは必須っぽい。実機 Android でもかなり熱くなるから、Unity の CPU/GPU ぶん廻しは相当なものなのだろう。ちなみに adb shell で top を調べると、アズレン(com.YoStarJP.AzurLane)がどれだけ CPU を消費しているのかが分かる。20%弱位消費している。まあ、これだけ消費していればバッテリーの減りも早いのではないだろうか。

image

せっかく GPIO が使えるので、物理的なジョイスティックとか繋げて操作できないかなと思ったりするのだが、何か良い方法はないものだろうか。Android のサービスアプリを作ればいけそうなんだが。

カテゴリー: 開発, Android, アズレン | アズルレーンを PINE64 で動作させるまで はコメントを受け付けていません

VB6 業務アプリの移行を考える

予算さえあれば、新規作成 or 完全移植してしまうのがベターなのだが、多くの場合予算の関係で VB6 の業務アプリをそのまま使い続けることがある。旧来の PC(Windows 2000やXPも含む)にインストールされている VB6 の業務アプリを専用機器のまま使う(あるいは、PC から吸い上げて仮想モード内のみで使う)方法もあるのだが、いくつかのネックがある。

  • 既存バグが解消されない
  • 新規システムと接続できない(修正できない)
  • 既存PCの CPU 速度に引っ張られて遅い

こともあり、 VB6 の業務アプリから何らかの形で引っ越したいところなのだが、予算がない、あるいは既存の業務アプリが複雑怪奇すぎるための引っ越しの予算が掛かかるかもしれない、という理由から、なんとか既存 VB6 コードを弄ろうとする。それは試算は試算なのだから、工場の機械よろしく使い潰すのがベターともいえる。

で、まったく移行予算が取れない場合は論外なのだが(社内等で VB6 のまま弄るしかない)、なんらかの予算が取れれば移行を外注することも可能ではないか?…という「仮定」のもとに考察してみる。

移行先のフレームワークを考える

VB6 の業務アプリの場合、C/S 方式が主なものになる。SQL Server か Acesss にデータを集めるために(当時の予算枠の具合で SQL Server か Access かが決まってくる)、ODBC, RDO, ADO を使って VB6 からデータベースサーバーへアクセスする。ユーザーが入力する画面では、旧文化オリエントのコントロール、スプレッドシートが使われていることが多い。実際、2002年頃に VB.NET が出てから、VB6 から VB.NET へ移行するために、各種の既存コントロールを .NET 化させたものが発売されている。ただし、VB のコンバートツールがあるものの、これらの .NET 用のコントロールまで網羅してくれてはいない。あくまで標準的なコントロールのコンバートのみとなり、スプレッドシートでかなりの部分をあれこれしている場合には、自動コンバートしたときにもアレコレしないといけないという「手間」が掛かってくる。イコール、移行予算が跳ね上がるのである。

また、2002年当時であれば、VB.NET や .NET の業務アプリも素朴なフレームワークなものが多かったのだが、今となっては、VB6 で作ったフレームワークをそのまま VB.NET に持って来るとコーディングの効率の悪さやメンテナンス性の悪さも引きずってしまう可能性が高い。たとえば、RDO や ADO で延々と SQL を書いている部分は、今であれば LINQ に直してしまうのが望ましい。特に Entity Framework と組み合わせてしまうと、INSERT/DELETE/UPDATE のコードはほぼ1行で済んでしまう。

また、当時から PC での C/S アプリをブラウザ形式の WEB アプリにすることが盛んであった。失敗には終わったが、Java アプレットや Siverlight、Flex のようなブラウザ上でのコンポーネントに移行してしまうというパターンもいくつかある。となると、既存の VB6 の C/S 形式のアプリを、何も考えずに C/S に直すというのもちょっと問題がある。潤沢ではない限られた移行予算となる場合は、

  • 移行時のコード量が、元のコードよりも大幅に減り、開発時間を減らす。
  • 移行時のテスト期間を何らかのツールを使って、大幅に削減できる。

という点に注視する必要がある。たとえば、移行コード量が移行前のものと同じでしかないのであれば、開発期間も同じぐらいかかり、単純に同じ程度の開発/移行コストが掛かるという見積もりになる。移行予算が潤沢に取れればよいが、そうもいかないであろう。IT 業者としては、新しい機能を盛り込むという理由を付けて、それなりの予算を取りたいところであるが、移行を頼む側から言えば、「同じ機能を実装してくれればよい」ので、余分に予算を取りたいわけではない。ある意味では、移行前も移行後も「同じ機能」でしかないので、できることなればい移行はゼロ円で済ませたいところなのだ。

一般的にソフトウェアは、劣化しないものとされているが、そういう意味では長期でソフトウェアを資産とするには、経年劣化があり資産価値がゼロになるということだ。このあたり、IT業者も非IT業者もあまり真面目に考えていない。

なので、旧来の VB6 の業務アプリは、OS がサポートから外されている、既存バグを直す人がいなくなっている、という理由から新しい業務アプリに移行するのが主な理由になる。そうなると、既存の VB6 と使用感は変わらないほうがよい。つまりは、「既存の VB6 アプリを Xamarin でタブレットアプリに移行しませんか?」というのはムダである。できることなれば、そのままでいいのだ。既存の不具合は直したいところだけど。

そうなると、移行先のフレームワークは限られてくる。ユーザーの特に新しくない使用感に合わせるためには、

  • VB6 業務アプリで C/S 風に使える

というのがベターである。この場合、ブラウザでぽちぽち入力するのも許容範囲であれば、

  • 現状の C/S をそのままのシステム移行
  • 内部で Web API を利用する C/S 方式へ移行
  • ブラウザ方式に移行

というパターンに落ち着く。既存の VB6 では RDO/ADO 等が使われているが、C/S 方式であっても EF+LINQ を利用する(コード量やテスト効率を含めて)、あるいは C/S でストアドプロシージャ等が使われていれば Web API/REST に移行するのもよいだろう。画面が多少パタパタしてもよいのでれば、HTMLを使ったブラウザアプリ(ASP.NET、PHP など)でも構わない。少なくとも、既存の C/S 方式をそのまま自動コードのコンバーターを使って移行するのは得策とはいえない。

移行先のプログラム言語を考える

2002年当時、VB6 から自動コンバートすると VB.NET のコードが出力される。今でもそうだけど、VB6 から C# へのコンバートはされない。先の理由から、自動コンバート自体おすすめできないので、なんらかの手作業による移行が必要になる。手作業であるから、移行できるコード量と、移行後のコード量というのが開発/移行コストに大きくかかわってくる。

既存の VB6 のコードで、標準モジュール(いわゆるライブラリ)が多ければ、*.bas なコードをそのまま VB.NET に持ってきても良いだろう。モジュールのままでもよいし、適当なユーティリティクラスでラップしてしまってもよい。特に複雑なロジックが入っているのであれば、*.bas なコードをそのまま流用できるならば、移行的にはかなり楽になる。

…ハズなのだが、実は、VB6 業務アプリでロジックが重要ということはあまりない。科学計算を必要とするとか、ブラックボックス的な業務ロジックを組む場合には、既に C++ であったり、C# に移行してしまったり、ストアドプロシージャで整理されていたりするので、VB6 自体には *.bas で移行する部分はほとんどないといってよい。*.bas なコードを眺めると、文字列の編集だとかデータのコンバートだとか、いまであれば .NET クラスライブラリに入っていそうなものばかりである。なので、VB6 だから VB.NET が有利である、というプログラム言語が同じであるというメリットはかなり低い。

そうなると、プログラム言語は、C# であっても VB.NET であっても構わない。C# の場合 VB6 から IF文や FOR文を移行するときにかなり書き替えなければいけないのだが、LINQを使うとかラムダ式をつかうとかイベントを多用するとか、を考えると VB の冗長なところが面倒だったりする。

なので、移行先のプログラム言語は、プログラマ自身が得意と思われる(チームが得意と思われる)言語がよい。C# か VB.NET のどちらを選んでもよい。まして、ブラウザアプリに切り替えてしまうのであれば、PHP でも十分なはずだ。

データベースを考える

C/S 方式の場合、サーバーにデータベースを据えることが多い。実際、VB6 での業務アプリの場合はサーバー側は十中八九 SQL Server となる。SQL Server のカラム名が日本語であったり、ひとつのテーブルのカラム数が50位あったり、正規化が不十分だったりすることは多いのだが、実は、データーベースの寿命はデスクトップアプリのそれよりも長い。

となれば、データベースの構造は、目をつぶってそのまま使うのひとつの方法である。よほどひどいモノでない限り、SQL Server のものを SQL Server のまま扱うのがよいだろう。このほうが EF + LINQ との相性もよいからだ。

ただし、EF を使うときに制限があり、テーブルに「主キーがひとつ」必要になる。LINQ が主キーを頼りに SaveChange するためなんだが、これはADO.NET Model のデザイン対象となるデータベースを仮に作ってしまい、主キーを付けることで回避できる。

印刷/帳票機能を移行する

旧来の VB6 では印刷機能が貧弱であったため、旧文化オリエントのスプレッドシートやレポートツールを使っていることが多いのだが、現在もそれを使い続けないとけない理由はない。

  • PDF に直接出力する
  • Excel や Word に出力する
  • HTML形式で出力する

最終的に紙に印刷するにしても、.NET から PDF に出力するライブラリはたくさんある。データをリスト形式で印刷するならば、HTML 形式を通して印刷してもよいだろう。

また、Excel や Word であらかじめテンプレートを作っておいて、データを埋め込む方法もできる。こうすると、微妙なフォントの大きさや印刷位置の調節をあらかじめ Excel や Word 上で確認することができる。

移行時の予算を考える

先に示した通り、現状の機能を移行する「だけ」なので、発注側にとって移行コストはゼロ円が望ましい。しかし、実際のとこころは資産価値が減少するのであるから、使い続けるためにはなんらかのコストを掛けるのは否めないというところだろう。

目安として、移行コストは新規開発の予算の半分から1/3といったところだろう。これは、機能はそのままでの移行案件の場合、

  • 要件定義、設計工程を省くことが可能
  • テスト工程で、正しい動作(既存の業務アプリ)が確認できる

ことになるためだ。多少の既存バグを修正する場合はよいのだが、移行時に機能追加をする場合には、その分のコストは別途見積もるのがよい。

また、これ以下の予算しか取れないばばあいは、コードを修正するような移行は諦めて、仮想環境への移行など延命処置に切り替える。この場合、当然のことながら VB6 の内部コードを弄ることはしないので、既存バグは既存バグのまま残ることになる。どちらを選択するかは顧客が選ぶことなる。

移行スケジュールを考える

大抵の IT プロジェクトの場合、予算が決まればスケジュールが決まる(人月で割るから)なのだが、VB6 からの移行の場合は、それは当てはまらない。というのも、単純に安めの移行予算を人月で割ってしまうと、超短期なスケジュールになってしまい納期遅延が必至になってしまうからだ。なので、移行スケジュールは、予算とは関係なく3か月から半年程度取ってしまうのがベターだ。

半年のスケジュールとなると、通常開発であれば(中小企業にとっては)相当な金額になってしまうものだが、実はフルタイムで移行プロジェクトに関わらなくてもよい。いや、むしろフルタイムで関わってしまうほうが移行プロジェクトのリスクが高くなってしまうとも云える。

プロジェクトの各タスク/WBS/チケットを出した後は、適当に順番にこなしていくのが移行プロジェクトを推進するときのノウハウになる。というのも、機能だけ移行する場合は、機能追加などの要件の調査や概要の再設計などが必要ないので、一種のウォーターフォール的な開発にバラすことができる。つまり、ひとつのチケットに対していつ開始していつ終了しても全体コストが変わらないパターンとなる。

適用条件としては、

  • 大幅な機能追加がないこと。「移行」だけに専念でき、要件定義、設計はそのままとする。
  • 既存のシステムが正常に動く(既存バグは除く)こと。

ということになる。この範囲であれば、顧客との交渉を減らすことのができ所謂コミュニケーションコストを減らせる。そして、週報等も省略し、適度なマイルストーンのみを配置する。全体的に緩くスケジュールを組み、別のプロジェクトと平行にこなす(保守プロジェクトとか)ことにより、チケット駆動開発が有効に働く。

これらの条件が揃ったときに「移行プロジェクト」の成功率は格段にあがる。

カテゴリー: 雑談 | VB6 業務アプリの移行を考える はコメントを受け付けていません

.NET Core で画像を縮小する

ふと思い立って、DS用のツイッタークライアントを試作している。ツイッター社からの機能の公開が不十分だし、それぞれのクライアント開発者も続々と撤退しているので、メリットがあるのか?というえば「ない!」んだけど、ASP.NET MVC Core の周辺の調査も兼ねて、というところで。

いずれ、github にでも公開するが、

  • ASP.NET MVC Core + .NET Core
  • CoreTweet

の組み合わせで作っている。以前、作っていた時は PHP でやっていたのだが、PHP にあまり慣れていないところもあって頓挫していしまった。今回は、仮想サーバーも借りたことだし、.NET Core も入れれば、その界隈のライブラリを使えるというメリットがあって、この組み合わせになっている。

.NET Core で画像を扱う

DSブラウザ(写真のはDSiなんだけど)は、結構古いので、絵文字が使えないとか内蔵している証明書が古めとか、そういう問題もある。メモリが限られているというのもある。なので、大き目の画像をはめてしまうとブラウザのメモリから溢れてしまう。

ひとまず、ツイッターで表示されている画像を 320×240 に固定にしてしまおう。

ところで、.NET Core 2.0 には画像関係のライブラリは標準で付いてこない。.NET Standard 3.0 だったかにはその予定はあるのだけど、ひとまず現状はない。

.NET Core向けの画像ライブラリ
https://www.infoq.com/jp/news/2017/04/net-core-imaging

最終的には、ラズパイや外部Linuxサーバーで動かすことになるので、Windows依存にしたくないところなので、.NET Core のままいくとして、NuGet から System.Drawing.Common をダウンロードする。

using System.Drawing;
using System.Net.Http;

public class ImageController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
    [HttpGet("Image/{path}")]
    public IActionResult Sumnail([FromRoute] string path)
    {
        try
        {
            var hc = new HttpClient();
            path = System.Web.HttpUtility.UrlDecode(path);
            var res = hc.GetAsync(path, HttpCompletionOption.ResponseContentRead).Result;
            var st = res.Content.ReadAsStreamAsync().Result;
            var srcbmp = new Bitmap(st);
            int h = 240;
            int w = 320;

            if ( srcbmp.Width > 320 )
            {
                h = srcbmp.Height * w / srcbmp.Width;
                if ( h > 240 )
                {
                    w = w * 240 / h;
                    h = 240;
                }
            }
            if (srcbmp.Height > 240)
            {
                w = srcbmp.Width * h / srcbmp.Height;
                if (w > 320)
                {
                    h = h * 320 / w;
                    w = 320;
                }
            }
            var destbmp = new Bitmap(w, h);
            var g = Graphics.FromImage(destbmp);
            g.FillRectangle(new SolidBrush(Color.LightGray), 0, 0, w, h);
            g.DrawImage(srcbmp, 0, 0, w, h);
            var mem = new System.IO.MemoryStream();
            destbmp.Save(mem, System.Drawing.Imaging.ImageFormat.Jpeg);
            mem.Position = 0;

            return new FileStreamResult(mem, "image/jpeg");
        }
        catch
        {
            return NotFound();
        }
    }
}

こうすると、

http://localhost:5000/Image/http%3a%2f%2fpbs.twimg.com%2fmedia%2fDfa0dCxUEAAgrwg.jpg

な感じで、320×240 の画像に縮小できる。これをタイムラインの index.cshtml に埋め込む。

@foreach ( var it in statuses )
{
<div style="width:320px;">
    @{
        var item = it.RetweetedStatus == null ? it : it.RetweetedStatus;
    }
    @if (it.RetweetedStatus != null)
    {
        <div><a href="Tweet/@it.User.ScreenName">@it.User.Name</a> さんがリツイート</div>
    }
    <img src="@item.User.ProfileImageUrl" width="48" height="48" align="left" style="margin:4px" />
    <div style="font-weight:bold"><a href="Tweet/@it.User.ScreenName">@item.User.Name</a> @item.User.ScreenName @item.CreatedAt</div>
    <div>@item.Text</div>

    @if (item.Entities != null && item.Entities.Media != null)
    {
        @foreach (var m in item.Entities.Media)
        {
            <!-- TODO:画像はサムネール化する -->
            var thum = System.Web.HttpUtility.UrlEncode(m.MediaUrl); 
            <img src="/Image/@thum" />
        }
    }
</div>

多分、magic.net を使ったほうが高機能なんだろうけど、縮小だけだったらこれで十分かも。Graphics クラスの中身はひと通りあるみたい。

NuGet Gallery | System.Drawing.Common 4.5.0
https://www.nuget.org/packages/System.Drawing.Common/

つい最近(5/30)に正式版になったっぽい

カテゴリー: 開発, C#, NET Core | .NET Core で画像を縮小する はコメントを受け付けていません

Android Things v1.0へsshで接続するなど諸々

せっかく Android Things が v1.0 になったので、再び Raspberry Pi に入れて確認してみる。

Android Things の microSD を作る

Android Things Setup Utillityの使い方 – Qiita
https://qiita.com/masaya3/items/a2fcb2811e74b076be47
Android Things Console
https://partner.android.com/things/console/#/tools

記事を参考にして、Android Things Console から Setup Utility をダウンロードする。zip ファイルを解凍して、android-things-setup-utility-windows を管理者権限で実行する。

– 1. Install Android Things and optionally set up Wi-Fi
– 1 – Raspberry Pi 3
– 1 – Default image: Used for development purposes. No access to the Android

のように選択すればラズパイ用の microSD ができる。WiFi の設定は microSD を作るときに設定できるのだけど、デスクトップPCの場合は WiFi に接続していない場合が多いし、ラズパイ+Android Thingsを起動した後にでもUSB接続のマウスとキーボードを使って、画面から設定が可能なので、この時点ではやらなくてもよい。

HDMI 接続のモニタ上から、network を設定できる。ベータ版とは違って画面上からできるのが便利。

adb shell する

普通の android と同じように adb shell ができる。Xamarin.Android の時と同じように、visual studio から「ツール」→「Android」→「Android adb コマンドプロンプト」を選択する。
既に、Android Things は開発者モード相当になっているので、WiFi が繋がっていれば tcpip で接続できる。

adb connect <Android ThingsのIP>:5555

リモートで画面が表示できる vysor があれば、画面も操作ができる

画面サイズは 640×480 固定になっているらしい。

Androidアプリをインストールする

せっかくなので、Xamarin.Forms を Android Things に入れて動かしてみる。Visual Studio 2017 で Xamarin.Forms のプロジェクトを作って、「Google iot_rpi3(Android 8.1 – API27)」で実行している。

右側に縞が入っているのは、モニタの解像度が合っていないから、このモニタは800×480なので、Android Things の config.txt あたりで設定できるはず。

既存のアプリ(*.apk)をインストールする

Android Things には Google Play のようなものがないので、*.apk ファイルを直接インストールする必要がある。

SSHDroid – Google Play のアプリ
https://play.google.com/store/apps/details?id=berserker.android.apps.sshdroid

SSHDroid が、Android へ SSH で繋げられるアプリなので、https://apps.evozi.com/apk-downloader/ や https://apkpure.com/jp/ から、SSHDroid_v2.1.2_apkpure.com.apk をダウンロードして PC に保存する。

adb install SSHDroid_v2.1.2_apkpure.com.apk

な形でインストールできる。

アプリを起動する

Android Things にはランチャーみたいなものがないので、adb shell am start -n を使わないといけない。このとき、開始する Activity 名が必要なのだが、これが苦労する。

package名のみからadb shell am start -nする – Qiita
https://qiita.com/mattak/items/41b1ce1d48ddb3b2bb4a

pm list package でインストール済みのパッケージ一覧を確認した後で、pm dump で起動するときのアクティビティを得る。既に adb shell しているときは pm list package でよい。

adb shell pm list package

more して android.intent.action.MAIN の部分だけを見る。

adb shell pm dump <パッケージ名>

この場合は、下記のように起動する。

adb shell am start -n com.companyname.App1/md5a445f6db5abf8b5b69aa92721cad9446.MainActivity

ちなみに、ホームへ戻るときには、input keyevent を使う。

adb shell input keyevent KEYCODE_HOME

SSHDroid へ接続する

am start -n berserker.android.apps.sshdroid/.MainActivity

で起動する。

Tera term で ssh:2222 で接続できる。ユーザ名は「root」でパスワードは「admin」になっている。

各種コマンドは busybox だそうで .bin がパスに追加されている。残念ながら su にはなれないが、vi が使えるのがいい。

WinSCP でつなぐことができるので、ファイル転送とかもできると思う。

その他

SSHDroid は SSH 接続するだけなので、Python を動かしたり、apt-get したりできない。このあたりは、Termux を使うといいらしいのだが、これは後で試してみる。

Termux – Google Play のアプリ
https://play.google.com/store/apps/details?id=com.termux

また、Android Things はグラフィック系がごっそりカットされる…予定だったのだが、ディスプレイ関係はごっそり残っている。ラズパイだとCPUが遅く駄目なんだと思うのだが、アクションじゃないゲームのほうが動くんじゃないかな。

例えば、戦艦少女RをAndroid Thingsで起動できる。アズレンはちょっと重たくて初期画面のところで駄目になってしまう。

com.huanmeng.zhanjian_jp_release/org.cocos2dx.cpp.AppActivity

Android アプリを Android Things に入れてもあまり意味がないのだが、ひとまず Android と同じ用にグラフィック系も扱えることが分かる(完全ではないけれど)。プラス、GPIO にセンサーを繋げたりボタンを繋げたりすることができるので、例えばロボット操作なアプリを Google Play で配布しておいて、実際はラズパイ+Android Things+ロボットアームな機器、を操作できるというのも可能ではある。ピン番号とかラズパイ用のハットを合わせないと駄目なんだけど、アプリ自体の配布は楽になるのかも。

あと、GUI 絡みは Xamarin.Forms がそのまま動くし、Android Things の場合は root になれるので、荒っぽいファイル操作も可能になる。まだ試してないのだけど、あらかじめARMでビルドしたバイナリファイルを microSD に入れておけば Android 上で実行できると思うんだけど、どうなんのだろう。

カテゴリー: 開発, Android, RaspberryPi | Android Things v1.0へsshで接続するなど諸々 はコメントを受け付けていません

M5Stack から Slack へ投稿できた編

前回、M5Stack から Slack へ投稿する挑戦中 やっていたものから、slack.com に投稿ができたので、ひとまず解決。

起動時に送信するだけなので、setup 関数に全て埋め込んでしまっているが、本来は M5Stack のスイッチを押したときとか、定期的なタイミングで温度センサーから読み込んで投稿、みたいなのを考えている。

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <M5Stack.h>

WiFiMulti wifi;

#define WIFI_SSID "<SSID名>"
#define WIFI_PASS "<SSIDパスワード>"
const char *server = "hooks.slack.com";
const char *json = "{\"text\":\"from arduino m5stack message.\",\"icon_emoji\":\":ghost:\",\"username\":\"m5stackpost\"}";

const char* slack_root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" \
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" \
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" \
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" \
"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" \
"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" \
"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" \
"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" \
"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" \
"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" \
"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" \
"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" \
"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" \
"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" \
"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" \
"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" \
"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" \
"-----END CERTIFICATE-----\n" ;
  
HTTPClient http;

void setup() {

  // put your setup code here, to run once:
  wifi.addAP(WIFI_SSID, WIFI_PASS);
  Serial.begin(115200);
  M5.begin();
  M5.Lcd.println("send slack");
  
  while (wifi.run() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.printf(".");
  }
  M5.Lcd.println("wifi connect ok");

  // post slack
  M5.Lcd.println("connect slack.com");
  http.begin( server, 443, "/services/XXXX/XXXX/XXXX", slack_root_ca );
  http.addHeader("Content-Type", "application/json" );
  http.POST((uint8_t*)json, strlen(json));
  M5.Lcd.println("post hooks.slack.com");
}



void loop() {
  // put your main code here, to run repeatedly:

}

ポイントは,

  1. WiFiMulti でアクセスポイントの接続
  2. HTTPClient を使う。
  3. HTTPClient::begin で hook.slack.com に https 接続する。このとき、slack.com の証明書を指定する。
  4. HTTPClient::POST() で JSON 形式のデータを POST する。

ESP32 絡みで、HTTP プロトコルを作る例はいくつかあるのだけど、きちんと POST できるのは「HTTPClient」であった。標準で「HttpClient」ってのがあるけど、これは動かない。

Windows ではじめるM5Stack – Qiita
https://qiita.com/xzr_tw/items/3363a500b4503e424d8b
espressif/arduino-esp32: Arduino core for the ESP32
https://github.com/espressif/arduino-esp32

の中にある https://github.com/espressif/arduino-esp32/blob/master/libraries/HTTPClient/src/HTTPClient.h を見ると、HTTPClient の各種メソッドが想像できる。マニュアルがあるかどうかわからないのだけど、まあ、github で HTTPClient.cpp を見ればよい。

内部で、WiFi.h と WiFiClientSecure.h がインクルードされているので、WiFiClientSecure を使って HTTP プロトコルのヘッダ部をちまちま作るよりもベターかもしれない。

slack に送る json の形式と URL アドレスは、

C# で Slack に投稿する | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/9117

で作ったものを使っている。

起動して、アクセスポイントに接続、その後 slack に投稿する。

PC の slack クライアントにリアルタイムに表示されるので、なかなか面白い。

何に使うか?

データ蓄積ならば、azure か aws の IoT Hub を使って情報蓄積するところで、それだと HTTP の GET で十分だったりする。ただ、何かの閾値を超えた(高温になったとか、ドアが開いたとか)場合には、何らかの警告をユーザーに示しておきたいわけで、大抵の場合はメール通知を使うか、専用のクライアントアプリを使うのだが(スマホの通知とか?)、もっとお手軽&試作的なところでは slack の通知を使うと便利だろう。まあ line でもいいんだけど、line の場合は電話番号が必要なので slack のように捨てメールアドレスで作れると便利だったりする。

M5Stack の場合は LCD が標準で付いているので、定期的に web api を叩いて表示するってのもできる。同じことはラズパイやPC等でもできるのだが、電力が少なくて済む(5V0.5A程度の範囲でよい)ってのがよい。ああ、Orange Pi でもいいんだけど、そっちのほうは別途ためしてみる。

カテゴリー: 開発, M5Stack, Slack | M5Stack から Slack へ投稿できた編 はコメントを受け付けていません

VBでwebapiするdotnetテンプレートをnuget化する

dotnet テンプレートができたので、nuget からダウンロードできるようにする。

Visual Basic で ASP.NET MVC Core する | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/9206

これをテンプレート化して nuget.org に入れるのだが、以下が参考になる。

NuGet クイックスタート | nupkg をつくる – secretbase.log
http://cointoss.hatenablog.com/entry/2017/03/15/071926
dotnet new のカスタム テンプレートを作成する | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/core/tutorials/create-custom-template
NuGet パッケージの作成方法 | Microsoft Docs
https://docs.microsoft.com/ja-jp/nuget/create-packages/creating-a-package

dotnetテンプレートを作る

色々はまるのだが、以下なフォルダ構造になるらしい。

+ src
 + Moonmile.WebapiTemplate.VB
  - Moonmile.WebapiTemplate.VB.nuspec
  - nuget.exe
 + content
  + .template.config
   - template.json
  - Moonmile.WebapiTemplate.VB.vbproj
  - *.vb 群
  • テンプレートとなるフォルダは「content」になる。
  • テンプレートの設定ファイル(template.json)は、「.template.config」フォルダ内に置く。
  • nuget のための Moonmile.WebapiTemplate.VB.nuspec は、コンテンツのひとつ上になる。

Moonmile.WebapiTemplate.VB.vbproj なフォルダで、Console プロジェクトなどを作ってテンプレート化することになる。

.template.config/template.json

{
    "$schema": "http://json.schemastore.org/template",
    "author": "Tomoaki Masuda",
    "classifications": [ "Web", "WebAPI" ], 
    "name": "ASP.NET Core Web API via Visual Basic",
    "identity": "Moonmile.WebapiTemplate.VB",         
    "groupIdentity":"Moonmile.WebapiTemplate",
    "shortName": "webapivb",                   
    "tags": {
      "language": "VB",         
      "type":"project"
    },
    "sourceName": "Moonmile.WebapiTemplate.VB",
    "preferNameDirectory":true  
  }
  • identity は、nuget でしているするときの名前になるハズ
  • sourceName で *.vbproj と同じ名前にしておくと dotnet new -name で指定したときにプロジェクト名を同じにあわせてくれる

この状態で nuget pack すると、*.nupkg を作ってくれる。nuget pack はプロジェクトファイルを指定しなくても、*.nuspec と名前を合わせておけば大丈夫らしい。

<?xml version="1.0"?>
<package >
  <metadata>
    <id>Moonmile.WebapiTemplate.VB</id>
    <version>0.1.0</version>
    <title>WebAPI project by Visual Basic</title>
    <authors>Tomoaki Masuda</authors>
    <owners>Tomoaki Masuda</owners>
    <licenseUrl>https://github.com/moonmile/dotnet-template-webapi-vb</licenseUrl>
    <projectUrl>https://github.com/moonmile/dotnet-template-webapi-vb</projectUrl>
    <iconUrl>http://moonmile.net/</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>
      Creates Web API project by Visual Basic.
    </description>
    <releaseNotes>
      sample version.
    </releaseNotes>
    <copyright>Copyright moonmile solutions</copyright>
    <tags>WebAPI VB</tags>
    <packageTypes>
      <packageType name="Template" />
    </packageTypes>
      </metadata>
</package>

ローカルで *.ngpkg をインストールする

できあがった *.ngpkg ファイルを dotnet new コマンドでインストールする。

dotnet new -i Moonmile.WebapiTemplate.VB.0.1.0.nupkg

こんな風に、自前のテンプレートが追加されていれば ok

アンインストールは、ID である Moonmile.WebapiTemplate.VB を指定すればok.

dotnet new -u Moonmile.WebapiTemplate.VB

nuget にアップロードしたものを取り込む場合は、ID で大丈夫

dotnet new -i Moonmile.WebapiTemplate.VB

試しにプロジェクトを作ってみる

dotnet new webapivb -lang vb -n web

どうやらデフォルトがC#に固定らしく、-lang で言語を指定しないとだめっぽい。

プロジェクトができたら、vscode や visual studio でコーディングができる。

当然のことながら、さっくりと dotnet run ができる。

テンプレートコードとnuget

moonmile/dotnet-template-webapi-vb: dotnet new tamplete create WebAPI by Visual Basic.
https://github.com/moonmile/dotnet-template-webapi-vb
NuGet Gallery | Moonmile.WebapiTemplate.VB
https://www.nuget.org/packages/Moonmile.WebapiTemplate.VB

まあ、普通ならば web api は C# で作るだろうし、F# のような関数型だと C# との違いも明確になるのだけど VB だといまひとつ文法が冗長なだけで手を出しても意味がないような気がしないでもない。このあたりは、単純に好みの問題かな。VBA や VBScript とかうまく融合できればいいのだけど。

おまけ

実は、dotnet new コマンドで取り込むのはC#/VBなどのプロジェクトじゃなくてよい。ファイルを取り込むことができるので、Excel を読み込ませることもできる。試しに Excel 方眼紙を dotnet new で作るパターン

https://www.nuget.org/packages/Moonmile.Excel.Hougan/

install すると、

dotnet new -i Moonmile.Excel.Hougan

こんな風に Excel 方眼紙プロジェクト?を作ることができる。

dotnet new excelhougan -lang Excel 
カテゴリー: 開発, NET Core, VB | VBでwebapiするdotnetテンプレートをnuget化する はコメントを受け付けていません

Visual Basic で ASP.NET MVC Core する

意図的なのかワザとなのか意地悪なのかしらないが、dotnet new には Visual Basic のプロジェクトを作成する機能はない。

機能はないのだが、下記を参照してカスタムテンプレートを作れば VB の ASP.NET MVC Core なプロジェクトテンプレートを作れる。

dotnet new のカスタム テンプレートを作成する | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/core/tutorials/create-custom-template

が、まあ、初手としてまずは「できる」ことを確認するために手作業でテンプレートを作ってみようって訳で。

.NET Core コンソールアプリから始める

プロジェクトで「コンソールアプリ(.NET Core)を作る

プロジェクトファイル(*.vbproj)を開いて、wwwroot と Microsoft.AspNetCore.All を追加する。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <RootNamespace>web_vb</RootNamespace>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="wwwroot\" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.8" />
  </ItemGroup>

  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.4" />
  </ItemGroup>

</Project>

C# にある「Microsoft.VisualStudio.Web.CodeGeneration.Tools」も追加しているが、スキャフォールディングとかしない(多分できない)ので、必要ないかも。

Program.vb と Startup.vb を追加する

C# と合わせるために2つのファイルを追加する。

Program.vb

Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Threading.Tasks
Imports Microsoft.AspNetCore
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.Extensions.Configuration
Imports Microsoft.Extensions.Logging

Module Program
    Sub Main(args As String())
        Console.WriteLine("Hello ASP.NET MVC and VB World!")
        Dim host = WebHost.CreateDefaultBuilder(args).
            UseStartup(Of Startup)().
            UseUrls("http://*:5000").Build()
        host.Run()
    End Sub
End Module

Startup.vb

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Threading.Tasks
Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.Extensions.Configuration
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Logging
Imports Microsoft.Extensions.Options

Public Class Startup
    Public Sub New(configuration As IConfiguration)
        _Configuration = configuration
    End Sub
    Private _Configuration As IConfiguration
    Public ReadOnly Property Configuration As IConfiguration
        Get
            Return _Configuration
        End Get
    End Property
    Public Sub ConfigureServices(services As IServiceCollection)
        services.AddMvc()
    End Sub
    Public Sub Configure(app As IApplicationBuilder, env As IHostingEnvironment)
        If env.IsDevelopment() Then
            app.UseDeveloperExceptionPage()
        End If
        app.UseMvc()
    End Sub
End Class

コントローラクラスを書き替える

ValuesController.vb を作る

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Threading.Tasks
Imports Microsoft.AspNetCore.Mvc

<Route("api/[controller]")>
Public Class ValuesController
    Inherits Controller

    <HttpGet>
    Public Function [Get]() As IEnumerable(Of String)
        Return New String() {"value1", "value2"}
    End Function

    <HttpGet("{id}")>
    Public Function [Get](id As Integer) As String
        Return "value"
    End Function

    <HttpPost>
    Public Sub Post(<FromBody> value As String)

    End Sub

    <HttpPut("{id}")>
    Public Sub Put(id As Integer, <FromBody> value As String)

    End Sub

    <HttpDelete("{id}")>
    Public Sub Delete(id As Integer)

    End Sub
End Class

HttpGet のところは、Getメソッドが標準とダブるので [Get] のようにしてあるが、GetList とか名前を付けてもよいと思う。

実行する

http://localhost:5000/api/values を実行すると、web api が動いていることが分かる。

Razor は使えるのか?

ASP.NET Core な Web API を VB で作ることができることは解ったのだが、じゃあ MVC の Razor は使えるのかどうか?ってのは未だ試していない。

dotnet new page コマンドを使うと C# の Razor(*.cshtml)を出力してくれるので、このあたりを追加すると VB でも使えるようになるのは?とか。

カテゴリー: 開発, ASP.NET, NET Core | Visual Basic で ASP.NET MVC Core する はコメントを受け付けていません

M5Stack から Slack へ投稿する挑戦中

スイッチサイエンスさんで売り切れだったので、Aliexpress から M5Stackを買いました。ってことで、どうせならば Slack に投稿してみようとして挑戦中

M5Stackでビットコインの価格を表示 – Qiita
https://qiita.com/eggman/items/36d30e01bf64f4a71516
Arduino – ESP32 WiFiClientSecure ライブラリで、安定して https ( SSL )記事をGETする方法 | ページ 3 / 3 | mgo-tec電子工作
https://www.mgo-tec.com/blog-entry-arduino-esp32-ssl-stable-root-ca.html/3

このあたりを参考にして

  • WiFi に接続させる
  • slack.com の証明書をプログラムに埋め込む
  • slack.com に https で POST する

ってことをやります。

下記は、まだ投稿ができていないけど、途中までのコード。

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
#include <M5Stack.h>

WiFiMulti wifi;

#define WIFI_SSID "<WiFiのSSID>"
#define WIFI_PASS "<WiFiのパスワード>"

const char* slack_root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" \
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" \
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" \
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" \
"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" \
"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" \
"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" \
"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" \
"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" \
"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" \
"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" \
"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" \
"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" \
"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" \
"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" \
"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" \
"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" \
"-----END CERTIFICATE-----\n" ;
  
WiFiClientSecure client;

void setup() {

  // put your setup code here, to run once:
  wifi.addAP(WIFI_SSID, WIFI_PASS);
  Serial.begin(115200);
  M5.begin();
  M5.Lcd.println("send slack");
  
  while (wifi.run() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.printf(".");
  }
  M5.Lcd.println("wifi connect ok");
  // post slack
  const char *server = "hooks.slack.com";
  const char *postdata = "{\"text\":\"from arduino m5stack message.\",\"icon_emoji\":\":ghost:\",\"username\":\"m5stackpost\"}";


  M5.Lcd.println("connect slack.com");
  client.setCACert(slack_root_ca);
  if (!client.connect(server, 443)) {
    M5.Lcd.println("Connection failed!");
    return ;
  }
  else 
  {
    M5.Lcd.println("Connected to server!");

    // client.println("POST /services/XXX/XXX/XXX HTTP/1.1");
    client.println("POST https://hooks.slack.com/services/XXX/XXX/XXX HTTP/1.0");
    client.print("Host: ");
    client.println( server ); 
    client.println("Content-Type: application/json" );
    char buf[20];
    client.print("Content-Length: " );
    // client.println("Connection: close");
    client.println();
    client.println( postdata ); Serial.println( postdata );
    M5.Lcd.println("post slack.com");
  }
}



void loop() {
  // put your main code here, to run repeatedly:

}

WiFiに接続させる

WiFiMultiを使って、addAP でアクセスポイントに接続する。WEP しか繋がらないような気もするので、WEP で用意しておく。

#include <WiFi.h>
#include <WiFiMulti.h>

#define WIFI_SSID "<WiFiのSSID>"
#define WIFI_PASS "<WiFiのパスワード>"

WiFiMulti wifi;
void setup() {

  M5.begin();
  M5.Lcd.println("send slack");
  wifi.addAP(WIFI_SSID, WIFI_PASS);
  while (wifi.run() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.printf(".");
  }

HTTPSで繋げるための準備

Slackに投稿するのに https が必要なので、相手の証明書をプログラムに埋め込む。

Arduino – ESP32 WiFiClientSecure ライブラリで、安定して https ( SSL )記事をGETする方法 | ページ 2 / 3 | mgo-tec電子工作
https://www.mgo-tec.com/blog-entry-arduino-esp32-ssl-stable-root-ca.html/2

を参考にして、slack.com の証明書を slack_root_ca として保存する。

const char* slack_root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" \
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" \
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" \
"QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" \
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" \
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" \
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" \
"CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" \
"nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" \
"43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" \
"T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" \
"gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" \
"BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" \
"TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" \
"DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" \
"hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" \
"06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" \
"PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" \
"YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" \
"CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" \
"-----END CERTIFICATE-----\n" ;
  
WiFiClientSecure client;

  client.setCACert(slack_root_ca);
  if (!client.connect(server, 443)) {
    M5.Lcd.println("Connection failed!");
    return ;
  }
  else 
  {
    M5.Lcd.println("Connected to server!");
  ...
  }

443ポートにWiFiClientSecureで接続すればok. ちなみに証明書が違っている場合は、client.connect がエラーを返す。

SlackへPOSTする。

hook.slack.com へは JSON形式で POST するので、HTTPプロトコルのヘッダを真面目に作る。

void setup() {
  ...

  const char *server = "hooks.slack.com";
  const char *postdata = "{\"text\":\"from arduino m5stack message.\",\"icon_emoji\":\":ghost:\",\"username\":\"m5stackpost\"}";

  M5.Lcd.println("connect slack.com");
  client.setCACert(slack_root_ca);
  if (!client.connect(server, 443)) {
    M5.Lcd.println("Connection failed!");
    return ;
  }
  else 
  {
    M5.Lcd.println("Connected to server!");

    // client.println("POST /services/XXX/XXX/XXX HTTP/1.1");
    client.println("POST /services/XXX/XXX/XXX HTTP/1.0");
    client.print("Host: ");
    client.println( server ); 
    client.println("Content-Type: application/json" );
    char buf[20];
    client.print("Content-Length: " );
    // client.println("Connection: close");
    client.println();
    client.println( postdata ); Serial.println( postdata );
    M5.Lcd.println("post slack.com");
  }
}

POST するときのアドレスは、

C# で Slack に投稿する | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/9117

で作った Incoming WebHooks ものを流用。

で、結果は?

このコードを M5Stack に転送して動かすと、slack.com に繋がって POST しているように見えるのだが…

slack のほうには送られてこないんだよね orz 同じ JSON データを C# で送った場合は大丈夫なので、SSL あたりが違うか、ヘッダ部分が違うのか。

ひとまず、いきなり HTTPS は段階が大変なので、一度 HTTP で繋げられるWEB APIサーバーを作って再開してみる。

カテゴリー: 開発, M5Stack | M5Stack から Slack へ投稿する挑戦中 はコメントを受け付けていません