Louis authored on25/07/2018 21:41:41
Showing11 changed files
1 1
new file mode 100755
... ...
@@ -0,0 +1,21 @@
1
+MIT License
2
+
3
+Copyright (c) 2016 ljonget
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.
0 22
new file mode 100755
... ...
@@ -0,0 +1 @@
1
+# Pebble-Watchface-Day-and-Night-Earth-Connection
0 2
\ No newline at end of file
1 3
new file mode 100755
... ...
@@ -0,0 +1,50 @@
1
+{
2
+    "author": "Louis Jonget",
3
+    "dependencies": {},
4
+    "keywords": [],
5
+    "name": "day-night-bt",
6
+    "pebble": {
7
+        "displayName": "Day and Night Earth improved Watchface",
8
+        "enableMultiJS": true,
9
+        "messageKeys": [],
10
+        "projectType": "native",
11
+        "resources": {
12
+            "media": [
13
+                {
14
+                    "file": "images/menu_icon.png",
15
+                    "menuIcon": true,
16
+                    "name": "IMAGE_MENU_ICON",
17
+                    "targetPlatforms": null,
18
+                    "type": "png"
19
+                },
20
+                {
21
+                    "file": "images/WORLD_MONO",
22
+                    "name": "WORLD_MONO",
23
+                    "targetPlatforms": null,
24
+                    "type": "pbi"
25
+                },
26
+                {
27
+                    "file": "images/BT_ko_icon.png",
28
+                    "name": "BT_ko_icon",
29
+                    "targetPlatforms": null,
30
+                    "type": "bitmap"
31
+                },
32
+                {
33
+                    "file": "images/BATTERY",
34
+                    "name": "BATTERY",
35
+                    "targetPlatforms": null,
36
+                    "type": "bitmap"
37
+                }
38
+            ]
39
+        },
40
+        "sdkVersion": "3",
41
+        "targetPlatforms": [
42
+            "diorite"
43
+        ],
44
+        "uuid": "892e12bc-7a3e-411c-ba97-daa492f91088",
45
+        "watchapp": {
46
+            "watchface": true
47
+        }
48
+    },
49
+    "version": "2.1.0"
50
+}
0 51
new file mode 100755
1 52
Binary files /dev/null and b/resources/images/BATTERY differ
2 53
new file mode 100755
3 54
Binary files /dev/null and b/resources/images/BT_ko_icon.png differ
4 55
new file mode 100755
5 56
Binary files /dev/null and b/resources/images/WORLD_MONO differ
6 57
new file mode 100755
7 58
Binary files /dev/null and b/resources/images/menu_icon.png differ
8 59
new file mode 100755
... ...
@@ -0,0 +1,3 @@
1
+
2
+// Comment or uncomment to invert the text
3
+//#define BLACK_ON_WHITE
0 4
new file mode 100755
... ...
@@ -0,0 +1,239 @@
1
+#include <pebble.h>
2
+#include "config.h"
3
+
4
+#define STR_SIZE 20
5
+#define REDRAW_INTERVAL 1
6
+#define WIDTH 144
7
+#define HEIGHT 72
8
+
9
+static Window *window;
10
+static TextLayer *time_text_layer;
11
+static TextLayer *date_text_layer;
12
+
13
+static GBitmap *world_bitmap;
14
+
15
+static Layer *canvas;
16
+static GBitmap *image;
17
+static int redraw_counter;
18
+// BT connection & Battery icon declare
19
+static BitmapLayer *s_battery_icon_layer, *s_bt_icon_layer;
20
+static GBitmap *s_battery_icon_bitmap, *s_bt_icon_bitmap;
21
+static bool low_battery;
22
+static int s_battery_level;
23
+// s is set to memory of size STR_SIZE, and temporarily stores strings
24
+char *s;
25
+
26
+
27
+static void draw_earth() {
28
+  // ##### calculate the time
29
+  int now = (int)time(NULL);
30
+
31
+  float day_of_year; // value from 0 to 1 of progress through a year
32
+  float time_of_day; // value from 0 to 1 of progress through a day
33
+  // approx number of leap years since epoch
34
+  // = now / SECONDS_IN_YEAR * .24; (.24 = average rate of leap years)
35
+  int leap_years = (int)((float)now / 131487192.0);
36
+  // day_of_year is an estimate, but should be correct to within one day
37
+  day_of_year = now - (((int)((float)now / 31556926.0) * 365 + leap_years) * 86400);
38
+  day_of_year = day_of_year / 86400.0;
39
+  time_of_day = day_of_year - (int)day_of_year;
40
+  day_of_year = day_of_year / 365.0;
41
+  // ##### calculate the position of the sun
42
+  // left to right of world goes from 0 to 65536
43
+  int sun_x = (int)((float)TRIG_MAX_ANGLE * (1.0 - time_of_day));
44
+  // bottom to top of world goes from -32768 to 32768
45
+  // 0.2164 is march 20, the 79th day of the year, the march equinox
46
+  // Earth's inclination is 23.4 degrees, so sun should vary 23.4/90=.26 up and down
47
+  int sun_y = -sin_lookup((day_of_year - 0.2164) * TRIG_MAX_ANGLE) * .26 * .25;
48
+  // ##### draw the bitmap
49
+  int x, y;
50
+  for(x = 0; x < WIDTH; x++) {
51
+    int x_angle = (int)((float)TRIG_MAX_ANGLE * (float)x / (float)(WIDTH));
52
+    for(y = 0; y < HEIGHT; y++) {
53
+      int y_angle = (int)((float)TRIG_MAX_ANGLE * (float)y / (float)(HEIGHT * 2)) - TRIG_MAX_ANGLE/4;
54
+      // spherical law of cosines
55
+      float angle = ((float)sin_lookup(sun_y)/(float)TRIG_MAX_RATIO) * ((float)sin_lookup(y_angle)/(float)TRIG_MAX_RATIO);
56
+      angle = angle + ((float)cos_lookup(sun_y)/(float)TRIG_MAX_RATIO) * ((float)cos_lookup(y_angle)/(float)TRIG_MAX_RATIO) * ((float)cos_lookup(sun_x - x_angle)/(float)TRIG_MAX_RATIO);
57
+      int byte = y * gbitmap_get_bytes_per_row(image) + (int)(x / 8);
58
+      //if ((angle < 0) ^ (0x1 & (((char *)gbitmap_get_data(world_bitmap))[byte] >> (x % 8)))) {
59
+      if ( (angle < 0) ^ (0x1 & (((char *)gbitmap_get_data(world_bitmap))[byte] >> (x % 8)))) {
60
+        // white pixel
61
+        ((char *)gbitmap_get_data(image))[byte] = ((char *)gbitmap_get_data(image))[byte] | (0x1 << (x % 8));
62
+     } else {
63
+        // black pixel
64
+        ((char *)gbitmap_get_data(image))[byte] = ((char *)gbitmap_get_data(image))[byte] & ~(0x1 << (x % 8));
65
+      }
66
+    }
67
+  }
68
+  layer_mark_dirty(canvas);
69
+}
70
+
71
+static void draw_watch(struct Layer *layer, GContext *ctx) {
72
+  graphics_draw_bitmap_in_rect(ctx, image, gbitmap_get_bounds(image));
73
+}
74
+
75
+static void handle_minute_tick(struct tm *tick_time, TimeUnits units_changed) {
76
+  static char time_text[] = "00:00";
77
+  static char date_text[] = "Xxx, Xxx 00";
78
+
79
+  strftime(date_text, sizeof(date_text), "%a, %b %e", tick_time);
80
+  text_layer_set_text(date_text_layer, date_text);
81
+
82
+  if (clock_is_24h_style()) {
83
+    strftime(time_text, sizeof(time_text), "%R", tick_time);
84
+  } else {
85
+    strftime(time_text, sizeof(time_text), "%I:%M", tick_time);
86
+  }
87
+  if (!clock_is_24h_style() && (time_text[0] == '0')) {
88
+    memmove(time_text, &time_text[1], sizeof(time_text) - 1);
89
+  }
90
+  text_layer_set_text(time_text_layer, time_text);
91
+ 
92
+  redraw_counter++;
93
+  if (redraw_counter >= REDRAW_INTERVAL) {
94
+    draw_earth();
95
+    redraw_counter = 0;
96
+  }
97
+}
98
+
99
+
100
+static void bluetooth_callback(bool connected) {
101
+  // Show ko icon if disconnected
102
+  layer_set_hidden(bitmap_layer_get_layer(s_bt_icon_layer), connected);
103
+
104
+  if(!connected && !quiet_time_is_active ()) {
105
+    // Issue a vibrating alert
106
+    vibes_double_pulse();
107
+  }
108
+}
109
+
110
+static void battery_callback(BatteryChargeState state) {
111
+  // Record the new battery level
112
+  s_battery_level = state.charge_percent;
113
+  
114
+ // display icon and vibrate if low battery
115
+  if( s_battery_level < 11 && !low_battery && !state.is_charging ) {
116
+    vibes_double_pulse();
117
+    low_battery = true;
118
+  }else if (state.is_charging) {
119
+    low_battery = false;
120
+  }
121
+  layer_set_hidden(bitmap_layer_get_layer(s_battery_icon_layer), !low_battery);
122
+
123
+}
124
+
125
+static void window_load(Window *window) {
126
+#ifdef BLACK_ON_WHITE
127
+  GColor background_color = GColorWhite;
128
+  GColor foreground_color = GColorBlack;
129
+#else
130
+  GColor background_color = GColorBlack;
131
+  GColor foreground_color = GColorWhite;
132
+#endif
133
+  window_set_background_color(window, background_color);
134
+  Layer *window_layer = window_get_root_layer(window);
135
+  GRect bounds = layer_get_bounds(window_layer);
136
+
137
+  time_text_layer = text_layer_create(GRect(0, 72, 144-0, 168-72));
138
+  text_layer_set_background_color(time_text_layer, background_color);
139
+  text_layer_set_text_color(time_text_layer, foreground_color);
140
+  text_layer_set_font(time_text_layer, fonts_get_system_font(FONT_KEY_ROBOTO_BOLD_SUBSET_49));
141
+  text_layer_set_text(time_text_layer, "");
142
+  text_layer_set_text_alignment(time_text_layer, GTextAlignmentCenter);
143
+  layer_add_child(window_layer, text_layer_get_layer(time_text_layer));
144
+
145
+  date_text_layer = text_layer_create(GRect(0, 130, 144-0, 168-130));
146
+  text_layer_set_background_color(date_text_layer, background_color);
147
+  text_layer_set_text_color(date_text_layer, foreground_color);
148
+  text_layer_set_font(date_text_layer, fonts_get_system_font(FONT_KEY_ROBOTO_CONDENSED_21));
149
+  text_layer_set_text(date_text_layer, "");
150
+  text_layer_set_text_alignment(date_text_layer, GTextAlignmentCenter);
151
+  layer_add_child(window_layer, text_layer_get_layer(date_text_layer));
152
+
153
+  canvas = layer_create(GRect(0, 0, bounds.size.w, bounds.size.h));
154
+  layer_set_update_proc(canvas, draw_watch);
155
+  layer_add_child(window_layer, canvas);
156
+
157
+  image = gbitmap_create_blank(GSize(WIDTH, HEIGHT), GBitmapFormat1Bit);
158
+
159
+  draw_earth();
160
+  //----------------
161
+  
162
+  // Create the Battery icon GBitmap
163
+  s_battery_icon_bitmap = gbitmap_create_with_resource(RESOURCE_ID_BATTERY );
164
+  
165
+  // Create the BitmapLayer to display the GBitmap
166
+  s_battery_icon_layer = bitmap_layer_create(GRect( 127, 143, 14, 22));
167
+  bitmap_layer_set_bitmap(s_battery_icon_layer, s_battery_icon_bitmap);
168
+  layer_add_child(window_layer, bitmap_layer_get_layer(s_battery_icon_layer));
169
+  
170
+  //----------------
171
+  
172
+  // Create the Bluetooth icon GBitmap
173
+  s_bt_icon_bitmap = gbitmap_create_with_resource(RESOURCE_ID_BT_ko_icon );
174
+  
175
+  // Create the BitmapLayer to display the GBitmap
176
+  s_bt_icon_layer = bitmap_layer_create(GRect( 3, 143, 14, 22));
177
+  bitmap_layer_set_bitmap(s_bt_icon_layer, s_bt_icon_bitmap);
178
+  layer_add_child(window_layer, bitmap_layer_get_layer(s_bt_icon_layer));
179
+  
180
+  // show correct state of battery from start
181
+  battery_callback(battery_state_service_peek());
182
+  // Show the correct state of the BT connection from the start
183
+  bluetooth_callback(connection_service_peek_pebble_app_connection());
184
+}
185
+
186
+static void window_unload(Window *window) {
187
+  text_layer_destroy(time_text_layer);
188
+  text_layer_destroy(date_text_layer);
189
+  layer_destroy(canvas);
190
+  gbitmap_destroy(image);
191
+  gbitmap_destroy(s_bt_icon_bitmap);
192
+  bitmap_layer_destroy(s_bt_icon_layer);
193
+  gbitmap_destroy(s_battery_icon_bitmap);
194
+  bitmap_layer_destroy(s_battery_icon_layer);
195
+}
196
+
197
+static void init(void) {
198
+  redraw_counter = 0;
199
+
200
+
201
+  world_bitmap = gbitmap_create_with_resource(RESOURCE_ID_WORLD_MONO);
202
+
203
+  window = window_create();
204
+  window_set_window_handlers(window, (WindowHandlers) {
205
+    .load = window_load,
206
+    .unload = window_unload,
207
+  });
208
+  
209
+  const bool animated = true;
210
+  window_stack_push(window, animated);
211
+
212
+  s = malloc(STR_SIZE);
213
+  tick_timer_service_subscribe(MINUTE_UNIT, handle_minute_tick);
214
+  
215
+  // Subscribe to battery info
216
+  battery_state_service_subscribe(battery_callback);
217
+  
218
+  // Register for Bluetooth connection updates
219
+  connection_service_subscribe((ConnectionHandlers) {
220
+    .pebble_app_connection_handler = bluetooth_callback
221
+  });  
222
+}
223
+
224
+static void deinit(void) {
225
+  tick_timer_service_unsubscribe();
226
+  free(s);
227
+  window_destroy(window);
228
+  gbitmap_destroy(world_bitmap);
229
+
230
+}
231
+
232
+int main(void) {
233
+  init();
234
+
235
+  APP_LOG(APP_LOG_LEVEL_DEBUG, "Done initializing, pushed window: %p", window);
236
+
237
+  app_event_loop();
238
+  deinit();
239
+}
0 240
new file mode 100755
... ...
@@ -0,0 +1,6 @@
1
+Pebble.addEventListener("ready",
2
+  function(e) {
3
+    var time = Math.round((new Date()).getTime() / 1000);
4
+    Pebble.sendAppMessage({"0": time});
5
+  }
6
+);
0 7
new file mode 100755
... ...
@@ -0,0 +1,52 @@
1
+#
2
+# This file is the default set of rules to compile a Pebble project.
3
+#
4
+# Feel free to customize this to your needs.
5
+#
6
+
7
+import os.path
8
+try:
9
+    from sh import CommandNotFound, jshint, cat, ErrorReturnCode_2
10
+    hint = jshint
11
+except (ImportError, CommandNotFound):
12
+    hint = None
13
+
14
+top = '.'
15
+out = 'build'
16
+
17
+
18
+def options(ctx):
19
+    ctx.load('pebble_sdk')
20
+
21
+
22
+def configure(ctx):
23
+    ctx.load('pebble_sdk')
24
+
25
+
26
+def build(ctx):
27
+    if False and hint is not None:
28
+        try:
29
+            hint([node.abspath() for node in ctx.path.ant_glob("src/**/*.js")], _tty_out=False) # no tty because there are none in the cloudpebble sandbox.
30
+        except ErrorReturnCode_2 as e:
31
+            ctx.fatal("\nJavaScript linting failed (you can disable this in Project Settings):\n" + e.stdout)
32
+
33
+    ctx.load('pebble_sdk')
34
+
35
+    build_worker = os.path.exists('worker_src')
36
+    binaries = []
37
+
38
+    for p in ctx.env.TARGET_PLATFORMS:
39
+        ctx.set_env(ctx.all_envs[p])
40
+        ctx.set_group(ctx.env.PLATFORM_NAME)
41
+        app_elf = '{}/pebble-app.elf'.format(ctx.env.BUILD_DIR)
42
+        ctx.pbl_program(source=ctx.path.ant_glob('src/c/**/*.c'), target=app_elf)
43
+
44
+        if build_worker:
45
+            worker_elf = '{}/pebble-worker.elf'.format(ctx.env.BUILD_DIR)
46
+            binaries.append({'platform': p, 'app_elf': app_elf, 'worker_elf': worker_elf})
47
+            ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/c/**/*.c'), target=worker_elf)
48
+        else:
49
+            binaries.append({'platform': p, 'app_elf': app_elf})
50
+
51
+    ctx.set_group('bundle')
52
+    ctx.pbl_bundle(binaries=binaries, js=ctx.path.ant_glob(['src/pkjs/**/*.js', 'src/pkjs/**/*.json']), js_entry_file='src/pkjs/app.js')