You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
8.6 KiB

9 years ago
  1. #include <pebble.h>
  2. #include <inttypes.h>
  3. #include "pebble_utils.h"
  4. #define KEY_TEMPERATURE 0
  5. #define KEY_CONDITIONS 1
  6. #define KEY_ROOM_TEMP 2
  7. #define WEATHER_TIME 0
  8. // Function signatures
  9. static void update_time();
  10. static void tick_handler(struct tm *tick_time, TimeUnits units_changed);
  11. static void main_window_load(Window *window);
  12. static void main_window_unload(Window *window);
  13. static void init();
  14. static void deinit();
  15. static void inbox_received_callback(DictionaryIterator *iterator, void *context);
  16. static void inbox_dropped_callback(AppMessageResult reason, void *context);
  17. static void outbox_failed_callback(DictionaryIterator *iterator, AppMessageResult reason, void *context);
  18. static void outbox_sent_callback(DictionaryIterator *iterator, void *context);
  19. // Global variables
  20. static Window *s_main_window;
  21. static TextLayer *s_time_layer;
  22. static TextLayer *s_weather_layer;
  23. static TextLayer *s_room_layer;
  24. static TextLayer *s_daymonth_layer;
  25. static GFont s_time_font;
  26. static GFont s_weather_font;
  27. static GFont s_date_font;
  28. static BitmapLayer *s_background_layer;
  29. static GBitmap *s_background_bitmap;
  30. int main(void) {
  31. init();
  32. app_event_loop();
  33. deinit();
  34. }
  35. static void update_time() {
  36. // Get a tm structure
  37. const time_t temp = time(NULL);
  38. const struct tm *tick_time = localtime(&temp);
  39. // Create a long-lived buffer
  40. static char buffer[] = "00:00";
  41. // Write the current hours and minutes into the buffer
  42. if (clock_is_24h_style()) {
  43. // Use 24 hour format
  44. strftime(buffer, sizeof(buffer), "%H:%M", tick_time);
  45. } else {
  46. // Use 12 hour format
  47. strftime(buffer, sizeof(buffer), "%I:%M", tick_time);
  48. }
  49. // Display this time on the TextLayer
  50. text_layer_set_text(s_time_layer, buffer);
  51. }
  52. static void update_date() {
  53. // Get a tm structure
  54. const time_t temp = time(NULL);
  55. const struct tm *tick_time = localtime(&temp);
  56. // Create a long-lived buffer
  57. static char buffer_daymonth[] = "00.000";
  58. // Write the current hours and minutes into the buffer
  59. strftime(buffer_daymonth, sizeof(buffer_daymonth), "%e.%b", tick_time);
  60. // Display this time on the TextLayer
  61. text_layer_set_text(s_daymonth_layer, buffer_daymonth);
  62. }
  63. static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
  64. update_time();
  65. if (units_changed & DAY_UNIT) {
  66. update_date();
  67. }
  68. if (persist_exists(WEATHER_TIME)) {
  69. (void) persist_delete(WEATHER_TIME);
  70. }
  71. // Get weather update every 30 minutes
  72. if (tick_time->tm_min % 30 == 0) {
  73. // Begin dictionary
  74. DictionaryIterator *iter;
  75. app_message_outbox_begin(&iter);
  76. // Add a key-value pair
  77. dict_write_value(iter, 0, (uint8_t)0);
  78. // Send the message!
  79. app_message_outbox_send();
  80. }
  81. }
  82. static void inbox_received_callback(DictionaryIterator *iterator, void *context) {
  83. // Store incoming information
  84. static char temperature_buffer[8];
  85. static char conditions_buffer[32];
  86. static char room_buffer[32];
  87. static char weather_layer_buffer[32];
  88. bool got_weather = false;
  89. bool got_room = false;
  90. // Read first item
  91. Tuple *t = dict_read_first(iterator);
  92. // For all items
  93. while(t != NULL) {
  94. // Which key was received?
  95. switch(t->key) {
  96. case KEY_TEMPERATURE:
  97. snprintf(temperature_buffer, sizeof(temperature_buffer), "%d", (int)t->value->int32);
  98. break;
  99. case KEY_CONDITIONS:
  100. snprintf(conditions_buffer, sizeof(conditions_buffer), "%s", t->value->cstring);
  101. got_weather = true;
  102. break;
  103. case KEY_ROOM_TEMP:
  104. snprintf(room_buffer, sizeof(room_buffer), "%s", t->value->cstring);
  105. got_room = true;
  106. break;
  107. default:
  108. APP_LOG(APP_LOG_LEVEL_ERROR, "Key %d not recognized!", (int)t->key);
  109. break;
  110. }
  111. // Look for next item
  112. t = dict_read_next(iterator);
  113. }
  114. // Assemble full string and display
  115. if (got_weather) {
  116. snprintf(weather_layer_buffer, sizeof(weather_layer_buffer), "%s°C, %s", temperature_buffer, conditions_buffer);
  117. text_layer_set_text(s_weather_layer, weather_layer_buffer);
  118. }
  119. if (got_room) {
  120. text_layer_set_text(s_room_layer, room_buffer);
  121. }
  122. }
  123. static void inbox_dropped_callback(AppMessageResult reason, void *context) {
  124. APP_LOG(APP_LOG_LEVEL_ERROR, "Message dropped!");
  125. }
  126. static void outbox_failed_callback(DictionaryIterator *iterator, AppMessageResult reason, void *context) {
  127. APP_LOG(APP_LOG_LEVEL_ERROR, "Outbox send failed!");
  128. }
  129. static void outbox_sent_callback(DictionaryIterator *iterator, void *context) {
  130. APP_LOG(APP_LOG_LEVEL_INFO, "Outbox send success!");
  131. }
  132. static void main_window_load(Window *window) {
  133. // Create GBitmap, then set to created BitmapLayer
  134. s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_TUTORIAL_BACKGROUND);
  135. s_background_layer = bitmap_layer_create(GRect(0, 0, 144, 168));
  136. bitmap_layer_set_bitmap(s_background_layer, s_background_bitmap);
  137. // Create time TextLayer
  138. s_time_layer = text_layer_create(GRect(5, 52, 139, 50));
  139. text_layer_set_background_color(s_time_layer, GColorClear);
  140. text_layer_set_text_color(s_time_layer, GColorBlack);
  141. // Create temperature Layer
  142. s_weather_layer = text_layer_create(GRect(0, 130, 144, 20));
  143. text_layer_set_background_color(s_weather_layer, GColorClear);
  144. text_layer_set_text_color(s_weather_layer, GColorWhite);
  145. text_layer_set_text(s_weather_layer, "Loading...");
  146. // Create room temperature Layer
  147. s_room_layer = text_layer_create(GRect(0, 150, 144, 20));
  148. text_layer_set_background_color(s_room_layer, GColorClear);
  149. text_layer_set_text_color(s_room_layer, GColorWhite);
  150. text_layer_set_text(s_room_layer, "Loading...");
  151. // Create day-month TextLayer
  152. s_daymonth_layer = text_layer_create(GRect(5, 12, 139, 30));
  153. text_layer_set_background_color(s_daymonth_layer, GColorBlack);
  154. text_layer_set_text_color(s_daymonth_layer, GColorWhite);
  155. // Create GFont
  156. s_time_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_PERFECT_DOS_48));
  157. s_weather_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_PERFECT_DOS_16));
  158. s_date_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_PERFECT_DOS_24));
  159. // Apply to TextLayer
  160. text_layer_set_font(s_time_layer, s_time_font);
  161. text_layer_set_font(s_weather_layer, s_weather_font);
  162. text_layer_set_font(s_room_layer, s_weather_font);
  163. text_layer_set_font(s_daymonth_layer, s_date_font);
  164. // Improve the layout to be more like a watchface
  165. text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
  166. text_layer_set_text_alignment(s_weather_layer, GTextAlignmentCenter);
  167. text_layer_set_text_alignment(s_room_layer, GTextAlignmentCenter);
  168. text_layer_set_text_alignment(s_daymonth_layer, GTextAlignmentCenter);
  169. // Add it as a child layer to the Window's root layer
  170. layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(s_background_layer));
  171. layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_time_layer));
  172. layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_weather_layer));
  173. layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_room_layer));
  174. layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_daymonth_layer));
  175. }
  176. static void main_window_unload(Window *window) {
  177. // Destroy TextLayer
  178. text_layer_destroy(s_time_layer);
  179. text_layer_destroy(s_weather_layer);
  180. text_layer_destroy(s_room_layer);
  181. text_layer_destroy(s_daymonth_layer);
  182. // Unload GFont
  183. fonts_unload_custom_font(s_time_font);
  184. fonts_unload_custom_font(s_weather_font);
  185. fonts_unload_custom_font(s_date_font);
  186. // Destroy GBitmap
  187. gbitmap_destroy(s_background_bitmap);
  188. // Destroy BitmapLayer
  189. bitmap_layer_destroy(s_background_layer);
  190. }
  191. static void init() {
  192. // Create main Window element and assign to pointer
  193. s_main_window = window_create();
  194. // Set handlers to manage the elements inside the Window
  195. window_set_window_handlers(s_main_window, (WindowHandlers){
  196. .load = main_window_load,
  197. .unload = main_window_unload
  198. });
  199. // Show the Window on the watch, with animated=true
  200. window_stack_push(s_main_window, true);
  201. // Register with TickTimerService
  202. tick_timer_service_subscribe((MINUTE_UNIT | DAY_UNIT), tick_handler);
  203. // Register AppMessage callbacks
  204. app_message_register_inbox_received(inbox_received_callback);
  205. app_message_register_inbox_dropped(inbox_dropped_callback);
  206. app_message_register_outbox_failed(outbox_failed_callback);
  207. app_message_register_outbox_sent(outbox_sent_callback);
  208. // Open AppMessage
  209. app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum());
  210. update_time();
  211. update_date();
  212. }
  213. static void deinit() {
  214. // Destroy Window
  215. window_destroy(s_main_window);
  216. }