SyntaxHighlighter

---SyntaxHighlighter ウィジェット---

2016年1月30日土曜日

FlashAirとAE-FAIO_baseでIFTTTしてPebbleに通知。

余熱(@yone2_net)さんから、試作の基板を頂いたので。


ボタンと液晶、Groveコネクタ、そして電源用USB端子がついていて、
FlashAirで手軽に何かするには非常に便利な感じです。

プログラムは以下。
拙作のlibAE_FAIOを使っています。
液晶が3.3Vに接続されているので、lcdContが必須になります。

require("/FTLE/lib/libAE_FAIO-core");
require("/FTLE/lib/libAE_FAIO-gpio");
require("/FTLE/lib/libAE_FAIO-i2c");
require("/FTLE/lib/libAE_FAIO-lcd");

PIN_LED = 0;
PIN_SW1 = 1;
PIN_LCD = 2;
PIN_CN2 = 3;

libAE_FAIO_Setup(100);
pinMode(PIN_LED,OUTPUT);
pinMode(PIN_SW1,INPUT);
pinMode(PIN_LCD,OUTPUT);
pinMode(PIN_CN2,INPUT);

lcdInit();
lcdCont(0x20,1);
lcdMax(8,2);

::main::

lcdClear();
lcdPrintLine("STANDBY\nFlashAir");

digitalWrite(PIN_LCD,LOW);
while true do
    digitalWrite(PIN_LED,HIGH);
    delay(100);
    digitalWrite(PIN_LED,LOW);
    delay(100);
if(digitalRead(PIN_SW1)==LOW)then break;end;
end

digitalWrite(PIN_LCD,HIGH);
lcdClear();
lcdPrintLine("IFTTT\nSend...");
fa.request("https://maker.ifttt.com/trigger/***/with/key/***")

delay(500);

lcdClear();
lcdPrintLine("Notice\nSend OK!");

delay(10000);

goto main

※goto文使うもんじゃないですね、ええ。わかってます。

2016年1月23日土曜日

HSPでPCにあるドライブの一覧を取得し、さらに詳細情報を得る



#uselib "Kernel32"
#func GetLogicalDriveStrings "GetLogicalDriveStringsA" int,var
#cfunc GetDriveType "GetDriveTypeA" var
#define DRIVE_UNKNOWN 0 //ドライブの種類が判別できません。
#define DRIVE_NO_ROOT_DIR 1 //指定のルートディレクトリが存在しません。
#define DRIVE_REMOVABLE 2 //ドライブからディスクを抜くことができます。
#define DRIVE_FIXED 3 //ドライブからディスクを抜くことができません。
#define DRIVE_REMOTE 4 //リモート (ネットワーク) ドライブです。
#define DRIVE_CDROM 5 //CD-ROM ドライブです。
#define DRIVE_RAMDISK 6 //RAM ディスクです。


sdim buf,1024
//ドライブ一覧を取得
GetLogicalDriveStrings 1024,buf

//NULL文字で区切られているので、分離して文字列に
null_cnt=0;
REPEAT 1024
b = peek(buf,cnt)
if(b == 0) : {
null_cnt++;
poke buf,cnt,','
}else{
null_cnt=0;
}

if(null_cnt>=2):{
poke buf,cnt,0
break
}
LOOP

//末端に付いた,を除去
buf = strtrim(buf,2,',')
//文字列を分離して配列に
split buf,",",drives

//詳細情報取得
dim drives_info,30 //詳細配列初期化
foreach drives
drives_info(cnt) = GetDriveType(drives.cnt)
loop

//表示
DriveListString=""
foreach drives
Show = ""+drives.cnt+" : "
if(drives_info(cnt) == DRIVE_UNKNOWN) : Show+="DRIVE_UNKNOWN"
if(drives_info(cnt) == DRIVE_NO_ROOT_DIR) : Show+="DRIVE_NO_ROOT_DIR"
if(drives_info(cnt) == DRIVE_REMOVABLE) : Show+="DRIVE_REMOVABLE"
if(drives_info(cnt) == DRIVE_FIXED) : Show+="DRIVE_FIXED"
if(drives_info(cnt) == DRIVE_REMOTE) : Show+="DRIVE_REMOTE"
if(drives_info(cnt) == DRIVE_CDROM) : Show+="DRIVE_CDROM"
if(drives_info(cnt) == DRIVE_RAMDISK) : Show+="DRIVE_RAMDISK"
mes Show

