あむちょです。
つねに自分の余命を表示する嫌な時計を作ってみた。
目次
Pebble Timeってなんですかって人はこちら。丸型スマートウォッチPebble Time Roundのレビュー
今回は、webと連携、データをローカルに保存、カスタムバイブパターンってのをやってみました。
今回も角形と丸型の両方に対応
Watch Face 「Expectancy」
上二行が残りの余命で、
年-月-日
時:分:秒
現在時刻
を表示してます。
寿命計算は、設定画面から質問に答えると計算されます。
気が向いたら日本語化させます。計算方法はこちらを参考にしました。寿命計算.com
寿命が表示させると心臓の鼓動っぽく2回バイブレーションします。
こちらからダウンロードできます。Pebble Time Watch Face 「Expectancy」
ソースコード
設定画面からサイトにアクセスし、寿命と誕生日のデータをJsonで受け取ってjsを使ってPebble本体にメッセージを送ってます。
おくられてきたデータはローカルに保存して、次に表示する時にも使います。
まずはC言語ファイル
#include #define NUM_EXPECT_PKEY 1 #define NUM_EXPECT_MON_PKEY 2 #define NUM_EXPECT_DAY_PKEY 3 #define NUM_EXPECT_DEFAULT -1 #define NUM_EXPECT_MON_DEFAULT 7 #define NUM_EXPECT_DAY_DEFAULT 6 #define KEY_EXPECT 0 #define KEY_BR_MON 1 #define KEY_BR_DAY 2 static Window *window; static TextLayer *text_much0; static TextLayer *text_much1; static TextLayer *text_now; static TextLayer *text_config; static int expect = NUM_EXPECT_DEFAULT; static int br_mon = NUM_EXPECT_MON_DEFAULT; static int br_day = NUM_EXPECT_DAY_DEFAULT; #if defined(PBL_RECT) #define DEL_Y (180-168)/2 #elif defined(PBL_ROUND) #define DEL_Y 0 #endif static void in_recv_handler(DictionaryIterator *iter, void *context){ Tuple *exp_t = dict_find(iter, KEY_EXPECT); Tuple *exp_m = dict_find(iter, KEY_BR_MON); Tuple *exp_d = dict_find(iter, KEY_BR_DAY); expect = exp_t->value->int16; persist_write_int(NUM_EXPECT_PKEY, expect); br_mon = exp_m->value->int8; persist_write_int(NUM_EXPECT_MON_PKEY, br_mon); br_day = exp_d->value->int8; persist_write_int(NUM_EXPECT_DAY_PKEY, br_day); layer_set_hidden(text_layer_get_layer(text_much0),false); layer_set_hidden(text_layer_get_layer(text_much1),false); layer_set_hidden(text_layer_get_layer(text_config),true); static const uint32_t const segments[] = { 200, 100, 150, 1000 ,200, 100, 150}; VibePattern pat = { .durations = segments, .num_segments = ARRAY_LENGTH(segments), }; vibes_enqueue_custom_pattern(pat); } static void handle_second_tick(struct tm *tick_time, TimeUnits units_changed){ static char timeMuch0[] = "2032-12-02"; static char timeMuch1[] = "00:00:00"; static char timeNow[] = "00:00:00"; if(expect != -1){ int year = expect-(tick_time->tm_year+1900); int month = tick_time->tm_mon+1; int day = tick_time->tm_mday; int hour = 24-tick_time->tm_hour; int min = 60-tick_time->tm_min; int sec = 60-tick_time->tm_sec; day = br_day-day; if(day < 0){ day += 31; month++; } month = br_mon-month; if(month < 0){ month += 12; year--; } char y[] = "123"; if(year < 10){ snprintf(y,sizeof(y),"0%d",year); } else{ snprintf(y,sizeof(y),"%d",year); } char m[] = "23"; if(month < 10){ snprintf(m,sizeof(m),"0%d",month); } else{ snprintf(m,sizeof(m),"%d",month); } char d[] = "12"; if(day < 10){ snprintf(d,sizeof(d),"0%d",day); } else{ snprintf(d,sizeof(d),"%d",day); } char h[] = "12"; if(hour < 10){ snprintf(h,sizeof(h),"0%d",hour); } else{ snprintf(h,sizeof(h),"%d",hour); } char mi[] = "23"; if(min < 10){ snprintf(mi,sizeof(mi),"0%d",min); } else{ snprintf(mi,sizeof(mi),"%d",min); } char s[] = "23"; if(sec < 10){ snprintf(s,sizeof(s),"0%d",sec); } else{ snprintf(s,sizeof(s),"%d",sec); } snprintf(timeMuch0,sizeof(timeMuch0),"%s-%s-%s",y,m,d); snprintf(timeMuch1,sizeof(timeMuch1),"%s:%s:%s",h,mi,s); text_layer_set_text(text_much0, timeMuch0); text_layer_set_text(text_much1, timeMuch1); } strftime(timeNow, sizeof(timeNow), "%H:%M:%S", tick_time); text_layer_set_text(text_now, timeNow); } static void window_load(Window *window) { Layer *window_layer = window_get_root_layer(window); GRect bounds = layer_get_bounds(window_layer); //expect hight text_much0 = text_layer_create((GRect) { .origin = { 0, 25-DEL_Y }, .size = { bounds.size.w, 28 } }); text_layer_set_text_alignment(text_much0, GTextAlignmentCenter); text_layer_set_background_color(text_much0, GColorClear); text_layer_set_text_color(text_much0, GColorWhite); text_layer_set_font(text_much0, fonts_get_system_font(FONT_KEY_LECO_26_BOLD_NUMBERS_AM_PM)); layer_add_child(window_layer, text_layer_get_layer(text_much0)); layer_set_hidden(text_layer_get_layer(text_much0),true); //expect low text_much1 = text_layer_create((GRect) { .origin = { 0, 90-20-DEL_Y }, .size = { bounds.size.w, 28 } }); text_layer_set_text_alignment(text_much1, GTextAlignmentCenter); text_layer_set_background_color(text_much1, GColorClear); text_layer_set_text_color(text_much1, GColorWhite); text_layer_set_font(text_much1, fonts_get_system_font(FONT_KEY_LECO_26_BOLD_NUMBERS_AM_PM)); layer_add_child(window_layer, text_layer_get_layer(text_much1)); layer_set_hidden(text_layer_get_layer(text_much1),true); //config text_config = text_layer_create((GRect) { .origin = { 0, 25-DEL_Y }, .size = { bounds.size.w, 28*3 } }); text_layer_set_text(text_config, "Check\nSetting"); text_layer_set_text_alignment(text_config, GTextAlignmentCenter); text_layer_set_background_color(text_config, GColorClear); text_layer_set_text_color(text_config, GColorWhite); text_layer_set_font(text_config, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD)); layer_add_child(window_layer, text_layer_get_layer(text_config)); //now text_now = text_layer_create((GRect) { .origin = { 0, 120-DEL_Y }, .size = { bounds.size.w, 28 } }); text_layer_set_text_alignment(text_now, GTextAlignmentCenter); text_layer_set_background_color(text_now, GColorClear); text_layer_set_text_color(text_now, GColorWhite); text_layer_set_font(text_now, fonts_get_system_font(FONT_KEY_LECO_26_BOLD_NUMBERS_AM_PM)); layer_add_child(window_layer, text_layer_get_layer(text_now)); if(expect != -1){ layer_set_hidden(text_layer_get_layer(text_much0),false); layer_set_hidden(text_layer_get_layer(text_much1),false); layer_set_hidden(text_layer_get_layer(text_config),true); } app_message_register_inbox_received((AppMessageInboxReceived) in_recv_handler); app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum()); } static void window_unload(Window *window) { text_layer_destroy(text_much0); text_layer_destroy(text_much1); text_layer_destroy(text_config); text_layer_destroy(text_now); } static void init(void) { expect = persist_exists(NUM_EXPECT_PKEY) ? persist_read_int(NUM_EXPECT_PKEY) : NUM_EXPECT_DEFAULT; br_mon = persist_exists(NUM_EXPECT_MON_PKEY) ? persist_read_int(NUM_EXPECT_MON_PKEY) : NUM_EXPECT_MON_DEFAULT; br_day = persist_exists(NUM_EXPECT_DAY_PKEY) ? persist_read_int(NUM_EXPECT_DAY_PKEY) : NUM_EXPECT_DAY_DEFAULT; window = window_create(); window_set_background_color(window, GColorBlack); window_set_window_handlers(window, (WindowHandlers) { .load = window_load, .unload = window_unload, }); window_stack_push(window, true); tick_timer_service_subscribe(SECOND_UNIT, &handle_second_tick); static const uint32_t const segments[] = { 200, 100, 150, 1000 ,200, 100, 150}; VibePattern pat = { .durations = segments, .num_segments = ARRAY_LENGTH(segments), }; vibes_enqueue_custom_pattern(pat); } static void deinit(void) { tick_timer_service_unsubscribe(); window_destroy(window); } int main(void) { init(); app_event_loop(); deinit(); }
ローカルのデータは
#define NUM_EXPECT_PKEY 1 #define NUM_EXPECT_MON_PKEY 2 #define NUM_EXPECT_DAY_PKEY 3 #define NUM_EXPECT_DEFAULT -1 #define NUM_EXPECT_MON_DEFAULT 7 #define NUM_EXPECT_DAY_DEFAULT 6 expect = persist_exists(NUM_EXPECT_PKEY) ? persist_read_int(NUM_EXPECT_PKEY) : NUM_EXPECT_DEFAULT; br_mon = persist_exists(NUM_EXPECT_MON_PKEY) ? persist_read_int(NUM_EXPECT_MON_PKEY) : NUM_EXPECT_MON_DEFAULT; br_day = persist_exists(NUM_EXPECT_DAY_PKEY) ? persist_read_int(NUM_EXPECT_DAY_PKEY) : NUM_EXPECT_DAY_DEFAULT;
でデータを取り出してなかったらデフォルト値を設定します。データ書き込みは
persist_write_int(NUM_EXPECT_PKEY, expect);
です。ともに任意のKEYを設定する必要があります。
カスタムバイブパターンは
static const uint32_t const segments[] = { 200, 100, 150, 1000 ,200, 100, 150}; VibePattern pat = { .durations = segments, .num_segments = ARRAY_LENGTH(segments), }; vibes_enqueue_custom_pattern(pat);
配列にOn時間とOff時間のパターンをいれるだけです。
次にスマホ本体とやりとりするためのjsファイル
Pebble.addEventListener("ready", function(e) { console.log("connect!" + e.ready); getLocation(); console.log(e.type); }); Pebble.addEventListener("appmessage", function(e) { console.log(e.type); console.log(e.payload.temperature); console.log("message!"); }); Pebble.addEventListener("webviewclosed", function(e) { console.log("webview closed"); console.log(e.type); console.log(e.response); var configuration = JSON.parse(decodeURIComponent(e.response)); var dict = {}; dict['KEY_EXPECT'] = configuration['expect']; dict['KEY_BR_MON'] = configuration['br_mon']; dict['KEY_BR_DAY'] = configuration['br_day']; Pebble.sendAppMessage(dict, function() { console.log('Send successful: ' + JSON.stringify(dict)); }, function() { console.log('Send failed!'); }); }); Pebble.addEventListener('showConfiguration', function(e) { Pebble.openURL('http://fieldwalking.jp/pebble/expectancy/'); });
お次は設定画面のhtmlはここから直接みておくれsetting
設定画面のUIはslateってのを使ってます。GitHub slate
外人さんは優しい
何個かリリースしてみて、たまに外人さんからお褒めのメールが届きます。
アプリの時もそうだけど、彼らは感謝のメールとか送ってくるのでやるきがでますね。
ただ、
バグに対する文句のメールも送ってくる
[ad][ad]