銀の弾丸、はじめました

Unityとかガジェットとか

BLEデバイス(Peripheral)のUUID一覧を取得する

iOS Objective-C のメモ

// セントラル
@property (nonatomic, strong) CBCentralManager *centralManager;
// ペリフェラル
@property (nonatomic, strong) CBPeripheral *peripheral;
@property (nonatomic) NSMutableArray *peripherals;
@end

NSMutableArray *a_peripheral;
NSString * const ServiceUUID = @"XXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX";

@implementation PeripheralTableViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSLog(@"PeripheralTableViewController - viwDidLoad");

    self.peripherals = [NSMutableArray array];  // データ用
    a_peripheral = [NSMutableArray array];      // 文字列用

    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self
                                                               queue:nil];
    self.serviceUUID = [CBUUID UUIDWithString:ServiceUUID];
    self.characteristicUUID = [CBUUID UUIDWithString:CharacteristicUUIDHeartRateMeasurement];
}


// セントラルマネージャ状態が変化
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {

    NSLog(@"Updated state: %ld", (long)central.state);

    switch (central.state) {
        case CBCentralManagerStatePoweredOn:
        {
            // スキャン開始
            NSArray *services = @[self.serviceUUID];
            [self.centralManager scanForPeripheralsWithServices:services
                                                        options:nil];
            break;
        }
        default:
            break;
    }
}

// ペリフェラル発見
- (void)   centralManager:(CBCentralManager *)central
    didDiscoverPeripheral:(CBPeripheral *)peripheral
        advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
    NSLog(@"peripheral:%@, advertisementData:%@, RSSI:%@",
          peripheral, advertisementData, RSSI);

    // 単数の場合は以下で良いが,
    //self.peripheral = peripheral;
    // 複数のPeripheral取得には配列に格納する必要がある
    // strong属性の配列(NSMutableArray)に保持
    if (![self.peripherals containsObject:peripheral]) {
        NSLog(@"peripheral.identifier : %@", peripheral.identifier);

        [self.peripherals addObject:peripheral.identifier];

        // <__NSConcreteUUID 0x15e85410> 1174BF05-3D9A-2AD4-40D8-8A35E4D74A4A
        // <__NSConcreteUUID 0x15e8a1c0> 20B403AA-24E0-C70A-48A6-62BD9F40A1E3
        NSString *source = [NSString stringWithFormat:@"%@", peripheral.identifier];

        NSString *pattern = @"(^<.*> )";
        NSString *replacement = @"";

        NSRegularExpression *regexp = [NSRegularExpression
                                       regularExpressionWithPattern:pattern
                                       options:NSRegularExpressionCaseInsensitive
                                       error:nil
                                       ];

        NSString *str = [regexp
                         stringByReplacingMatchesInString:source
                         options:NSMatchingReportProgress
                         range:NSMakeRange(0, source.length)
                         withTemplate:replacement
                         ];
        NSLog(@"これがPeripheralのUUIDだ!!! : %@",  str);

        [a_peripheral addObject:str];

        NSLog(@"self.peripherals -> %@", self.peripherals);
        NSLog(@"a_peripheral -> %@", a_peripheral);
        NSLog(@"self.peripherals count : %d", [self.peripherals count]);
        NSLog(@"a_peripheral count : %d", [a_peripheral count]);
    }

    // スキャン停止
    //[self.centralManager stopScan];

    // 接続開始
    //[central connectPeripheral:peripheral options:nil];
}

加工した文字列用の配列を用意したのは,生のまま出力すると以下の用になってしまうため

(結果1)

self.peripherals -> (
    "<__NSConcreteUUID 0x15e85410> 1174BF05-3D9A-2AD4-40D8-8A35E4D74A4A",
    "<__NSConcreteUUID 0x15e8a1c0> 20B403AA-24E0-C70A-48A6-62BD9F40A1E3"
)

<__NSConcreteUUID 0x15e8a1c0>  の部分が不要で,気持ち悪いので
別途文字列にして加工してUUIDのみ配列に入れてる.

(結果2)

a_peripheral -> (
    "1174BF05-3D9A-2AD4-40D8-8A35E4D74A4A",
    "20B403AA-24E0-C70A-48A6-62BD9F40A1E3"
)

追記(2015/12/04)

どうやら,文字列操作しなくてもUUIDのNSStringを取得できるらしい…

[peripheral.identifier UUIDString]

stackoverflow.com

参考文献

iOS×BLE Core Bluetoothプログラミング