DriveListString += Show + "\n"
loop

objsize 500
DriveSelect= -1
listbox DriveSelect,100,DriveListString
button "OK",*OK

stop
*OK
mes drives.DriveSelect

2016年1月22日金曜日

FlashAir対話型応用設定ツールを考案中

FlashAirでよくやりたくなることってなんだろう。
それがわかるなら、簡単に設定できる(Luaスクリプトを生成する)ツールを作ろうかなと思っている。

現状ありそうだと思うこと

・外部入力があったら外部のURLを叩く
・外部入力があったら日時のログファイルを作ってDropboxにアップロードする

・特定のファイルが更新されたら外部のURLを叩く
・特定のファイルが更新されたらDropboxにアップロードする

・特定のフォルダにファイルが追加されたら外部のURLを叩く
・特定のフォルダにファイルが追加されたらDropboxにアップロードする

・何らかのファイルが更新されたら外部のURLを叩く
・何らかのファイルが更新されたらDropboxにアップロードする

・AirioのLEDをチカチカする

外部のURL
 →IFTTT maker Channel
 →stewgate(twitter)
 →pushover(プッシュ通知)
 →その他の任意のURL

なにか他に、よく使われそうな機能の要望があったら、この記事のコメント欄か、
twitterの方に教えてほしい。



2016年1月18日月曜日

Boost AsioでSerialのレスポンスが妙に遅い(その上それがばらつく)とき

Boost AsioでSerialのレスポンスが妙に遅い(その上それがばらつく)とき。
例えば、ループバックで1バイト送って帰ってくるのに、16ms~70msとかかかるとき。
特に、再起動直後重かったりする場合。

大抵、Readに時間がかかっています。
そして、Windows APIで直接COMポートを叩いたり、Boost Asioを使う場合でも
固定長のデータをやり取りする場合は早かったりします。

解決方法
1.読み込み時のバッファ変数を小さくする
2.transfer_at_leastを使わないでReadする。

これだけで、応答が1ms以下になったりしますが、これでも解決しない場合。

USBシリアル変換器を使っていませんか?
その場合は、デバイスマネージャの当該機器の詳細設定の「レイテンシタイマー」を
適切な値(環境によりますが、1ms~6msの間くらい)で設定してあげると、早くなります。

2016年1月12日火曜日

Pebble Time用のWatchFaceのサンプルを作った。

Pebble Time用のWatchFaceのサンプルを作った。

・画像の表示
・月/日 時:分の表示
・バッテリー残量の表示
・Bluetooth状態の表示/接続・切断時バイブ

と、基本的に欲しい機能を突っ込みました。
ほとんど公式のチュートリアル通りです。


プロジェクトのファイルを置いておくので、CloudPebbleにインポートすれば
あとは背景画像を差し替えるだけで使えると思います。
Pebble Classicでも使えるとは思いますが、動作確認はしていませんし、
動くようにも作っていません。(各オプションがPebble Time用になっています)

ダウンロード


動画を見ながらどうぞ。(3:40から手順解説になります)


以下ソースコード。

#include <pebble.h>
#include "main.h"

//うまくWatchFaceに登録されない時は、一度スマホからこのWatchFaceを削除したり
//UUIDやバージョン、作者名を変更したりすると良い。

//mainウィンドウポインタ
static Window *s_main_window;
//時間表示用文字列レイヤー
static TextLayer *s_time_layer;
static TextLayer *sw_time_layer;

//バッテリー表示レイヤー
static TextLayer *s_bat_layer;

//ビットマップ表示用レイヤー
static BitmapLayer *s_background_layer;
//ビットマップデータポインタ
static GBitmap *s_background_bitmap;

//Bluetoothステータス
static char bt_status[4] = "BT";
//過去のBluetoothステータス
static int bt_st_old = 1;

