├── .gitignore ├── README.md ├── SmartStatus.jpg ├── appinfo.json ├── resources ├── fonts │ ├── Google Android License.txt │ ├── Roboto-Bold.ttf │ └── Roboto-Condensed.ttf └── images │ ├── app_icon.png │ ├── background.png │ ├── battery.png │ ├── battery_pebble.png │ ├── battery_phone.png │ ├── battery_status.png │ ├── cloud.png │ ├── disconnect_large.png │ ├── fog.png │ ├── rain.png │ ├── snow.png │ ├── sun.png │ ├── sun_cloud.png │ ├── thunder.png │ └── wind.png ├── src ├── globals.h └── sm_watchapp.c └── wscript /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SmartStatus Watch App 2 | ===================== 3 | 4 | IMPORTANT: This is the version of SmartStatus that only works with the App Store version of Smartwatch+ 5 | 6 | The SmartStatus watch app only works in conjunction with the Smartwatch+ iOS app. [Smartwatch+](https://itunes.apple.com/us/app/smartwatch+-for-pebble/id711357931?ls=1&mt=8) is available on the Apple App Store. 7 | 8 | This code provides an example of how to communicate with Smartwatch+ and how to use status information from your iOS device within your own watch face or app. The status information that is currently available to you through Smartwatch+ is 9 | 10 | * Current weather 11 | * iPhone battery percentage 12 | * Currently playing song/artist 13 | * Next calendar appointment 14 | 15 | ![SmartStatus watchapp](https://raw.github.com/robhh/SmartStatus-AppStore/master/SmartStatus.jpg) -------------------------------------------------------------------------------- /SmartStatus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/SmartStatus.jpg -------------------------------------------------------------------------------- /appinfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "uuid": "fb5338d6-751c-4d4f-9074-70d4bad021a0", 3 | "shortName": "SmartStatus", 4 | "longName": "SmartStatus", 5 | "companyName": "Robert Hesse", 6 | "versionCode": 1, 7 | "versionLabel": "1.0.0", 8 | "watchapp": { 9 | "watchface": false 10 | }, 11 | "appKeys": { 12 | "dummy": 0 13 | }, 14 | "resources": { 15 | "media": [ 16 | { 17 | "type": "png", 18 | "name": "IMAGE_MENU_ICON", 19 | "file": "images/app_icon.png", 20 | "menuIcon": true 21 | }, 22 | { 23 | "type": "png", 24 | "name": "IMAGE_BACKGROUND", 25 | "file": "images/background.png" 26 | }, 27 | { 28 | "type": "png", 29 | "name": "IMAGE_DISCONNECT", 30 | "file": "images/disconnect_large.png" 31 | }, 32 | { 33 | "type": "png", 34 | "name": "IMAGE_SUN", 35 | "file": "images/sun.png" 36 | }, 37 | { 38 | "type": "png", 39 | "name": "IMAGE_RAIN", 40 | "file": "images/rain.png" 41 | }, 42 | { 43 | "type": "png", 44 | "name": "IMAGE_CLOUD", 45 | "file": "images/cloud.png" 46 | }, 47 | { 48 | "type": "png", 49 | "name": "IMAGE_SUN_CLOUD", 50 | "file": "images/sun_cloud.png" 51 | } 52 | , 53 | { 54 | "type": "png", 55 | "name": "IMAGE_WIND", 56 | "file": "images/wind.png" 57 | } 58 | , 59 | { 60 | "type": "png", 61 | "name": "IMAGE_FOG", 62 | "file": "images/fog.png" 63 | } 64 | , 65 | { 66 | "type": "png", 67 | "name": "IMAGE_SNOW", 68 | "file": "images/snow.png" 69 | } 70 | , 71 | { 72 | "type": "png", 73 | "name": "IMAGE_THUNDER", 74 | "file": "images/thunder.png" 75 | } 76 | , 77 | { 78 | "type": "png", 79 | "name": "IMAGE_BATTERY", 80 | "file": "images/battery.png" 81 | } 82 | , 83 | { 84 | "type": "png", 85 | "name": "IMAGE_BATTERY_PHONE", 86 | "file": "images/battery_phone.png" 87 | } 88 | , 89 | { 90 | "type": "png", 91 | "name": "IMAGE_BATTERY_PEBBLE", 92 | "file": "images/battery_pebble.png" 93 | } 94 | , 95 | 96 | { 97 | "type": "font", 98 | "name": "FONT_ROBOTO_CONDENSED_21", 99 | "file": "fonts/Roboto-Condensed.ttf" 100 | }, 101 | 102 | { 103 | "type": "font", 104 | "characterRegex": "[:0-9]", 105 | "name": "FONT_ROBOTO_BOLD_SUBSET_49", 106 | "file": "fonts/Roboto-Bold.ttf" 107 | } 108 | ] } 109 | } 110 | -------------------------------------------------------------------------------- /resources/fonts/Google Android License.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2008 The Android Open Source Project 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | ########## 16 | 17 | This directory contains the fonts for the platform. They are licensed 18 | under the Apache 2 license. 19 | -------------------------------------------------------------------------------- /resources/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /resources/fonts/Roboto-Condensed.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/fonts/Roboto-Condensed.ttf -------------------------------------------------------------------------------- /resources/images/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/app_icon.png -------------------------------------------------------------------------------- /resources/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/background.png -------------------------------------------------------------------------------- /resources/images/battery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/battery.png -------------------------------------------------------------------------------- /resources/images/battery_pebble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/battery_pebble.png -------------------------------------------------------------------------------- /resources/images/battery_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/battery_phone.png -------------------------------------------------------------------------------- /resources/images/battery_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/battery_status.png -------------------------------------------------------------------------------- /resources/images/cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/cloud.png -------------------------------------------------------------------------------- /resources/images/disconnect_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/disconnect_large.png -------------------------------------------------------------------------------- /resources/images/fog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/fog.png -------------------------------------------------------------------------------- /resources/images/rain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/rain.png -------------------------------------------------------------------------------- /resources/images/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/snow.png -------------------------------------------------------------------------------- /resources/images/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/sun.png -------------------------------------------------------------------------------- /resources/images/sun_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/sun_cloud.png -------------------------------------------------------------------------------- /resources/images/thunder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/thunder.png -------------------------------------------------------------------------------- /resources/images/wind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robhh/SmartStatus-AppStore/e265e2272dbd4013997fda6554736644204d95d8/resources/images/wind.png -------------------------------------------------------------------------------- /src/globals.h: -------------------------------------------------------------------------------- 1 | #ifndef _globals_h 2 | #define _globals_h 3 | 4 | #define SM_RECONNECT_KEY 0xFC01 5 | #define SM_SEQUENCE_NUMBER_KEY 0xFC02 6 | #define SM_OPEN_SIRI_KEY 0xFC03 7 | #define SM_STATUS_SCREEN_REQ_KEY 0xFC04 8 | #define SM_PLAYPAUSE_KEY 0xFC05 9 | #define SM_NEXT_TRACK_KEY 0xFC06 10 | #define SM_PREVIOUS_TRACK_KEY 0xFC07 11 | #define SM_VOLUME_UP_KEY 0xFC08 12 | #define SM_VOLUME_DOWN_KEY 0xFC09 13 | #define SM_COUNT_MAIL_KEY 0xFC0A 14 | #define SM_COUNT_SMS_KEY 0xFC0B 15 | #define SM_COUNT_PHONE_KEY 0xFC0C 16 | #define SM_COUNT_BATTERY_KEY 0xFC0D 17 | #define SM_SCREEN_ENTER_KEY 0xFC0E 18 | #define SM_SCREEN_EXIT_KEY 0xFC0F 19 | #define SM_WEATHER_COND_KEY 0xFC10 20 | #define SM_WEATHER_TEMP_KEY 0xFC11 21 | #define SM_WEATHER_ICON_KEY 0xFC12 22 | #define SM_STATUS_SCREEN_UPDATE_KEY 0xFC13 23 | #define SM_VOLUME_VALUE_KEY 0xFC14 24 | #define SM_PLAY_STATUS_KEY 0xFC15 25 | #define SM_ARTIST_KEY 0xFC16 26 | #define SM_ALBUM_KEY 0xFC17 27 | #define SM_TITLE_KEY 0xFC18 28 | #define SM_WEATHER_HUMID_KEY 0xFC19 29 | #define SM_WEATHER_WIND_KEY 0xFC1A 30 | #define SM_WEATHER_DAY1_KEY 0xFC1B 31 | #define SM_WEATHER_DAY2_KEY 0xFC1C 32 | #define SM_WEATHER_DAY3_KEY 0xFC1D 33 | #define SM_WEATHER_ICON1_KEY 0xFC1E 34 | #define SM_WEATHER_ICON2_KEY 0xFC1F 35 | #define SM_WEATHER_ICON3_KEY 0xFC20 36 | #define SM_CALENDAR_UPDATE_KEY 0xFC21 37 | #define SM_MENU_UPDATE_KEY 0xFC22 38 | #define SM_STOCKS_GRAPH_KEY 0xFC23 39 | #define SM_BITCOIN_GRAPH_KEY 0xFC24 40 | #define SM_BITCOIN_LOW_KEY 0xFC25 41 | #define SM_BITCOIN_HIGH_KEY 0xFC26 42 | #define SM_BITCOIN_CURR_KEY 0xFC27 43 | #define SM_BITCOIN_TITLE_KEY 0xFC28 44 | #define SM_STOCKS_LOW_KEY 0xFC29 45 | #define SM_STOCKS_HIGH_KEY 0xFC2A 46 | #define SM_STOCKS_CURR_KEY 0xFC2B 47 | #define SM_STOCKS_TITLE_KEY 0xFC2C 48 | #define SM_LAUNCH_CAMERA_KEY 0xFC2D 49 | #define SM_TAKE_PICTURE_KEY 0xFC2E 50 | #define SM_URL1_KEY 0xFC2F 51 | #define SM_URL2_KEY 0xFC30 52 | #define SM_URL1_TEXT_KEY 0xFC31 53 | #define SM_URL2_TEXT_KEY 0xFC32 54 | #define SM_GPS_1_KEY 0xFC33 55 | #define SM_GPS_2_KEY 0xFC34 56 | #define SM_GPS_3_KEY 0xFC35 57 | #define SM_GPS_4_KEY 0xFC36 58 | #define SM_RESET_DST_KEY 0xFC37 59 | #define SM_MESSAGES_UPDATE_KEY 0xFC38 60 | #define SM_CALLS_UPDATE_KEY 0xFC38 61 | #define SM_CAL_DETAILS_KEY 0xFC39 62 | #define SM_DETAILS1_KEY 0xFC3A 63 | #define SM_DETAILS2_KEY 0xFC3B 64 | #define SM_CALL_SMS_KEY 0xFC3C 65 | #define SM_CALL_SMS_UPDATE_KEY 0xFC3D 66 | #define SM_CALL_SMS_CMD_KEY 0xFC3E 67 | #define SM_SMS_SENT_KEY 0xFC3F 68 | #define SM_FIND_MY_PHONE_KEY 0xFC40 69 | #define SM_REMINDERS_KEY 0xFC41 70 | #define SM_REMINDERS_DETAILS_KEY 0xFC42 71 | #define SM_STATUS_CAL_TIME_KEY 0xFC43 72 | #define SM_STATUS_CAL_TEXT_KEY 0xFC44 73 | #define SM_STATUS_MUS_ARTIST_KEY 0xFC45 74 | #define SM_STATUS_MUS_TITLE_KEY 0xFC46 75 | #define SM_UPDATE_INTERVAL_KEY 0xFC47 76 | #define SM_SONG_LENGTH_KEY 0xFC48 77 | #define SM_STATUS_UPD_WEATHER_KEY 0xFC49 78 | #define SM_STATUS_UPD_CAL_KEY 0xFC4A 79 | #define SM_NAV_ICON_KEY 0xFC4B 80 | #define SM_NAV_INSTRUCTIONS_KEY 0xFC4C 81 | #define SM_STREAMING_BMP_KEY 0xFC4D 82 | #define SM_CANVAS_DICT_KEY 0xFC4E 83 | 84 | 85 | 86 | #define STATUS_SCREEN_APP NUM_APPS 87 | 88 | typedef enum {CALENDAR_APP, MUSIC_APP, GPS_APP, STOCKS_APP, BITCOIN_APP, CAMERA_APP, WEATHER_APP, URL_APP, FINDPHONE_APP, REMINDERS_APP, STATUS_SCREEN_APP} AppIDs; 89 | 90 | static char *app_names[] = {"Calendar", "Music", "GPS", "Stocks", "Bitcoin", "Camera", "Weather", "HTTP Request", "Find My Phone", "Reminders"}; 91 | 92 | 93 | #endif 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/sm_watchapp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "globals.h" 3 | 4 | #define STRING_LENGTH 255 5 | #define NUM_WEATHER_IMAGES 9 6 | 7 | enum {CALENDAR_LAYER, MUSIC_LAYER, NUM_LAYERS}; 8 | 9 | static void reset(); 10 | 11 | static Window *window; 12 | static TextLayer *text_layer; 13 | 14 | static PropertyAnimation *ani_out, *ani_in; 15 | 16 | static Layer *animated_layer[NUM_LAYERS], *weather_layer; 17 | static Layer *battery_layer, *battery_pbl_layer; 18 | 19 | static TextLayer *text_date_layer, *text_time_layer; 20 | 21 | static TextLayer *text_weather_cond_layer, *text_weather_temp_layer, *text_battery_layer; 22 | static TextLayer *calendar_date_layer, *calendar_text_layer; 23 | static TextLayer *music_artist_layer, *music_song_layer; 24 | 25 | static BitmapLayer *background_image, *weather_image, *battery_image_layer, *battery_pbl_image_layer; 26 | 27 | static int active_layer; 28 | 29 | static char string_buffer[STRING_LENGTH]; 30 | static char weather_cond_str[STRING_LENGTH], weather_temp_str[5]; 31 | static int weather_img, batteryPercent, batteryPblPercent; 32 | 33 | static char calendar_date_str[STRING_LENGTH], calendar_text_str[STRING_LENGTH]; 34 | static char music_artist_str1[STRING_LENGTH], music_title_str1[STRING_LENGTH]; 35 | 36 | 37 | GBitmap *bg_image, *battery_image, *battery_pbl_image; 38 | GBitmap *weather_status_imgs[NUM_WEATHER_IMAGES]; 39 | 40 | static AppTimer *timerUpdateCalendar = NULL; 41 | static AppTimer *timerUpdateWeather = NULL; 42 | static AppTimer *timerUpdateMusic = NULL; 43 | 44 | 45 | 46 | const int WEATHER_IMG_IDS[] = { 47 | RESOURCE_ID_IMAGE_SUN, 48 | RESOURCE_ID_IMAGE_RAIN, 49 | RESOURCE_ID_IMAGE_CLOUD, 50 | RESOURCE_ID_IMAGE_SUN_CLOUD, 51 | RESOURCE_ID_IMAGE_FOG, 52 | RESOURCE_ID_IMAGE_WIND, 53 | RESOURCE_ID_IMAGE_SNOW, 54 | RESOURCE_ID_IMAGE_THUNDER, 55 | RESOURCE_ID_IMAGE_DISCONNECT 56 | }; 57 | 58 | 59 | 60 | 61 | static uint32_t s_sequence_number = 0xFFFFFFFE; 62 | 63 | AppMessageResult sm_message_out_get(DictionaryIterator **iter_out) { 64 | AppMessageResult result = app_message_outbox_begin(iter_out); 65 | if(result != APP_MSG_OK) return result; 66 | dict_write_int32(*iter_out, SM_SEQUENCE_NUMBER_KEY, ++s_sequence_number); 67 | if(s_sequence_number == 0xFFFFFFFF) { 68 | s_sequence_number = 1; 69 | } 70 | return APP_MSG_OK; 71 | } 72 | 73 | void reset_sequence_number() { 74 | DictionaryIterator *iter = NULL; 75 | app_message_outbox_begin(&iter); 76 | if(!iter) return; 77 | dict_write_int32(iter, SM_SEQUENCE_NUMBER_KEY, 0xFFFFFFFF); 78 | app_message_outbox_send(); 79 | } 80 | 81 | 82 | void sendCommand(int key) { 83 | DictionaryIterator* iterout; 84 | sm_message_out_get(&iterout); 85 | if(!iterout) return; 86 | 87 | dict_write_int8(iterout, key, -1); 88 | app_message_outbox_send(); 89 | } 90 | 91 | 92 | void sendCommandInt(int key, int param) { 93 | DictionaryIterator* iterout; 94 | sm_message_out_get(&iterout); 95 | if(!iterout) return; 96 | 97 | dict_write_int8(iterout, key, param); 98 | app_message_outbox_send(); 99 | } 100 | 101 | 102 | 103 | 104 | 105 | static void select_click_down_handler(ClickRecognizerRef recognizer, void *context) { 106 | //show the weather condition instead of temperature while center button is pressed 107 | layer_set_hidden(text_layer_get_layer(text_weather_temp_layer), true); 108 | layer_set_hidden(text_layer_get_layer(text_weather_cond_layer), false); 109 | } 110 | 111 | static void select_click_up_handler(ClickRecognizerRef recognizer, void *context) { 112 | //revert to showing the temperature 113 | layer_set_hidden(text_layer_get_layer(text_weather_temp_layer), false); 114 | layer_set_hidden(text_layer_get_layer(text_weather_cond_layer), true); 115 | } 116 | 117 | 118 | static void up_click_handler(ClickRecognizerRef recognizer, void *context) { 119 | //update all data 120 | reset(); 121 | 122 | sendCommandInt(SM_SCREEN_ENTER_KEY, STATUS_SCREEN_APP); 123 | } 124 | 125 | static void down_click_handler(ClickRecognizerRef recognizer, void *context) { 126 | //slide layers in/out 127 | 128 | property_animation_destroy((PropertyAnimation*)ani_in); 129 | property_animation_destroy((PropertyAnimation*)ani_out); 130 | 131 | 132 | ani_out = property_animation_create_layer_frame(animated_layer[active_layer], &GRect(0, 124, 143, 45), &GRect(-138, 124, 143, 45)); 133 | animation_schedule((Animation*)ani_out); 134 | 135 | 136 | active_layer = (active_layer + 1) % (NUM_LAYERS); 137 | 138 | ani_in = property_animation_create_layer_frame(animated_layer[active_layer], &GRect(138, 124, 144, 45), &GRect(0, 124, 144, 45)); 139 | animation_schedule((Animation*)ani_in); 140 | 141 | 142 | } 143 | 144 | static void click_config_provider(void *context) { 145 | window_raw_click_subscribe(BUTTON_ID_SELECT, select_click_down_handler, select_click_up_handler, context); 146 | window_single_click_subscribe(BUTTON_ID_UP, up_click_handler); 147 | window_single_click_subscribe(BUTTON_ID_DOWN, down_click_handler); 148 | } 149 | 150 | static void window_load(Window *window) { 151 | Layer *window_layer = window_get_root_layer(window); 152 | GRect bounds = layer_get_bounds(window_layer); 153 | 154 | } 155 | 156 | static void window_unload(Window *window) { 157 | 158 | 159 | } 160 | 161 | static void window_appear(Window *window) 162 | { 163 | sendCommandInt(SM_SCREEN_ENTER_KEY, STATUS_SCREEN_APP); 164 | 165 | } 166 | 167 | 168 | static void window_disappear(Window *window) 169 | { 170 | sendCommandInt(SM_SCREEN_EXIT_KEY, STATUS_SCREEN_APP); 171 | 172 | /* 173 | app_timer_cancel_event(g_app_context, timerUpdateCalendar); 174 | app_timer_cancel_event(g_app_context, timerUpdateMusic); 175 | app_timer_cancel_event(g_app_context, timerUpdateWeather); 176 | */ 177 | } 178 | 179 | 180 | void battery_layer_update_callback(Layer *me, GContext* ctx) { 181 | 182 | //draw the remaining battery percentage 183 | graphics_context_set_stroke_color(ctx, GColorBlack); 184 | graphics_context_set_fill_color(ctx, GColorWhite); 185 | 186 | graphics_fill_rect(ctx, GRect(2+16-(int)((batteryPercent/100.0)*16.0), 2, (int)((batteryPercent/100.0)*16.0), 8), 0, GCornerNone); 187 | 188 | } 189 | 190 | void battery_pbl_layer_update_callback(Layer *me, GContext* ctx) { 191 | 192 | //draw the remaining pebble battery percentage 193 | graphics_context_set_stroke_color(ctx, GColorBlack); 194 | graphics_context_set_fill_color(ctx, GColorWhite); 195 | 196 | graphics_fill_rect(ctx, GRect(2+16-(int)((batteryPblPercent/100.0)*16.0), 2, (int)((batteryPblPercent/100.0)*16.0), 8), 0, GCornerNone); 197 | 198 | } 199 | 200 | 201 | void reset() { 202 | 203 | layer_set_hidden(text_layer_get_layer(text_weather_temp_layer), true); 204 | layer_set_hidden(text_layer_get_layer(text_weather_cond_layer), false); 205 | text_layer_set_text(text_weather_cond_layer, "Updating..."); 206 | 207 | } 208 | 209 | 210 | void handle_minute_tick(struct tm *tick_time, TimeUnits units_changed) { 211 | // Need to be static because they're used by the system later. 212 | static char time_text[] = "00:00"; 213 | static char date_text[] = "Xxxxxxxxx 00"; 214 | 215 | char *time_format; 216 | 217 | 218 | // TODO: Only update the date when it's changed. 219 | strftime(date_text, sizeof(date_text), "%a, %b %e", tick_time); 220 | text_layer_set_text(text_date_layer, date_text); 221 | 222 | 223 | if (clock_is_24h_style()) { 224 | time_format = "%R"; 225 | } else { 226 | time_format = "%I:%M"; 227 | } 228 | 229 | strftime(time_text, sizeof(time_text), time_format, tick_time); 230 | 231 | // Kludge to handle lack of non-padded hour format string 232 | // for twelve hour clock. 233 | if (!clock_is_24h_style() && (time_text[0] == '0')) { 234 | memmove(time_text, &time_text[1], sizeof(time_text) - 1); 235 | } 236 | 237 | text_layer_set_text(text_time_layer, time_text); 238 | } 239 | 240 | 241 | void reconnect(void *data) { 242 | reset(); 243 | 244 | sendCommandInt(SM_SCREEN_ENTER_KEY, STATUS_SCREEN_APP); 245 | 246 | } 247 | 248 | void bluetoothChanged(bool connected) { 249 | 250 | if (connected) { 251 | app_timer_register(5000, reconnect, NULL); 252 | } else { 253 | bitmap_layer_set_bitmap(weather_image, weather_status_imgs[NUM_WEATHER_IMAGES-1]); 254 | vibes_double_pulse(); 255 | } 256 | 257 | } 258 | 259 | 260 | void batteryChanged(BatteryChargeState batt) { 261 | 262 | batteryPblPercent = batt.charge_percent; 263 | layer_mark_dirty(battery_layer); 264 | 265 | } 266 | 267 | 268 | static void init(void) { 269 | window = window_create(); 270 | window_set_fullscreen(window, true); 271 | window_set_click_config_provider(window, click_config_provider); 272 | window_set_window_handlers(window, (WindowHandlers) { 273 | .load = window_load, 274 | .unload = window_unload, 275 | .appear = window_appear, 276 | .disappear = window_disappear 277 | }); 278 | const bool animated = true; 279 | window_stack_push(window, animated); 280 | 281 | //init weather images 282 | for (int i=0; ivalue->cstring, strlen(t->value->cstring)); 533 | weather_cond_str[strlen(t->value->cstring)] = '\0'; 534 | text_layer_set_text(text_weather_cond_layer, weather_cond_str); 535 | } 536 | 537 | t=dict_find(received, SM_WEATHER_TEMP_KEY); 538 | if (t!=NULL) { 539 | memcpy(weather_temp_str, t->value->cstring, strlen(t->value->cstring)); 540 | weather_temp_str[strlen(t->value->cstring)] = '\0'; 541 | text_layer_set_text(text_weather_temp_layer, weather_temp_str); 542 | 543 | layer_set_hidden(text_layer_get_layer(text_weather_cond_layer), true); 544 | layer_set_hidden(text_layer_get_layer(text_weather_temp_layer), false); 545 | 546 | } 547 | 548 | t=dict_find(received, SM_WEATHER_ICON_KEY); 549 | if (t!=NULL) { 550 | bitmap_layer_set_bitmap(weather_image, weather_status_imgs[t->value->uint8]); 551 | } 552 | 553 | t=dict_find(received, SM_COUNT_BATTERY_KEY); 554 | if (t!=NULL) { 555 | batteryPercent = t->value->uint8; 556 | layer_mark_dirty(battery_layer); 557 | snprintf(string_buffer, sizeof(string_buffer), "%d", batteryPercent); 558 | text_layer_set_text(text_battery_layer, string_buffer ); 559 | } 560 | 561 | t=dict_find(received, SM_STATUS_CAL_TIME_KEY); 562 | if (t!=NULL) { 563 | memcpy(calendar_date_str, t->value->cstring, strlen(t->value->cstring)); 564 | calendar_date_str[strlen(t->value->cstring)] = '\0'; 565 | text_layer_set_text(calendar_date_layer, calendar_date_str); 566 | } 567 | 568 | t=dict_find(received, SM_STATUS_CAL_TEXT_KEY); 569 | if (t!=NULL) { 570 | memcpy(calendar_text_str, t->value->cstring, strlen(t->value->cstring)); 571 | calendar_text_str[strlen(t->value->cstring)] = '\0'; 572 | text_layer_set_text(calendar_text_layer, calendar_text_str); 573 | } 574 | 575 | 576 | t=dict_find(received, SM_STATUS_MUS_ARTIST_KEY); 577 | if (t!=NULL) { 578 | memcpy(music_artist_str1, t->value->cstring, strlen(t->value->cstring)); 579 | 580 | music_artist_str1[strlen(t->value->cstring)] = '\0'; 581 | text_layer_set_text(music_artist_layer, music_artist_str1); 582 | } 583 | 584 | t=dict_find(received, SM_STATUS_MUS_TITLE_KEY); 585 | if (t!=NULL) { 586 | memcpy(music_title_str1, t->value->cstring, strlen(t->value->cstring)); 587 | 588 | music_title_str1[strlen(t->value->cstring)] = '\0'; 589 | text_layer_set_text(music_song_layer, music_title_str1); 590 | } 591 | 592 | 593 | t=dict_find(received, SM_STATUS_UPD_WEATHER_KEY); 594 | if (t!=NULL) { 595 | int interval = t->value->int32 * 1000; 596 | 597 | if (timerUpdateWeather != NULL) 598 | app_timer_cancel(timerUpdateWeather); 599 | timerUpdateWeather = app_timer_register(interval , updateWeather, NULL); 600 | } 601 | 602 | t=dict_find(received, SM_STATUS_UPD_CAL_KEY); 603 | if (t!=NULL) { 604 | int interval = t->value->int32 * 1000; 605 | 606 | if (timerUpdateCalendar != NULL) 607 | app_timer_cancel(timerUpdateCalendar); 608 | timerUpdateCalendar = app_timer_register(interval , updateCalendar, NULL); 609 | } 610 | 611 | t=dict_find(received, SM_SONG_LENGTH_KEY); 612 | if (t!=NULL) { 613 | int interval = t->value->int32 * 1000; 614 | 615 | if (timerUpdateMusic != NULL) 616 | app_timer_cancel(timerUpdateMusic); 617 | timerUpdateMusic = app_timer_register(interval , updateMusic, NULL); 618 | 619 | } 620 | 621 | } 622 | 623 | int main(void) { 624 | app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum() ); 625 | app_message_register_inbox_received(rcv); 626 | 627 | init(); 628 | 629 | 630 | app_event_loop(); 631 | app_message_deregister_callbacks(); 632 | 633 | deinit(); 634 | 635 | } 636 | -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # This file is the default set of rules to compile a Pebble project. 4 | # 5 | # Feel free to customize this to your needs. 6 | # 7 | 8 | top = '.' 9 | out = 'build' 10 | 11 | def options(ctx): 12 | ctx.load('pebble_sdk') 13 | 14 | def configure(ctx): 15 | ctx.load('pebble_sdk') 16 | 17 | def build(ctx): 18 | ctx.load('pebble_sdk') 19 | 20 | ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'), 21 | target='pebble-app.elf') 22 | 23 | ctx.pbl_bundle(elf='pebble-app.elf', 24 | js=ctx.path.ant_glob('src/js/**/*.js')) 25 | --------------------------------------------------------------------------------