// Largest expected inbox and outbox message sizes const uint32_t inbox_size = 64; const uint32_t outbox_size = 64; static char s_auth[40]; static char s_api[40]; static char s_username[40]; static char s_password[40]; static char s_server[100]; static bool s_js_ready; static Window *s_window; static TextLayer *s_text_layer,*s_statusbar; static ActionBarLayer *s_action_bar_layer; static StatusBarLayer *s_status_bar_layer; static GBitmap *s_h_on_bitmap, *s_h_off_bitmap, *s_q_mark_bitmap; static const int16_t MARGIN = 8; bool is_home_on = false; static uint32_t size ; time_t current_time; /* typedef enum { status, username, password, server } AppKey; */ static char * msg; // An instance of the struct Settings settings; // Save the settings to persistent storage static void prv_save_settings() { persist_write_data(SETTINGS_KEY, &settings, sizeof(settings)); } //! helper to construct the various text layers as they appear in this app static GRect init_text_layer(Layer *parent_layer, TextLayer **text_layer, int16_t y, int16_t h, int16_t additional_right_margin, char *font_key) { // why "-1" (and then "+2")? because for this font we need to compensate for weird white-spacing const int16_t font_compensator = strcmp(font_key, FONT_KEY_LECO_38_BOLD_NUMBERS) == 0 ? 3 : 1; const GRect frame = GRect(MARGIN - font_compensator, y, layer_get_bounds(parent_layer).size.w - 2 * MARGIN + 2 * font_compensator - additional_right_margin, h); *text_layer = text_layer_create(frame); text_layer_set_background_color(*text_layer, GColorClear); text_layer_set_text_color(*text_layer, PBL_IF_COLOR_ELSE(GColorWhite, GColorBlack)); text_layer_set_font(*text_layer, fonts_get_system_font(font_key)); layer_add_child(parent_layer, text_layer_get_layer(*text_layer)); return frame; } static void init_statusbar_text_layer(Layer *parent, TextLayer **layer) { init_text_layer(parent, layer, 0, 16, 0, FONT_KEY_GOTHIC_18_BOLD); GRect sb_bounds = layer_get_bounds(text_layer_get_layer(*layer)); sb_bounds.origin.y -= 1; layer_set_bounds(text_layer_get_layer(*layer), sb_bounds); text_layer_set_text_alignment(*layer, GTextAlignmentCenter); } static void inbox_dropped_callback(AppMessageResult reason, void *context) { // A message was received, but had to be dropped APP_LOG(APP_LOG_LEVEL_ERROR, "Message dropped. Reason: %d", (int)reason); } static void outbox_sent_callback(DictionaryIterator *iter, void *context) { // The message just sent has been successfully delivered APP_LOG(APP_LOG_LEVEL_INFO, "Message sent. "); } static void outbox_failed_callback(DictionaryIterator *iter, AppMessageResult reason, void *context) { // The message just sent failed to be delivered APP_LOG(APP_LOG_LEVEL_ERROR, "Message send failed. Reason: %d", (int)reason); } static void select_click_handler(ClickRecognizerRef recognizer, void *context) { // Declare the dictionary's iterator DictionaryIterator *out_iter; // Prepare the outbox buffer for this message AppMessageResult result = app_message_outbox_begin(&out_iter); if(result == APP_MSG_OK) { // Add an item to ask for weather data msg = "get"; dict_write_cstring(out_iter, status, msg); // Send this message result = app_message_outbox_send(); if(result != APP_MSG_OK) { APP_LOG(APP_LOG_LEVEL_ERROR, "Error sending the outbox: %d", (int)result); }else{ text_layer_set_text(s_text_layer, "Sent..."); } } else { // The outbox cannot be used right now APP_LOG(APP_LOG_LEVEL_ERROR, "Error preparing the outbox: %d", (int)result); } } static void up_click_handler(ClickRecognizerRef recognizer, void *context) { // Declare the dictionary's iterator DictionaryIterator *out_iter; // Prepare the outbox buffer for this message AppMessageResult result = app_message_outbox_begin(&out_iter); if(result == APP_MSG_OK) { // Add an item to switch home mode on msg = "home_on"; dict_write_cstring(out_iter, status, msg); // Send this message result = app_message_outbox_send(); if(result != APP_MSG_OK) { APP_LOG(APP_LOG_LEVEL_ERROR, "Error sending the outbox: %d", (int)result); }else{ text_layer_set_text(s_text_layer, "Sent..."); } } else { // The outbox cannot be used right now APP_LOG(APP_LOG_LEVEL_ERROR, "Error preparing the outbox: %d", (int)result); } } static void down_click_handler(ClickRecognizerRef recognizer, void *context) { // Declare the dictionary's iterator DictionaryIterator *out_iter; // Prepare the outbox buffer for this message AppMessageResult result = app_message_outbox_begin(&out_iter); if(result == APP_MSG_OK) { // Add an item to switch home mode off msg = "home_off"; dict_write_cstring(out_iter, status, msg); // Send this message result = app_message_outbox_send(); if(result != APP_MSG_OK) { APP_LOG(APP_LOG_LEVEL_ERROR, "Error sending the outbox: %d", (int)result); }else{ APP_LOG(APP_LOG_LEVEL_INFO, "Sending to the outbox: %s", msg); text_layer_set_text(s_text_layer, "Sent..."); } } else { // The outbox cannot be used right now APP_LOG(APP_LOG_LEVEL_ERROR, "Error preparing the outbox: %d", (int)result); } } static void click_config_provider(void *context) { window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler); window_single_click_subscribe(BUTTON_ID_UP, up_click_handler); window_single_click_subscribe(BUTTON_ID_DOWN, down_click_handler); } static void update_time() { // Get a tm structure time_t temp = time(NULL); struct tm *tick_time = localtime(&temp); // Write the current hours and minutes into a buffer static char s_buffer[8]; strftime(s_buffer, sizeof(s_buffer), clock_is_24h_style() ? "%H:%M" : "%I:%M", tick_time); // Display this time on the TextLayer text_layer_set_text(s_statusbar, s_buffer); } static void comm_is_ready() { // Authenticate to get token from syno // Declare the dictionary's iterator DictionaryIterator *out_iter; // Prepare the outbox buffer for this message AppMessageResult result = app_message_outbox_begin(&out_iter); if(result == APP_MSG_OK) { // Add an item to ask for weather data msg = "auth"; dict_write_cstring(out_iter, status, msg); // Send this message result = app_message_outbox_send(); if(result != APP_MSG_OK) { APP_LOG(APP_LOG_LEVEL_ERROR, "Error sending the outbox: %d", (int)result); }else{ text_layer_set_text(s_text_layer, "Authenticating..."); } } else { // The outbox cannot be used right now APP_LOG(APP_LOG_LEVEL_ERROR, "Error preparing the outbox: %d", (int)result); } // set the text //text_layer_set_text(s_text_layer, "Welcome to Syno Cam Switch ! ready"); // click provider window_set_click_config_provider(s_window, click_config_provider); } static void tick_handler(struct tm *tick_time, TimeUnits units_changed) { update_time(); } // Handle the response from AppMessage static void inbox_received_callback(DictionaryIterator *iter, void *context) { // A new message has been successfully received APP_LOG(APP_LOG_LEVEL_DEBUG, "New message! "); size = dict_size(iter); // JS readiness Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_JSReady); if(ready_tuple){ //Pebblekit JS is ready ! Safe to send messages s_js_ready = true; comm_is_ready(); APP_LOG(APP_LOG_LEVEL_DEBUG, "received jsready message on watch... "); } // Read Auth returns Tuple *auth_tuple = dict_find(iter, MESSAGE_KEY_auth); if(auth_tuple) { strncpy(s_auth, auth_tuple->value->cstring, 40); // Display in the TextLayer text_layer_set_text(s_text_layer, s_auth); APP_LOG(APP_LOG_LEVEL_DEBUG, "Auth message received ... "); }else{ APP_LOG(APP_LOG_LEVEL_DEBUG, "not auth message... "); } // Read API returns Tuple *api_tuple = dict_find(iter, MESSAGE_KEY_status); if(api_tuple) { strncpy(s_api, api_tuple->value->cstring, 40); // Display in the TextLayer text_layer_set_text(s_text_layer, s_api); APP_LOG(APP_LOG_LEVEL_DEBUG, "status message received ... "); }else{ APP_LOG(APP_LOG_LEVEL_DEBUG, "not status message... "); } // Read String preferences Tuple *username_t = dict_find(iter, MESSAGE_KEY_username); if(username_t) { strncpy(s_username, username_t->value->cstring, 40); prv_save_settings(); APP_LOG(APP_LOG_LEVEL_DEBUG, "new username in settings... %s",s_username); } Tuple *password_t = dict_find(iter, MESSAGE_KEY_password); if(password_t) { strncpy(s_password, password_t->value->cstring, 40); prv_save_settings(); APP_LOG(APP_LOG_LEVEL_DEBUG, "new password in settings... %s",s_password); } Tuple *server_t = dict_find(iter, MESSAGE_KEY_server); if(server_t) { strncpy(s_server, server_t->value->cstring, 99); prv_save_settings(); APP_LOG(APP_LOG_LEVEL_DEBUG, "new server in settings... %s",s_server); } } static void init(void) { // Open AppMessage app_message_open(inbox_size, outbox_size); // Register to be notified about inbox received events app_message_register_inbox_received(inbox_received_callback); // Register to be notified about inbox dropped events app_message_register_inbox_dropped(inbox_dropped_callback); // Register to be notified about outbox sent events app_message_register_outbox_sent(outbox_sent_callback); // Register to be notified about outbox failed events app_message_register_outbox_failed(outbox_failed_callback); // Create a window and get information about the window s_window = window_create(); Layer *window_layer = window_get_root_layer(s_window); GRect bounds = layer_get_bounds(window_layer); //load buttons s_h_on_bitmap = gbitmap_create_with_resource(RESOURCE_ID_HOME_ON); s_q_mark_bitmap = gbitmap_create_with_resource(RESOURCE_ID_Q_MARK); s_h_off_bitmap = gbitmap_create_with_resource(RESOURCE_ID_HOME_OFF); s_action_bar_layer = action_bar_layer_create(); action_bar_layer_set_icon(s_action_bar_layer, BUTTON_ID_UP, s_h_on_bitmap); action_bar_layer_set_icon(s_action_bar_layer, BUTTON_ID_SELECT, s_q_mark_bitmap); action_bar_layer_set_icon(s_action_bar_layer, BUTTON_ID_DOWN, s_h_off_bitmap); action_bar_layer_add_to_window(s_action_bar_layer, s_window); s_status_bar_layer = status_bar_layer_create(); Layer *status_bar_base_layer = status_bar_layer_get_layer(s_status_bar_layer); GRect status_frame = layer_get_frame(status_bar_base_layer); status_frame.origin.y = -STATUS_BAR_LAYER_HEIGHT; layer_set_frame(status_bar_base_layer, status_frame); layer_add_child(window_layer, status_bar_base_layer); if (bounds.origin.y == 0) { bounds.origin.y = STATUS_BAR_LAYER_HEIGHT; bounds.size.h -= STATUS_BAR_LAYER_HEIGHT; GRect frame = layer_get_frame(window_layer); frame.size.h = bounds.size.h; layer_set_frame(window_layer, frame); layer_set_bounds(window_layer, bounds); layer_set_clips(window_layer, false); } init_statusbar_text_layer(window_layer, &s_statusbar); text_layer_set_text(s_statusbar, ""); // Create a text layer and set the text const GEdgeInsets label_insets = {.right = ACTION_BAR_WIDTH, .left = ACTION_BAR_WIDTH / 2}; s_text_layer = text_layer_create(grect_inset(bounds, label_insets)); text_layer_set_text(s_text_layer, "Welcome to Syno Cam Switch !"); // Set the font and text alignment text_layer_set_font(s_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD)); text_layer_set_text_alignment(s_text_layer, GTextAlignmentCenter); // Add the text layer to the window layer_add_child(window_layer, text_layer_get_layer(s_text_layer)); // Enable text flow and paging on the text layer, with a slight inset of 5, for round screens text_layer_enable_screen_text_flow_and_paging(s_text_layer, 5); // Push the window, setting the window animation to 'true' window_stack_push(s_window, true); // get the current time ! //update_time(); //Kick the tick_handler for instant update current_time = time(NULL); tick_handler(localtime(¤t_time),MINUTE_UNIT); tick_timer_service_subscribe((MINUTE_UNIT), tick_handler); // App Logging! APP_LOG(APP_LOG_LEVEL_DEBUG, "Just pushed a window!"); } static void deinit(void) { // Destroy the text layer text_layer_destroy(s_text_layer); // Destroy the action bar layer action_bar_layer_destroy(s_action_bar_layer); // Destroy the status bar layer status_bar_layer_destroy(s_status_bar_layer); // Destroy the window window_destroy(s_window); } int main(void) { init(); app_event_loop(); deinit(); }