//バッテリーハンドラ
static void battery_handler(BatteryChargeState new_state) {
   //バッテリー状態取得して表示(ついでにBluetooth接続状態を表示)
  static char s_battery_buffer[32];
  snprintf(s_battery_buffer, sizeof(s_battery_buffer), "Bat: %d%%   %s", new_state.charge_percent,bt_status);
  text_layer_set_text(s_bat_layer, s_battery_buffer);
}

//Bluetoothハンドラ
void bt_handler(bool connected) {
  if (connected) {
      //接続に変化したらバイブ
      if(bt_st_old == 0)
         vibes_short_pulse();
      bt_st_old = 1;
      snprintf(bt_status,4,"BT");
   } else {
      //切断に変化したらバイブ
      if(bt_st_old == 1)
         vibes_short_pulse();
      bt_st_old = 0;
      snprintf(bt_status,4,"--");
  }
   //現在のバッテリーを読む(BT表示)
   battery_handler(battery_state_service_peek());
}

//画面更新
static void update_time() {
  //時刻構造体を得る
  time_t temp = time(NULL);
   //ローカル時刻を得る
  struct tm *tick_time = localtime(&temp);
   
   //文字列バッファを確保し、そこに文字列形式で時刻を得る。
   //24時間表示かどうかで切り替えている。
   static char s_buffer[8];
  strftime(s_buffer, sizeof(s_buffer), clock_is_24h_style() ?
                                          "%H:%M" : "%I:%M", tick_time);
   static char sp_buffer[16];
   snprintf(sp_buffer,16,"%02d/%02d  %s",
   (tick_time->tm_mon+1),
  tick_time->tm_mday,
   s_buffer);

  //テキストレイヤーにセットする
  text_layer_set_text(s_time_layer, sp_buffer);
  text_layer_set_text(sw_time_layer, sp_buffer);


}


//タイマーハンドラ
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
  update_time();//1分に1回画面更新する
}

//Windowが生成された時
static void main_window_load(Window *window) {   
  //ウィンドウの情報を取得
  Layer *window_layer = window_get_root_layer(window);
  GRect bounds = layer_get_bounds(window_layer);

   //ビットマップデータの読み込み
   //RESOURCESではRESOURCE_ID_を含めない名前で指定する。
   //この場合。IDENTIFIER=BACKGROUND
   s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_BACKGROUND);
   //ビットマップレイヤーの作成
   s_background_layer = bitmap_layer_create(bounds);
   //ビットマップレイヤーにビットマップを割り
   bitmap_layer_set_bitmap(s_background_layer, s_background_bitmap);
  //windowレイヤーに子レイヤーとしてビットマップレイヤーを追加
   layer_add_child(window_layer, bitmap_layer_get_layer(s_background_layer));

   //-------------------------------------
   
   //境界付きでテキストレイヤーを作成
  sw_time_layer = text_layer_create(
         //x, y, w , h
      GRect(1, 111, bounds.size.w, 50)

      //PBL_IF_ROUND_ELSE(if_true, if_false)なので、円形ならx=58,角形ならx=52
      //GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50)
   );

  //テキストレイヤーを設定
  text_layer_set_background_color(sw_time_layer, GColorClear);
  text_layer_set_text_color(sw_time_layer, GColorFromHEX(0x000000));
  //text_layer_set_text(s_time_layer, "00:00");
  text_layer_set_font(sw_time_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28));
  text_layer_set_text_alignment(sw_time_layer, GTextAlignmentCenter);

  //windowレイヤーに子レイヤーとしてテキストレイヤーを追加
  layer_add_child(window_layer, text_layer_get_layer(sw_time_layer));
   
   //-------------------------------------
   
  //境界付きでテキストレイヤーを作成
  s_time_layer = text_layer_create(
         //x, y, w , h
      GRect(0, 110, bounds.size.w, 50)

      //PBL_IF_ROUND_ELSE(if_true, if_false)なので、円形ならx=58,角形ならx=52
      //GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50)
   );

  //テキストレイヤーを設定
  text_layer_set_background_color(s_time_layer, GColorClear);
  text_layer_set_text_color(s_time_layer, GColorFromHEX(0xFFFFFF));
  //text_layer_set_text(s_time_layer, "00:00");
   
  text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28));
  text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);

  //windowレイヤーに子レイヤーとしてテキストレイヤーを追加
  layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
   
   //-------------------------------------
   
  //境界付きでテキストレイヤーを作成
  s_bat_layer = text_layer_create(
         //x, y, w , h
      GRect(0, 140, bounds.size.w, 50)

      //PBL_IF_ROUND_ELSE(if_true, if_false)なので、円形ならx=58,角形ならx=52
      //GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50)
   );

  //テキストレイヤーを設定
  text_layer_set_background_color(s_bat_layer, GColorClear);
  text_layer_set_text_color(s_bat_layer, GColorFromHEX(0xFFFFFF));
  //text_layer_set_text(s_time_layer, "00:00");
   
  text_layer_set_font(s_bat_layer, fonts_get_system_font(FONT_KEY_GOTHIC_14));
  text_layer_set_text_alignment(s_bat_layer, GTextAlignmentCenter);

  //windowレイヤーに子レイヤーとしてテキストレイヤーを追加
  layer_add_child(window_layer, text_layer_get_layer(s_bat_layer));
   
   //---------------------
   
   //タイマーサービスに分単位での更新を登録する。
   tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
   
   //バッテリー状態サービスに登録する
   battery_state_service_subscribe(battery_handler);
   //現在のバッテリーを読む
   battery_handler(battery_state_service_peek());
   
   //Bluetooth接続状態サービスに登録する
   connection_service_subscribe((ConnectionHandlers){
     .pebble_app_connection_handler = bt_handler
  });
}