iOS×BLE Core Bluetoothプログラミング

Pebble.jsによる色の指定(色一覧)

Pebble.js の色一覧

 
色の指定は以下の Color Name を指定する.
大文字(アッパーケース),小文字(ローケース)も区別するので注意が必要です.
現在(2015/10/03)Pebble.jsによる色の指定方法がまとまったドキュメントが公式サイトにすらないので,コードを元にまとめました.
(永久保存版かもw)
 
* white, clearWhiteの違いはよく分かりません.
 
 
clear
* clearはPebble Classicだと白,Pebble Timeだと黒になると思います.
black
 
oxfordBlue
 
dukeBlue
 
blue
 
darkGreen
 
midnightGreen
 
cobaltBlue
 
blueMoon
 
islamicGreen
 
jaegerGreen
 
tiffanyBlue
 
vividCerulean
 
green
 
malachite
 
mediumSpringGreen
 
cyan
 
bulgarianRose
 
imperialPurple
 
indigo
 
electricUltramarine
 
armyGreen
 
darkGray
 
liberty
 
veryLightBlue
 
kellyGreen
 
mayGreen
 
cadetBlue
 
pictonBlue
 
brightGreen
 
screaminGreen
 
mediumAquamarine
 
electricBlue
 
darkCandyAppleRed
 
jazzberryJam
 
purple
 
vividViolet
 
windsorTan
 
roseVale
 
purpureus
 
lavenderIndigo
 
limerick
 
brass
 
lightGray
 
babyBlueEyes
 
springBud
 
inchworm
 
mintGreen
 
celeste
 
red
 
folly
 
fashionMagenta
 
magenta
 
orange
 
sunsetOrange
 
brilliantRose
 
shockingPink
 
chromeYellow
 
rajah
 
melon
 
richBrilliantLavender
 
yellow
 
icterine
 
pastelYellow
 
white
 
clearWhite
 
 

Sample

// sample_code.js
var textField = new UI.Text({
  position: new Vector2(18,55),
  size: new Vector2(144, 168),
  font: 'gothic-28',
  backgroundColor: 'oxfordBlue',
  color: 'lightGray',
  textOverflow:'wrap',
  text: 'Hello world.'
});
 

参考サイト

 
 
 

Pebbleアプリ公開時メモ

Pebbleアプリ(Watchapp,Watchface)をストア公開する際のメモ

Pebbleアプリの登録は Developerサイト から行う.

Watchapp公開時に必要なモノ

  • pbwファイル
  • 144x144のpngファイル(多分,PebbleApp Storeサイト用)
  • 48x48のpngファイル(多分,スマフォのPebbleアプリ内表示用)
  • 144x168のpngかアニメーションgifファイル(画面ショット1〜5枚)
  • ヘッダ用イメージファイル720x320 png
  • バナー用イメージファイル(任意)720x320 png(ヘッダと同じのでもいいと思う)

Watchface公開時に必要なモノ

  • pbwファイル
  • 144x168のpngかアニメーションgifファイル(画面ショット1〜5枚)
  • バナー用イメージファイル(任意)720x320 png

Watchfaceの場合は上記の他に,pbwファイル生成前(ビルド前)に28x28のpngファイルをリソース画像として追加する必要がある.(28x27とかでも大丈夫)

CloudPebbleだと,まず RESOURCES で画像を ADD NEW で追加して, Settings -> MENU IMAGE で追加した画像を選択してからビルドすればpbwに画像(アイコン)が内包される.

この画像はWatchfaceアプリの一覧(リスト)の左側に表示されるアイコンになる.

f:id:japanetfutan:20150923143222p:plain

アプリ公開時注意点

Timeline使わないのにTimelineの項目の enable timeline を押してしまうともうだめですw

削除して1からアップロードし直さないとダメっぽい…

f:id:japanetfutan:20150923143224p:plain

Timeline使う予定ないのに,このボタン押したら最後…って言う仕様…
(それのせいで作り直した…)

Pebble.jsについてメモ

ドキュメントはここ.

developer.getpebble.com

実は結構,やれる事少ない…と言うか単純.
でも,ドキュメントが色々と省略されてて色々試行錯誤の連続だった(今も)
なので,メモを残しておく.

Pebble.js使う上で必ず宣言するやつ.

var UI = require('ui');
var Vector2 = require('vector2');  //条件によってはここ不要

親オブジェクトについて

WatchFaceアプリの場合は UI.Window を使い,通常のアプリの場合は UI.Window か UI.Card を使う感じ.
WatchFaceでは Card UI は使えない.(現在は使えるようです.)

