📜 ⬆️ ⬇️

We program under Pebble. Lesson One: Stupid Watches

When I brought the Pebble watch, I thought it was just a smart watch. Well, there is a sms on the screen to show, time in two belts, put in place of digital - hipster analog. And so on.



But it turns out that the clock has a fairly large community , an open API for creating its applications , an online development environment - in general, an ideal toy for a bored developer.

So what do we have? Three buttons on the right, one button on the left, a screen with a resolution of 144x168 pixels.
Two types of programs - watchface, skins for watches and watchapp - applications for watches. The first can not respond to the buttons, the second can. The first ones are scrolled with the up and down buttons in the clock display mode, the second ones are shown at the end of the menu after pressing the middle button. Applications have a top bar by default, in which the name of the application is displayed at startup, and during operation - the clock, but it can be disabled. All the guts are completely the same, you can change the type of application by reassembly, without making changes to the code.
')

Getting started


Go to cloudpebble.net , create an account, click Create Project, select SDK 2.

From the side we see:
Settings - project settings
Compilation - build project
main.c is our only project file

Go to Settings.

App kind is just a type, a watch skin or an application.
Short Name is displayed in the clock menu, Long name - in the application on the phone (a menu from which you can delete applications)
Menu image - a picture in the watch menu.
UUID - identifier of the clock. Used, for example, when updating an application. If the downloaded application has the same number as one of the old ones, it will be replaced with a new one.

In the Compilation section, you can build a program (the Run build button), after which you will be given a link to the binary and a QR code for downloading it. It can be scanned by phone, and immediately set on the clock. This will have to be done often ...

Now open main.c, and copy instead of what is there, this is the code:
#include "pebble.h" Window *window; /*   ... !   ,    . */ int main(void) { window = window_create(); /*          http://goo.gl/mdb5B9*/ window_stack_push(window, true); /*      .       -         . http://goo.gl/jXG3aw */ app_event_loop(); /*      http://goo.gl/7hLyRX */ window_destroy(window); /*      http://goo.gl/G3FJ6i */ } 
After the description - links to API pages for one or another function. Son, this is our bible ... No, Dad, this is our Kama Sutra.
The above program does nothing useful, just shows a blank screen. Does not respond to buttons, when you press the button back - ends.


Let's display some inscription. First, set the background color of the program window:
 window_set_background_color(window, GColorBlack); 

The second parameter can take values: GColorBlack - black, GColorWhite - white, GColorClear - transparent paint a transparent background through which the previous layer will be visible (if it were). By default, it is White, which is why the first program had a white background. Of course, this should be done after the window_create function.
In order to display the text, we need a text layer.
Create a layer:
 TextLayer *text_layer; 

We initialize and set the coordinates:
 text_layer = text_layer_create(GRect(0, 0, 144, 168)); 

GRect - a function to create a rectangle. She gets the coordinates in the following order - the first two numbers are the coordinates of the upper left corner of the triangle - x, y. The second two numbers are the width and height of our rectangle. For convenience, I made the following image:

Remember that coordinates are counted from the physical beginning of the screen, but in application mode, the first 16 pixels will close the upper bar, if it is not removed.
Here is a 1: 1 picture:

Opening it in any editor is very convenient to calculate the coordinates. Unfortunately, the development environment does not provide such an opportunity.

By default, the font color is black, the background color is white, left-justified, the font is Raster Gothic 14.
We are changing all this. Our background is black, so the color of the letters should be white:
 text_layer_set_text_color(text_layer, GColorWhite); 

Make the background (text layer) transparent:
 text_layer_set_background_color(text_layer, GColorClear); 

Center alignment:
 text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); 

And we do a bit more font:
 text_layer_set_font(text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD)); 
Here is a list of all standard fonts.
FONT_KEY_GOTHIC_14
FONT_KEY_GOTHIC_14_BOLD
FONT_KEY_GOTHIC_18
FONT_KEY_GOTHIC_18_BOLD
FONT_KEY_GOTHIC_24
FONT_KEY_GOTHIC_24_BOLD
FONT_KEY_GOTHIC_28
FONT_KEY_GOTHIC_28_BOLD
FONT_KEY_BITHAM_30_BLACK
FONT_KEY_BITHAM_42_BOLD
FONT_KEY_BITHAM_42_LIGHT
FONT_KEY_BITHAM_42_MEDIUM_NUMBERS
FONT_KEY_BITHAM_34_MEDIUM_NUMBERS
FONT_KEY_BITHAM_34_LIGHT_SUBSET
FONT_KEY_BITHAM_18_LIGHT_SUBSET
FONT_KEY_ROBOTO_CONDENSED_21
FONT_KEY_ROBOTO_BOLD_SUBSET_49
FONT_KEY_DROID_SERIF_28_BOLD

Make the child Add the layer we created to the main screen layer as a child:
 layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer)); 

Finally, write our text to the layer:
 text_layer_set_text(text_layer, "Hi, habrahabr!"); 

And when you exit - do not forget to free the memory:
 text_layer_destroy(text_layer); 
Our program already looks like this:


But its source. You can copy to the editor, build and run on the clock to brag: I wrote a program for the clock (!)
 #include "pebble.h" Window *window; TextLayer *text_layer; /*     ...    */ int main(void) { window = window_create(); window_set_background_color(window, GColorBlack); /* http://goo.gl/B6tj94 */ window_stack_push(window, true); text_layer = text_layer_create(GRect(0, 0, 144, 168)); /*   (http://goo.gl/00eAW6)        http://goo.gl/kYuFh5 */ text_layer_set_text_color(text_layer, GColorWhite); /*    http://goo.gl/wt4ZIC */ text_layer_set_background_color(text_layer, GColorClear); /*     http://goo.gl/Y7HARg */ text_layer_set_font(text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD)); /*   http://goo.gl/MOhxNe */ text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); /*    http://goo.gl/K6LWeG */ layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer)); /*          http://goo.gl/jFy8LV */ text_layer_set_text(text_layer, "Hi, habrahabr!"); /*   http://goo.gl/KT1hD6 */ app_event_loop(); text_layer_destroy(text_layer); window_destroy(window); } 


Finally, you can add time to our watches.
Create a variable of the desired type (time in seconds) and put the current time in it in the POSIX format
  time_t now = time(NULL); 
Create a structure that will store the current time value in a more readable format - year, month, day, hour, minute, second, as well as day in weeks, day in year, and AM / PM:
 struct tm *current_time = localtime(&now); 
And after that we write the time converted into it by the localtime function from POSIX into a readable form.

Since we only need time, and in the variable we have all the information to the heap, we need to select the parts we need. This is done by the strftime function. It takes the following variables as arguments: a variable recording the result, its size, a recording format, a variable in which there is time. Since the function needs a variable (it cannot write to the text layer), and its size, you must first create such a variable.
 static char time[] = "00:00:00"; 

Of course, it is not necessary to write during the initialization 00:00:00, you can also “”, but you can not write anything, but simply set the size in the second argument of the function by number, but this will not be very clear.
 strftime(time, sizeof(time), "%T", current_time); 

If in current_time we always have the current time, then from this moment, in the time variable, there is a formatted time value at the time of the execution of strftime. How it is formatted depends on the third argument,% T. The format documentation is easily googled by function name, for example, here . In this case,% T is the same as "% H:% M:% S". Hours, minutes and seconds, separated by colons.

Now you can write this value to the text layer:
 text_layer_set_text(text_layer, time); 

It seems like we got a watch. And when they start they will show the correct time. That's just the problem - they are not updated, and show the correct time only once a day.
We need to somehow recalculate time every second and display it on the screen. This is done like this.
We create a function that will do this, and we transfer everything about recalculation and time output to it:

 static void second_tick(struct tm* tick_time, TimeUnits units_changed) { static char time[] = "00:00:00"; strftime(time, sizeof(time), "%T", current_time); text_layer_set_text(text_layer, time); } 


We subscribe to the timer service:

 tick_timer_service_subscribe(SECOND_UNIT, &second_tick); 


The first argument means that the function in the second argument will be called every second. If there are no seconds in the clock, you can save energy and wake the processor 60 times less by calling the function every minute: MINUTE_UNIT
Or every hour: HOUR_UNIT
Or every day: DAY_UNIT
Well, you understand the logic: MONTH_UNIT, YEAR_UNIT

After that, it is desirable to call this function forcibly, without waiting for the next tick of the timer - well, just for beauty, so as not to look at the blank screen for a second. It is good if a second. And if the timer ticks every minute?

 second_tick(current_time, SECOND_UNIT); 


As a result, our watches look like this:



Source:

 #include "pebble.h" Window *window; TextLayer *text_layer; static void second_tick(struct tm* tick_time, TimeUnits units_changed) /* ,     */ { static char time[] = "00:00:00"; /*       */ strftime(time, sizeof(time), "%T", tick_time); /*     */ text_layer_set_text(text_layer, time); /*        */ } int main(void) { window = window_create(); window_set_background_color(window, GColorBlack); window_stack_push(window, true); text_layer = text_layer_create(GRect(0, 0, 144, 168)); text_layer_set_text_color(text_layer, GColorWhite); text_layer_set_background_color(text_layer, GColorClear); text_layer_set_font(text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD)); text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer)); time_t now = time(NULL); /*       POSIX- */ struct tm *current_time = localtime(&now); /*   POSIX     */ tick_timer_service_subscribe(SECOND_UNIT, &second_tick); /*     */ second_tick(current_time, SECOND_UNIT); /*       */ app_event_loop(); text_layer_destroy(text_layer); window_destroy(window); tick_timer_service_unsubscribe(); } 


References:

Httpeble : a library that implements http requests inside programs
[EN] A project of a truly smart watch (calendar, weather, reminders, phone search, HTTP requests for smart home control, music management, camera control, GPS, stock reports)
PapaBubaDiop writes about the development of a game for Pebble.
A huge collection of various applications for pebble, most - with the source.


Source: https://habr.com/ru/post/204338/


All Articles