//Windowが破棄された時
static void main_window_unload(Window *window) {
   //ビットマップデータを破棄
   gbitmap_destroy(s_background_bitmap);
   //ビットマップレイヤーを破棄
   bitmap_layer_destroy(s_background_layer);
   //テキストレイヤーを破棄
  text_layer_destroy(s_time_layer);
}

//Appの読み込み時
static void init() {
  //Windowエレメントを作成し、ポインタに割り付け
  s_main_window = window_create();

   //背景色を黒色に設定
   window_set_background_color(s_main_window, GColorCyan);

  //ウィンドウハンドラを割り付け
  window_set_window_handlers(s_main_window, (WindowHandlers){
    .load = main_window_load,
    .unload = main_window_unload
  });

  //スタックにプッシュし表示。アニメーション有効=true
  window_stack_push(s_main_window, true);
   //この時点でmain_window_loadが呼ばれる?
   
   //時刻を初期設定する。
   update_time();
}

static void deinit() {
  //ウィンドウを破棄
  window_destroy(s_main_window);
}

int main(void) {
  init();
  app_event_loop();
  deinit();
}

2016年1月11日月曜日

Pebble Time用日本語言語パック

twitterのリプライに表示不可文字が目立ったので、

Pebble language pack - 日本語言語パックさんにて、寄付をしていたのもあり、
Pebble Laboratory: 言語パック製作所を使ってみました。


設定は以下のとおり。


 で、これでも常用漢字の一部が抜けていたので、常用漢字とキャピキャピ系顔文字、2ch系顔文字、数学記号、罫線、事務系機種依存文字、ギリシャ記号を追加。


データサイズは1226KB。(Pebble Timeの推奨上限は1400KB)
すべてが適用できているわけではないようだが、概ね入ったようだ。
もしかすると、生成元のフォントにない文字が多いのかもしれない。


公開してもよいのかわからないが、上げておく。
サイズが大きいため、Pebble Timeが不安定になる可能性がある。よって利用を推奨はしない。



使用後、まだ不足している文字があることに気付いたので、
いっその事と思い、ShiftJISに含まれるほぼすべての文字を含めた言語パックも作成した。
1388KBと、かなりギリギリのサイズなので注意。

PebbleTimeJapanesShiftJISv2(Seg_faul).pbl

(ところで、これにtwitter頻出5000字を加えると100KBほど増えるのだが、一体どんな漢字が使われているのか...)


これを利用される方は、ぜひPebble language pack - 日本語言語パックさんにて、
寄付をして欲しい。

Ω・響・ω・㌢などが表示できていることがわかる。

2016年1月9日土曜日

Pebble使って1日目

Pebble使って1日目、使ってみてわかったこと。