var window = new UI.Window();

// または,以下のような感じ

var main = new UI.Card({
   title: 'Pebble.js',
   icon: 'images/menu_icon.png',
   subtitle: 'Hello World!',
   body: 'Press any button.'
 });

Accel(加速度センサ)について

必須コード

var Accel = require(‘ui/accel');
Accel.init()

加速度確認には2種類の方法がある.

Tap系

Accel.on('tap', function(e){
  console.log('Tap event on axis: ' + e.axis + ' and direction: ' + e.direction);
});

または

Window.or('accelTap', function(e){
  console.log('Tapped the window');
});

上記2種はWinodwを対象にしているかそれ以外(Cardとか?)を対象にTapのイベントトリガを設置するイメージ.

Tapとは叩くイメージがあるが,ここでは加速度が反応する行為(腕,手首を素早く振るなど)とする.
Tapイベントトリガは省電力.

Accel.on

常に加速度センサを監視して情報を取得するイメージ.

Accel.on('data', function(e) {
  console.log('Just received ' + e.samples + ' from the accelerometer.');
});

または

window.on('accelData', function(e) {
 console.log('Accel data: ' + JSON.stringify(e.accels));
});

ミリ秒単位で3軸データを取得する事も可能.
電池消費量は激しいがより細かいデータを収集できる.

また,加速度の反応する基準を Accel.config() で指定する事が可能.
(特定の座標以上の時,特定の動きの時にイベントを走らせるなどの事が可能)


その他いろいろ微妙に苦労した点

Windowフルスクリーン

var window = new UI.Window();
window.fullscree(true);

これで上部バー(hh:mm)部が非表示になり,座標全体が上にズレる!

setTimeout

n秒後にxxさせたい時に使う.

通常のJSの場合

function hogehoge(){
  console.log('hogehoge');
}

setTimeout('hogehoge()', 3000);

となるが,Pebble.jsの場合は以下のように書く必要がある.
メソッドとして外出しできないっぽい…(文字列として書く必要もない…てか書いたらエラー)

Pebble.jsの場合

setTimeout(function(){
  console.log('hogehoge');
}, 3000);

Ajax

必須コード

var ajax = require('ajax');

JSはデフォルト非同期なので色々躓く部分があるが, async オプション false で簡単に同期処理解決できる.

ajax(
    {
      url: URL,
      type: 'json',
      async: false
    },
    function(data) {
      // Success!
      console.log('Successfully fetched weather data!');

      // Extract data
      var location = data.name;
      var temperature = Math.round(data.main.temp - 273.15) + 'C';

      // Always upper-case first letter of description
      var description = data.weather[0].description;
      description = description.charAt(0).toUpperCase() + description.substring(1);

      var date = new Date();
      var hour = date.getHours();
      var minutes = date.getMinutes();
      textField.text(location + ', ' + temperature + '\n' + description + '\n\n' + hour + ':' + minutes);

    },
    function(error) {
      // Failure!
      console.log('Failed fetching weather data: ' + error);

      return error;
    }
  );

font,colorなどの指定方法について

色のサンプル,名前は以下で確認できる.

developer.getpebble.com

Pebble.jsで色指定する際の特徴

  • キャメルケースっぽい.
  • 色の(フォント名も)スペースは詰める.
  • 意味が変わる部分の間は - (ハイフン)を挟む.

* 残念ながら現状ではCSSのように16進数表記の指定ができない.

(ラッパー作ったら需要ありそう,存在しない色は近似値的な色にする的な)

var textField = new UI.Text({
  position: new Vector2(18,55),
  size: new Vector2(144, 168),
  //font: 'gothic-28-bold',
  font: 'gothic-28',
  backgroundColor: 'black',
  color: 'lightGray',
  textOverflow:'wrap',
  //textAlign:'center',
  text: ''
});

デフォルトのシステムフォント

以下は公式のサンプルコード.

github.com

ただし,数値のみしかないフォントも多い.
デザイン重視のアプリはカスタムフォント必須かも.

色について

Pebble C の場合 APLINEBASALT で色を分けないとAPLINE で BUILD ERRORになる.
(APLITEの画面表示は2値なので白か黒以外の色の指定は出来ない)
しかし, Pebble.js の場合, BASALT 向けに lightGray と書いても APLINE で勝手に白になる.便利!

whiteを指定した場合の結果(左が APLINE で右が BASALT
f:id:japanetfutan:20150918162852p:plain f:id:japanetfutan:20150918162854p:plain

lightGrayを指定した場合の結果(左が APLINE で右が BASALT
f:id:japanetfutan:20150918162848p:plain f:id:japanetfutan:20150918162850p:plain


自動で lightGraywhite になっているのが確認できる.

Pebble.jsで使う色一覧を別エントリーにまとめました.

dvorak.hatenablog.com

memo.

APLITE : Pebble Classic,Pebble Watch
BASALT : Pebble Time

Settings(設定・コンフィグ周りの処理)

var Settings = require('settings');
  • Settings.config で設定画面への遷移,戻って来た(設定画面閉じた)時の処理を記述できる
  • 設定画面からの戻りの処理(鯖のWeb)はPebble CのJSと同様, pebblejs://close# な感じ

developer.getpebble.com

何か,勝手にオプション更新してくれる

指定した設定用ページのURLに対して

以下のオプションを勝手に付与してくれる(実際以下は「"{}」も含め,エンコードされてる)
?#{"start":null,"end":null}

デコードして,Hashの頭の # を消して, JSON.parse(HASH_DATA) するとJSONデータとしてサーバー側で扱える.

var h = decodeURIComponent(document.location.hash).substr(1);
//alert(h);
h=JSON.parse(h);
Pebble.js側は本当に勝手に色々やってくれるので,サーバー側でKeyとValueをセットする部分さえ作ればいい.

仕組みとしては,設定にstartとendと言う項目があったとして,
Pebble.js側は何もしなくても勝手にデータを上書きして更新してくれる.
(機能としてはJSのlocalStorageを使っている)

* 初回アクセス時にエラーになるので当然,宣言,初期化は必要.

サーバー側htmlでUIWebを閉じる際に 'pebblejs:close#'+encodeURIComponent(JSON.stringify({start:'value1', end:'value2'})); となっていれば,
あとはPebble.jsが勝手にKeyとValueを保存してくれる.

var options = {start:'value1, end:'value2'};
var location_uri = "pebblejs://close#" + encodeURIComponent(JSON.stringify(options));
document.location = location_uri;

次(2回目以降)に設定htmlを開く際にもPebble.js側は何もする必要がなく,設定ファイルを開くだけでいい.
(勝手に保存されているlocalStorageのKeyとValueを全てJSON StringにエンコードしてURLの語尾に付与する.)

この勝手にURL語尾に付与する部分とか最初気付かなくて色々悩んでた…Pebble.jsさん勝手にやり過ぎてて困る…
凄いんだけど,もっとDocumentにちゃんと記載してくれよ(;・∀・)

Settings.option

データの保存は内部的にJSのlocalStorageの上位層?に作られてるっぽい.
Settings.option を使ってるパラメータの保存,削除などを行う.

 Settings.data

Settings.option に影響させない(パラメータ以外のデータ?)については,
Settings.data を使う.(ネイティブJSのlocalStorageよりも Settings.dataの利用を推奨している)


まとめ的な

ググるとPebble C で Watchfaceアプリ作る的な情報が多い.
Pebble.jsはWebフロントエンドエンジニアやJS触れるデザイナーにも扱えるので是非挑戦して欲しいと思いました.
CloudPebble 使えばエミュレータIDEも込みなので0円で,ブラウザのみでアプリがJavaScriptで作れちゃいます.
Pebble.js自体はまだ一応βですが,最初の「何だかよく分からない」部分がボトルネックになってると思うので,そこを少しでも取り払えたらな,と思いました.

CloudPebbleについてメモ

CloudPebbleはちょっとクセのあるブラウザIDE

CloudPebble

凄く便利な部分もあるけど,ちょっとダメな部分もある.
ハマった部分などをメモっておく.

SETTINGS

項目名 内容
USES LOCATION 位置情報を使う場合,ONチェック
CONFIGURABLE 設定を使う場合.ONチェックするとアプリにギアマーク付く.

Ctrl(Command) + F で検索

使い難い!
現状だとコード長くなるとちょっとつらいですね.

Ctrl(Command) + S で保存できるけど…

なんと実行のショートカットキーがない.
なので Ctrl(Command) + R で実行できるGoogle Chrome Extensions書いた.

github.com

ただ,よく事故ってページ更新になってしまう…Alt + Rとかに置き換えようか…

TIMELINE(PREVIEW)って??

デフォルトでサンプルコード(JSON)が書かれてるだけ.
TIMELINE機能を使わない場合意味はない.

エミュレータは共通

ブラウザの別タブで別PROJECTを開いていてもエミュレータは共通に動いてしまう.
(別ブラウザを使ってもエミュレータは共通になる…IP単位?)

エミュレータで加速度を使う

SDK3.4 から使えるようになった.
母艦のスマフォでエミュレーションする.
Pebble本体がなくてもPebble単体アプリであれば,全ての機能がエミュレータで開発・デバッグできるようになった.
(設定画面の確認レベルでエミュレーションできる…設定値反映は無理っぽい?)

昔のPebble Watchもエミュレータで動かせる

COMPILATIONEMULATOR で BUILD後に INSTALL ON APLITE で実行できる.
INSTALL ON BASALT はPebble Timeのエミュレータになる.

* ただし,アプリの設定でAPLITEにも対応させる必要がある.
  SETTINGSBUILD APLITE にONチェック.
  更にコードでも処理を分ける必要がある…

f:id:japanetfutan:20150914110156p:plain

  Pebble.js の場合,ここを意識する必要はない(項目自体がない)


CloudPebbleの挙動がおかしい時

  • ブラウザのタブ閉じて新規タブから開き直す.
  • iOSのPebbleTiemアプリで開発中のアプリを実行前に削除
  • iOSのPebbleTimeアプリのDEVELOPER(ON) ->  Enable Developer Connections を一旦 OFF にして直ぐ ON

上記3つは結構使った…WatchFaceアプリだと頻発し易かった印象を受ける.


CloudPebbleのビルド,インストール,実行とかのまとめ

SETTINGSを変更した場合,1度 RUN BUILD してから INSTALL AND RUN する必要がある!

INSTALL AND RUN ができるのはコード部分のみ)

先にBUILD!!

と,言うか,普通にコード変更してもまずはビルド.
エディタ画面の実行ボタンが特殊で1ボタンだけで 保存 -> ビルド -> インストール -> 実行 している.

Pebble Timeのプリインストールアプリ「Watchfaces」の仕様

Pebble Timeのプリインストールアプリ Watchfaces

インストール済みのWatchfaceが一覧でリスト表示され,そこから選択する事でWatchfaceを変更する事ができます.

が,

Watchfaceの名前が長いと「...」で(Ellipsis)語尾が潰されてしまいます.

この名前の部分,実はCloudPebbleで言う,SETTINGSLONG APP NAME の部分なので,全文表示させたいなら Long Name も短くした方がいいです.
f:id:japanetfutan:20150912160427p:plain

はみ出た部分は「...」表記になる.

f:id:japanetfutan:20150912160425p:plain

多分,Max 12文字.

Pebble Timeの液晶について

国内外問わずいつでも何処でも何度でも議論されるのでまとめてみる.

E InkでもE paperでもない

「反射型メモリ液晶」が正解.
しかしながら公式も(!) E paper display と表記している.
マーケティング的にごっちゃに使われてきたが正確にはメモリ液晶はE paper display(電子ペーパー)ではない.

が,既にメモリ液晶は電子ペーパーだ!とする派も多い…
(立体投影が全てホログラムみたいに呼ばれてしまっているのと同様の現状)

E Inkではないので当然,バッテリーが切れたら画面は消え何も映らない.

反射型メモリ液晶

直射日光下でも見辛くなるなんて事はなく,むしろよく見えるようになる.
通常の液晶に比べ超省電力性がある.

E Inkパネルと違いリフレッシュが早いのでゲーム,アニメーション用途にも使い易い.

Pebble Watchで使用されているメモリ液晶 LS013B7DH05SHARP製)
Sharp Memory LCDs: Ultra-low power, high performance, and long life…with memory in every pixel

Pebble Timeで使用されているメモリ液晶 LPM014T262C (Japan Display製)
* PDF注意

http://www.j-display.com/product/pdf/LPM014T262C_v1.pdf

液晶の更新について

Pebbleの液晶は1ピクセル更新するのに,その行全てを更新する方式.
1ピクセルが真横に移動するアニメーションは1行(144px)だけの更新で済むが,縦移動になると移動したピクセル数(行数) x 列数(144px)の分のピクセル更新が走る.

省電力

反射型メモリ液晶はE Inkとは異なるので画面の切替時は勿論のこと,

静止画表示状態でもバッテリーを消費する

ただし,消費電力は極めて低い.

ディスプレイから話はそれるが極論で言えば,
Pebble Timeが充電されていない状態ならば,例え電源を切っていても自然放電されるのでバッテリーは消費する.