#include <pebble.h>
// Persistent storage key
#define SETTINGS_KEY 1
// Largest expected inbox and outbox message sizes
const uint32_t inbox_size = 64;
const uint32_t outbox_size = 64;
static char s_auth[60];
static char s_api[40];
static char s_username[40];
static char s_password[40];
static char s_server[255];
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;
// Define our settings struct
typedef struct Settings {
char username;
char password;
char server;
} Settings;
// An instance of the struct
static 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;
}
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);
}
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();
}
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, 60);
// 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, 255);
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();
}