・アニメーションかわいい。とにかくかわいい。

・設定は意外と細かくできる。

・iPhone(iOS)上でのPebble Timeアプリではフィルタリングができないが、
 これはApple Notification Center Serviceで送信しているため。
 なので、iOSの設定アプリから「通知センターに表示する」を無効にすると送信されず、
 有効にしていれば送信される、という挙動をするので、代用ができそうだ。

・画面は常に表示されてるので、光にかざせばはっきり見える。
 反射型液晶のため、角度に結構依存する。
 (腕時計になれた人なら無意識に見やすい角度を探すと思うので問題ないと思う)

・明るい室内なら特に問題ない。暗い室内なら、バックライト必須。
 (あまり良い比較ではないだろうが、劣化したG-SHOCKよりはよっぽど見やすい)

・バックライトは、腕を振るうと付いてくれるので、そんなに不便ではない。
 また、3段階および完全消灯が選べる。

・バッテリーは、1日中頻繁にいじってて10%減。
 ただし10%単位でしか表示されないので、15%くらいは減っているかもしれない。
 慣れてきて触る機会が減ればもっと持つようになるだろう。

・バイブレーションがかなり強力。
 通知やタイマーとかでバイブが動くが、気づかないことがありえないくらいには強い。
 これも3段階および無効が選べる。

・通知が腕で見れるのは結構幸せ。
 楽。かなり楽。スマートフォンを取り出さずに見れるこの感覚はぜひ味わってもらいたい。

・ショートカットキーが便利。
 時計画面にて、上ボタン長押しおよび、下ボタン長押しで、任意のアプリを起動するように
 設定できる。自分は、上ボタンに通知一覧、下ボタンにタイマーを設定している。
 メニューを開かずに操作ができるので便利。

・ボタンの押し心地が良い。
 押しづらかったり、堅かったりしないので、使いやすい。

・G-SHOCKの時、ボタンの押しにくさと、操作のわかりづらさ、耳が悪く音に気づかない等で
 アラームやタイマーを使わず、もっぱらiPhoneのタイマーを使っていたのだが、
 Pebbleにしてからはバイブで知らせてくれるし、操作はグラフィカルでわかりやすいしで
 Pebbleのタイマーを使っている。
 なにげにタイマーのためにiPhoneを取り出して操作するのはストレスだったのだと再認識。

・夜間モードがある。
 平日・休日に通知バイブを制限する・禁止する時間帯を設定できる。
 スマートフォン上の設定とは関係なしに動いてしまうために付いているのだろう。

・戻るボタン長押しでも夜間モードに入る。マナーモードと同等な感じ。

・スタンバイモードもある。
 30分間、腕の動きがないと睡眠中と判断して、Bluetoothを切断してバッテリーを温存する機能が
 あるようだ。ただ、自分は使っていないが。

・Pebbleのアプリは全て無料...ではない。
 →Pebbleのストア自体に課金機能はないが、複雑な機能を実現しているものの場合、
  スマートフォンに入れる方のコンパニオンアプリが有料なことが多い。(120\~500\くらい)
  極稀に、設定画面を管理するサーバーのほうで課金がかかる場合がある。

・サードパーティのアプリの中には、中途半端な奴も居る。
 Pebble Classicのみ対応のアプリもある。
 Pebble Timeでカラー表示できるように宣伝しておきながら、
 実は白黒しか出せない(しかも有料)というのもある。

・サードパーティのアプリで、設定画面がちゃんと出てこないことがある。
 数分待てば出てきたり、Wi-Fi切れば出てきたり。
 これは多分、設定画面を外部サーバーにおいている弊害だろう。

・IFTTTのレシピを検索してると、Pebbleに使うために作ったらしきレシピがよく出てくる。
 大抵、出力先がPushoverになっている。
 デバイスの通知を経由しないと送れないため。
 なら、IFTTTのアプリIFの通知機能を使えばいいと思うかもしれないが、
 あれはなぜかよく通知に失敗する。

 Pushoverは、500円買いきりの有料アプリで、HTTPSでRequest投げたり、
 メール送ったり、IFTTTで使ったりして、通知を飛ばせる優秀なアプリ。
 FlashAirでも使っているし、自宅サーバーでも使っているのだが、
 なにが優秀かというと、色々カスタマイズできる上に、しっかり通知してくれること。
 マルチデバイス対応で、マルチプラットフォーム対応なので、安心して使える。
  

 



スクリーンショット集

時計画面は 91 Dub v3.0 を使用。

色が予め用意されたテーマの他、自分で各色好きな色を好きな箇所に使える。

使ってみた結果、変に色が付いているより白黒な方が見やすいのと、
愛用のG-SHOCKに合わせてこういう風に設定。

余談だが、設定はiPhoneのPebble Timeアプリから行うのだが、
HTMLとjavascriptで設定画面が構築できるようだ。


公式ミュージックアプリ
安心してください。日本語対応ですよ。(フォント導入時)



Twebble
twitterを腕の上で。レスポンスは良くないが、とりあえず読める。
コンパニオンアプリと提携しているアプリは、日本語で落ちる事が多いのだが、
これはPebble上のみで動いているので問題なく動く。
Postもできるが、英語のみ。かなり特殊な入力スタイルで打ち込む。



MyNotes
非常にシンプルなメモ帳。
腕の上で読まなければならない短い文章を入れておける。
5ページまで入り、ボタンで切り替えられる。



Image Viewer
外部サーバーから画像を読み込んで表示する。
iPhoneをWi-Fiに接続していればLAN上のサーバーにもアクセス可能。
jpg/png/gifをデコード・減色して表示してくれる。画像サイズが多ければ縮小も。


HTTP REQUEST
名前の通り、リクエストを飛ばしてくれる。上下ボタンのワンタッチと、
中央ボタンから入るメニューに6個登録できる。
ただし、短いURLしか対応していないので注意。どのくらい短いかというと、
IFTTTのMaker chが使えないくらい。
作者スクショを見る限り、LAN内使用を目的としているようなので致し方無いか。



Smartwatch+
Pebbleをよりスマートウォッチ化してくれる有料アプリ。
iPhone上のアプリと提携して、天気情報、カメラ操作&表示(白黒)、
GPS現在位置の表示などができる。

こちらのHTTP Request機能は、長いURLでも対応している。
ただし、カレンダーやリマインダー機能は、日本語が含まれた項目があると落ちる。



Compass
無駄に本格的なコンパスアプリ。
Pebble内臓の電子コンパスを使うため、スマートフォンと接続が切れていてもOK。



Battery+
バッテリーモニタ。
かなり詳細な情報を出してくれる他、グラフなどもとってくれる。
グラフはスマートフォン上でも見れる。



Authenticator
いわゆるGoogle認証アプリと同等の働きをする、ワンタイムパスワード生成器。
便利そうなのだが、まだ使っていない。


設定画面の例
必要最小限のものから、Pebble本体と通信していろいろするものも。
本体と通信するものは、読み込みに時間が掛かる。
どれにせよ、設定画面は外部サーバーに置く仕様のようだ。
アプリ作者がサイトを閉鎖すれば、使えなくなるのだろう。(エミュ鯖でも建てないかぎり)
また、設定が悪いのか、キャリアネットワークでないと設定画面が出てこないものもある。


2016年1月8日金曜日

スマートウォッチのPebbleを買いました



大体の情報はネットにあるので、要点だけ書きます。

Android・iPhoneの両対応のスマートウォッチ。
日本で発売していないが、公式サイトは日本語対応で、技適も通っている。

メモリ液晶を使っており、充電無しで3日~7日は動くらしい。
Pebble Timeは64色のパレットカラーが使える。

日本語の表示がデフォではできないのだが、
韓国人の方が作成した日本語化パックを使うとシステムメニューも含め日本語化可能。

昔はAndroid端末からしか日本語化できなかったようだが、現在はiPhoneからでも日本語化可能。
(実際やりました)

スマートウォッチ上で動くアプリは、C言語とjavascriptの両方で可能。
→作ったMyWatchFace

スマートフォン上で動く自作のコンパニオンアプリと提携させられる他、
コンパニオンアプリもjavascriptで書いて実行することも可能。

開発環境は、PC上と、Webサイト上の両方があるが、Webサイト上のほうが便利
(アカウント作るだけでOKな上、実機で走らせることもできる。)

30m防水なので雨の中でも水中でも安心。(泳ぐのは非推奨ですが)

後ろの充電ポートはシリアルポートになっており、Arduino等のマイコンとの接続可能。

といったところでしょうか。
公式サイトで注文し、DHLで輸送。1/3日に注文し、1/8に到着しました。
年末年始だから遅いけれども、本来はもっと早い模様。
なんだかんだで合計3万円くらい。

公式サイトからの購入にこだわらなければ、Amazonの並行輸入版が2万円で買える模様。

腕時計上で、自分の好きな時計が使える感覚は、想像以上です。
メールを腕の上で確認できるのが素晴らしい。

まだ使い始めて数十分なので、使い慣れたらまた報告します。


2016年1月7日木曜日

FlashAiで、書き込まれた最新の1ファイルを自動でDropBoxにアップロードするスクリプト



デジカメをDropbox対応にしたり、ゲームフリークをDropbox対応にしたり、
ポメラをDropbox対応にしたり、いろいろ汎用的に使えます。
但し、フォルダ指定の変更をお忘れなく。

アップロードには30秒~60秒かかります。
もちろん、アップロード中に書き込まれたファイルはアップロードされません。
管理ファイルを用意すれば別ですが。

Dropbox API登録が必要です。手順はこちら(少し古いですが)

フォルダ・ファイル名に日本語や空白が含まれていると失敗する。
(別途対処が必要)

7/17追記
現在、"Error argument:c003fe09" が発生して動作しないのが確認されています。
殆どのHTTPSサイト接続時に起きるようで、原因は不明です。

-----------------dropbox_upload.lua---------------------

--150MBまでの最新のファイルを自動で探索しDropboxにアップロードするサンプル

--ファイルの書き込みをしないので安全。
--但し、書き込まれた時の特定フォルダ内最新1ファイルしかアップロードしない。

--捜索対象のフォルダ(空欄=root)
--末端に/を付けないこと。ファイル探索には成功するが、Dropbox側で怒られる
fpath = "/DCIM/101JVCSO";

--ここにアクセストークン。自分用のAPI登録をしたなら、Generated access tokenで生成できる。
--公式のサンプルのように、appKeyやappSecretを使っていろいろする必要はない。
token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

--アップロード先フォルダ
--App folder– Access to a single folder created specifically for your app.にしたなら、
--アプリフォルダ内にファイルができる。
--Full Dropbox– Access to all files and folders in a user's Dropbox.にしたなら
--自由に。ファイル破壊も発生するので注意。

--uploadDir="/someFolder"
uploadDir="";

--注意:CONFIGでIPアドレスを固定していると、接続してもやっぱり固定されているので色々失敗する。
--DHCP_Enabled=YESにすること。

--注意:STAモードもしくはBridgeモードにすること。
--        APPAUTOTIME=0とすること。(通信が切られかねないため)
--    LUA_SD_EVENT=/dropbox_upload.luaのようにすること。(このファイルをdrobpx_upload.luaにした場合)


--作業用変数
filename = "";

--プロセス開始

   sleep(6000); --ファイル書き込み待機(カメラや使う機器が書き込み終了するまでにかかる時間に合わせて変更する。)
 --ここを下手に短くすると、カメラがエラーを吐いたり、写真が破損したり、1つまえに撮影した画像がアップロードされたりする

--ファイル走査
--http://dotnsf.blog.jp/archives/2015-09-16.htmlより、最新のファイルを探す
last_filepath = ""
max_mod = 0
for filename in lfs.dir(fpath) do
filepath = fpath .. "/" .. filename
mod = lfs.attributes( filepath, "modification" )
if mod > max_mod then
max_mod = mod
last_filepath = filepath
end
end

--ファイルがなければ終了
if(last_filepath == "")then print("No file."); goto EXIT; end;

filename = last_filepath;

--アップロード処理開始

--ファイル本体をデータに
mes = "<!--WLANSDFILE-->";
--ファイルサイズを取得
len_s = lfs.attributes(filename,"size");

--アップロード先パス設定
uploadPath = uploadDir..filename;
--Dropbox引数(上書き・通知の有無)
dropboxArg = '{"path": "'.. uploadPath ..'","mode": "overwrite"}';

--ヘッダー情報
hed = {
["Content-Length"] = len_s,
["Authorization"] = "Bearer "..token,
["Dropbox-API-Arg"] = dropboxArg,
["Content-Type"] = "application/octet-stream"
};

  --
--リクエスト
b,c,h = fa.request{
url = "https://content.dropboxapi.com/2/files/upload",
method = "POST",
headers = hed,
body = mes,
file = filename,
bufsize=1460*10
};

--エラーが帰ってきたらファイルに保存する
if(c>200)then
f=io.open("res","w")
f:write(h)
f:write(b)
f:close();
  end

--ブラウザでのデバッグ用
print(dropboxArg);

print(c)
print(h)
print(b)

::EXIT::
--終了処理

2016年1月6日水曜日

FlashAirからfa.requestを投げる時の注意

FlashAirからfa.requestを投げる時の注意。

一言だけ。
「ブラウザからLua実行する場合は、Wi-Fiを弄るな」。

例えば以下の様なスクリプトがある場合、
これをブラウザ(およびFTLE)から実行すると、大抵はc = -1(fa.requestの実行失敗)になる。
たとえ、現在つないでいるWi-Fi APに接続しなおしたとしても、だ。

回避するには、
・ブラウザ(もしくはFTLE)から実行する場合は、Wi-Fi関係の操作をしない
・SDカードイベントもしくは、起動時実行から実行する

--Wi-FiアクセスポイントのSSID
ssid="FlashAir";
--Wi-Fiアクセスポイントのパスワード
networkkey="12345678";
--ここから
fa.Disconnect();
sleep(3000);
fa.Connect(ssid, networkkey);
sleep(15000);
--ここまでをコメントアウトすると動く。
b,c,h = fa.request("http://example.com/")
f = io.open("file.txt","w")
f:write(c);
f:close();

7/17追記
現在、かつて動いていたスクリプトが、"Error argument:c003fe09" が
発生して動作しないのが確認されています。
殆どのHTTPSサイト接続時に起きるようで、原因は不明です。

2016年1月5日火曜日

FlashAirからDropboxにアップロード"だけ"するスクリプト(公式サンプルより簡単)

--150MBまでのファイルをDropboxにアップロードするサンプル

--追記:送信バッファの設定をしない場合、大きなファイルはアップロードに失敗する
--(成功するがファイルが破損する)ため、公式サンプル同様の送信バッファ設定に修正しました。

--ここにアクセストークン。自分用のAPI登録をしたなら、Generated access tokenで生成できる。
--公式のサンプルのように、appKeyやappSecretを使っていろいろする必要はない。
token = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";

--アップロードしたいファイル名
filename = "/FlashTools.lua";

--アップロード先フォルダ
--App folder– Access to a single folder created specifically for your app.にしたなら、
--アプリフォルダ内にファイルができる。
--Full Dropbox– Access to all files and folders in a user's Dropbox.にしたなら
--自由に。ファイル破壊も発生するので注意。

--uploadDir="/someFolder"
uploadDir="";


--アップロード処理開始

   --ファイル本体をデータに
   mes = "<!--WLANSDFILE-->";
   --ファイルサイズを取得
   len_s = lfs.attributes(filename,"size");

   --アップロード先パス設定
   uploadPath = uploadDir..filename;
   --Dropbox引数(上書き・通知の有無)
   dropboxArg = '{"path": "'.. uploadPath ..'","mode": "overwrite"}';
   print(dropboxArg);


   --ヘッダー情報
   hed = {
      ["Content-Length"] = len_s,
      ["Authorization"] = "Bearer "..token,
      ["Dropbox-API-Arg"] = dropboxArg,
      ["Content-Type"] = "application/octet-stream"
   };

   --リクエスト
   b,c,h = fa.request{
      url = "https://content.dropboxapi.com/2/files/upload",
      method = "POST",
      headers = hed,
      body = mes,
      file = filename,
      bufsize=1460*10
   };

   --結果
   --c=400なら失敗。200なら成功。
   print(h);
   print(b);