Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/pebble-my-data.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2014-10-16 23:32:17 +0400
committerAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2014-10-16 23:32:17 +0400
commit9e38f5606ec18eb1805c8d99639843525fab9316 (patch)
tree6fb1e2c7f45037832b7caacd1d9c6cd109faccec
parentbfda6bc48548a9a77d59aa5190dd98934ef885aa (diff)
WatchFace and plain text
-rw-r--r--README.md157
-rw-r--r--appinfo.json7
-rw-r--r--resources/configuration.html11
-rw-r--r--src/js/pebble-js-app.src.js82
-rw-r--r--src/pebble-my-data.c46
5 files changed, 85 insertions, 218 deletions
diff --git a/README.md b/README.md
index 564d1e9..604dbeb 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
-# Pebble My Data App
+# Pebble My Data App - WatchFace/TXT version
Pebble watches application to show only your own data, prepared on your own server.
This software is licensed under the terms of the MIT license.
-Sources available on [github](https://github.com/bahbka/pebble-my-data).
+Original sources available on [github](https://github.com/bahbka/pebble-my-data).
Inspired by [Pebble Cards](http://keanulee.com/pebblecards).
[My Data at Pebble App Store](https://apps.getpebble.com/applications/53b0607c94943f8e710001e2)
@@ -11,160 +11,11 @@ Inspired by [Pebble Cards](http://keanulee.com/pebblecards).
## Features
-* Fetch JSON from custom URL, specified in settings
+* Fetch TXT from custom URL, specified in settings
* No companion app required, using PebbleKit JS
* Force update with buttons or shaking
-* Append select=1/select=2 GET param on short/long select button update
-* Ability to change up/down buttons behavior from JSON (scrolling or up=1|2,down=1|2 params)
-* Append coordinates to URL (configurable)
-* Append HTTP request header Pebble-Token (unique to device/app pair), can be used for server-side device identification
-* Authentication (see documentation)
-* Scrollable data area
-* Custom update interval, specified in JSON
-* Vibrate on update if specified in JSON
-* Change text font from JSON
-* Black/white theme switched from JSON
-* Turn on light from JSON
-* Blink content from JSON
-* Define scroll offset as percentage after update from JSON
+* Custom update interval
* Vibrate on bluetooth connection loss (configurable)
* Watches battery charge status
* Digital clock (12h/24h support), seconds dots blinking (configurable)
-## Changelog
-
-### 2.3.5
-- Reduced GPS cache lifetime (from 30 mins to 10 mins).
-
-### 2.3.4
-- Workaround for APP_MSG_INTERNAL_ERROR (request last response after 0.1s if occur)
-
-### 2.3.3
-- Extract fields from any level of JSON (useful with [KimonoLabs API](https://www.kimonolabs.com)); multiple content fields will be concatenated with '\n\n'; other fields will be converted to integer, first copy will be used
-- Don't schedule update if another one already in progress
-- Keeps update type on retries when update failed
-
-### 2.3.2
-- Update with shake function (append shake=1 GET param while update, configurable)
-- Changed scroll param behavior, now used to define scroll offset as percentage
-- Truncate content if too big
-
-### 2.2.0
-- Authentication (see documentation)
-
-### 2.1.2
-- Ability to change up/down buttons behavior from JSON (scrolling or up=1|2,down=1|2 params)
-- Added HTTP request header Pebble-Token (unique to device/app pair), can be used for server-side device identification
-- **WARNING:** Changed short=1/long=1 params to select=1/select=2 (sorry for this)
-
-### 2.0.3
-
-- Append coordinates to URL (configurable)
-- Digital clock font, AM/PM support
-- Seconds dots blinking (configurable)
-- Configurable vibration on bluetooth loss
-- Turn on light (value in JSON)
-- Blink content (value in JSON)
-- Scroll-up content after update (value in JSON)
-- Improved configuration page
-- Some minor fixes
-
-### 1.1.0
-
-- Append short=1 or long=1 GET param to URL on short/long select button update (changed to select=1/select=2 in 2.1.2)
-
-### 1.0.0
-
-- Initial release
-
-## Screenshots
-![pebble screenshot 1](https://raw.githubusercontent.com/bahbka/pebble-my-data/master/stuff/screenshots/pebble-screenshot_2014-07-06_18-18-15.png)
-![pebble screenshot 2](https://raw.githubusercontent.com/bahbka/pebble-my-data/master/stuff/screenshots/pebble-screenshot_2014-07-06_18-19-33.png)
-![pebble screenshot 3](https://raw.githubusercontent.com/bahbka/pebble-my-data/master/stuff/screenshots/pebble-screenshot_2014-07-06_18-23-00.png)
-![pebble screenshot 4](https://raw.githubusercontent.com/bahbka/pebble-my-data/master/stuff/screenshots/pebble-screenshot_2014-07-06_18-26-22.png)
-![pebble screenshot 5](https://raw.githubusercontent.com/bahbka/pebble-my-data/master/stuff/screenshots/pebble-screenshot_2014-07-06_18-27-09.png)
-[![android screenshot 1](https://raw.githubusercontent.com/bahbka/pebble-my-data/master/stuff/screenshots/Screenshot_2014-07-06-18-31-03_small.png)](https://raw.githubusercontent.com/bahbka/pebble-my-data/master/stuff/screenshots/Screenshot_2014-07-06-18-31-03.png)
-
-## JSON
-
-JSON output example (some fields are optional):
-
- {
- "content": "Hello\nWorld!",
- "refresh": 300,
- "vibrate": 0,
- "font": 4,
- "theme": 0,
- "scroll": 33,
- "light": 1,
- "blink": 3,
- "updown": 1,
- "auth": "salt"
- }
-
-GET param short=1 or long=1 added to URL on short or long select button update
-
-### content
-Your content to display. Use "\n" as CR.
-
-### refresh
-Next update delay in seconds.
-
-### vibrate
-
-- 0 - Don't vibrate
-- 1 - Short vibrate
-- 2 - Double vibrate
-- 3 - Long vibrate
-
-### font
-
-- 1 - GOTHIC_14
-- 2 - GOTHIC_14_BOLD
-- 3 - GOTHIC_18
-- 4 - GOTHIC_18_BOLD
-- 5 - GOTHIC_24
-- 6 - GOTHIC_24_BOLD
-- 7 - GOTHIC_28
-- 8 - GOTHIC_28_BOLD
-
-### theme
-
-- 0 - Black
-- 1 - White
-
-### scroll
-Scroll content to offset (as percentage 0..100).
-If param not defined or >100 - position will be kept.
-
-### light
-
-- 0 - Do nothing
-- 1 - Turn pebble light on for short time
-
-### blink
-
-- 1..10 - Blink content count (blinks with black/white for "count" times)
-
-### updown
-- 0 use up/down buttons for scrolling
-- 1 use up/down buttons for update, appending up=1|2/down=1|2 params (1=short/2=long)
-
-### auth
-Salt for Pebble-Auth hash (see below)
-
-## Auth
-
-Authentication algorithm example (reinvent the wheel):
- 1. -> Pebble makes HTTP request with Pebble-Token header (Pebble App Token by default, unique to device/app pair, can be changed at configuration page, clear to restore default)
- 2. <- Server answers with JSON like { ..., "content": "logging in...", "refresh": 5, "auth": "randomsalt", ... }
- 3. Pebble calculates MD5(MD5(password)+"randomsalt"), saves it as auth token and uses as Pebble-Auth HTTP request header in future requests.
- 4. -> Pebble makes HTTP request after 5 seconds with Pebble-Token header and with Pebble-Auth header (calculated and stored in previous step)
- 5. Server checks Pebble-Token and Pebble-Auth headers if data equal data in database (Pebble-Token <=> login, calculate MD5(password_md5_db+"randomsalt"))
- 6. <- Server answers with private content (seems your need https for more security), or some error if auth failed; auth field in JSON not needed anymore, until you desire to regenerate auth token with new salt (paranoid mode) or to clear Pebble-Auth header
-
-To clear Pebble-Auth header, send { ..., "auth": "", ...} (eg logout).
-
-## Bugs
-
-Sometime after install JS app fails to start, issue related Pebble App. Force stop Pebble App and start it again.
diff --git a/appinfo.json b/appinfo.json
index aa6386f..70b40d5 100644
--- a/appinfo.json
+++ b/appinfo.json
@@ -1,12 +1,12 @@
{
"uuid": "9be6e663-b542-49f3-82d9-9bc174ddc63a",
"shortName": "My Data",
- "longName": "My Data",
+ "longName": "My Data (watchface)",
"companyName": "bahbka",
"versionCode": 235,
"versionLabel": "2.3.5",
"watchapp": {
- "watchface": false
+ "watchface": true
},
"capabilities": [ "configurable", "location" ],
"appKeys": {
@@ -23,7 +23,8 @@
"config_location": 10,
"config_vibrate": 11,
"config_seconds": 12,
- "config_shake": 13
+ "config_shake": 13,
+ "config_interval": 14
},
"resources": {
"media": [
diff --git a/resources/configuration.html b/resources/configuration.html
index 59dac4b..bcd8833 100644
--- a/resources/configuration.html
+++ b/resources/configuration.html
@@ -79,7 +79,6 @@ vim: sw=2 ts=2 expandtab ai
Password
<input type="password" id="password" class="text" value="">
- </div>
<hr size="1" />
@@ -92,6 +91,7 @@ vim: sw=2 ts=2 expandtab ai
<input type="checkbox" id="config_location" class="checkbox">
</div>
</div>
+ </div>
<div class="param">
<div class="label">
@@ -121,6 +121,15 @@ vim: sw=2 ts=2 expandtab ai
<input type="checkbox" id="config_shake" class="checkbox">
</div>
</div>
+
+ <div class="param">
+ <div class="label">
+ Update interval in seconds:<br>
+ </div>
+ <div class="checkbox">
+ <input type="text" id="config_interval" class="text" style="width: 100px;">
+ </div>
+ </div>
<input type="submit" id="save" class="submit" value="save and apply">
</form>
diff --git a/src/js/pebble-js-app.src.js b/src/js/pebble-js-app.src.js
index 4bbed74..45d636d 100644
--- a/src/js/pebble-js-app.src.js
+++ b/src/js/pebble-js-app.src.js
@@ -23,7 +23,8 @@ var config = {
"config_location": false,
"config_vibrate": true,
"config_seconds": true,
- "config_shake": false
+ "config_shake": false,
+ "config_interval": 300
};
function extract_fields(raw) {
@@ -40,7 +41,7 @@ function extract_fields(raw) {
"light": INT_FIELD,
"blink": INT_FIELD,
"updown": INT_FIELD,
- "auth": STR_FIELD
+ "auth": STR_FIELD,
};
var result = {};
@@ -90,26 +91,17 @@ function http_request(url) {
if (req.readyState == 4) {
if(req.status == 200) {
try {
- var response = extract_fields(JSON.parse(req.responseText));
+ //var response = extract_fields(JSON.parse(req.responseText));
//console.log("success: " + JSON.stringify(response));
+ var response = req.responseText;
- response["msg_type"] = MSG.JSON_RESPONSE;
-
- if (response["content"] && response["content"].length > CONTENT_MAX_LENGTH) {
- response["content"] = response["content"].substring(0, CONTENT_MAX_LENGTH);
- }
-
- window.localStorage.setItem('pebble-my-data-response', JSON.stringify(response));
- Pebble.sendAppMessage(response);
-
- if (response["auth"] != null) {
- if (response["auth"] == "") {
- window.localStorage.removeItem('pebble-my-data-auth');
- } else if (config["password"]) {
- window.localStorage.setItem('pebble-my-data-auth', MD5(MD5(config["password"]) + response["auth"]));
- }
+ if (response && response.length > CONTENT_MAX_LENGTH) {
+ response = response.substring(0, CONTENT_MAX_LENGTH);
}
+ window.localStorage.setItem('pebble-my-data-response', response);
+ //Pebble.sendAppMessage(response);
+ Pebble.sendAppMessage({ "msg_type": MSG.JSON_RESPONSE, "content": response });
} catch(e) {
console.log("json parse error " + e);
Pebble.sendAppMessage({ "msg_type": MSG.ERROR });
@@ -127,35 +119,7 @@ function http_request(url) {
}
function fetch_data(url) {
- if (config["config_location"]) {
- if(navigator.geolocation) {
- navigator.geolocation.getCurrentPosition(
- function(position) {
- var latitude = position.coords.latitude;
- var longitude = position.coords.longitude;
-
- var s = (url.indexOf("?")===-1)?"?":"&";
- http_request(url + s + 'lat=' + latitude + '&lon=' + longitude);
- },
- function(error) {
- //error error.message
- /*
- TODO inform user about error
- PERMISSION_DENIED (numeric value 1)
- POSITION_UNAVAILABLE (numeric value 2)
- TIMEOUT (numeric value 3)
- */
- http_request(url);
- },
- { maximumAge: 600000 } // 10 minutes
- );
- } else {
- //error geolocation not supported
- http_request(url);
- }
- } else {
- http_request(url);
- }
+ http_request(url);
}
Pebble.addEventListener("ready",
@@ -169,10 +133,15 @@ Pebble.addEventListener("ready",
config = JSON.parse(json);
//console.log("loaded config = " + JSON.stringify(config));
config["msg_type"] = MSG.CONFIG;
+ if (("config_interval" in config) && (typeof config["config_interval"] === 'string')) {
+ config["config_interval"] = parseInt(config["config_interval"]);
+ if (isNaN(config["config_interval"])) config["config_interval"] = 300;
+ }
+ //console.log("sending options 1 = " + JSON.stringify(config));
Pebble.sendAppMessage(config); // send current config to pebble
} catch(e) {
- console.log("stored config json parse error");
+ console.log("stored config json parse error: " + json + ' - ' + e);
Pebble.sendAppMessage({ "msg_type": MSG.ERROR });
}
}
@@ -183,8 +152,12 @@ Pebble.addEventListener("appmessage",
function(e) {
//console.log("received message: " + JSON.stringify(e.payload));
- config["msg_type"] = MSG.CONFIG;
- Pebble.sendAppMessage(config); // send current config to pebble
+ if (("config_interval" in config) && (typeof config["config_interval"] === 'string')) {
+ config["config_interval"] = parseInt(config["config_interval"]);
+ if (isNaN(config["config_interval"])) config["config_interval"] = 300;
+ }
+ //console.log("sending options 2 = " + JSON.stringify(config));
+ Pebble.sendAppMessage(config); // send current config to pebble
if (config["url"]) {
var url = config["url"];
@@ -192,7 +165,7 @@ Pebble.addEventListener("appmessage",
if (e.payload["refresh"] == MSG.IN_RETRY) {
response = window.localStorage.getItem('pebble-my-data-response');
- Pebble.sendAppMessage(JSON.parse(response));
+ Pebble.sendAppMessage({ "msg_type": MSG.JSON_RESPONSE, "content": response });
} else {
if (e.payload["refresh"] == MSG.SELECT_SHORT_PRESS_UPDATE) {
@@ -242,7 +215,14 @@ Pebble.addEventListener("webviewclosed", function(e) {
window.localStorage.setItem('pebble-my-data', e.response);
config["msg_type"] = MSG.CONFIG;
+ //config = extract_fields(config);
//console.log("push config = " + JSON.stringify(config));
+
+ if (("config_interval" in config) && (typeof config["config_interval"] === 'string')) {
+ config["config_interval"] = parseInt(config["config_interval"]);
+ if (isNaN(config["config_interval"])) config["config_interval"] = 300;
+ }
+ //console.log("sending options 3 = " + JSON.stringify(config));
Pebble.sendAppMessage(config); // send current config to pebble
if (config["url"]) {
diff --git a/src/pebble-my-data.c b/src/pebble-my-data.c
index 4bbf371..c9110a0 100644
--- a/src/pebble-my-data.c
+++ b/src/pebble-my-data.c
@@ -47,12 +47,12 @@ static uint8_t blink_count;
bool config_vibrate = true;
bool config_seconds = false;
bool config_shake = false;
+int config_interval = 300;
bool updown = false;
bool update_in_progress = false;
-#define DEFAULT_REFRESH 300*1000
#define RETRY_DELAY 60*1000
#define IN_RETRY_DELAY 100
#define REQUEST_TIMEOUT 30*1000
@@ -80,7 +80,8 @@ enum { // AppMessage keys
KEY_CONFIG_LOCATION,
KEY_CONFIG_VIBRATE,
KEY_CONFIG_SECONDS,
- KEY_CONFIG_SHAKE
+ KEY_CONFIG_SHAKE,
+ KEY_CONFIG_INTERVAL
};
enum { // msg type
@@ -504,6 +505,7 @@ void in_received_handler(DictionaryIterator *received, void *context) {
} else {
config_vibrate = false;
}
+ persist_write_bool(KEY_CONFIG_VIBRATE, config_vibrate);
}
Tuple *config_seconds_tuple = dict_find(received, KEY_CONFIG_SECONDS);
@@ -520,6 +522,7 @@ void in_received_handler(DictionaryIterator *received, void *context) {
handle_timer_tick(NULL, MINUTE_UNIT);
}
}
+ persist_write_bool(KEY_CONFIG_SECONDS, config_seconds);
}
Tuple *config_shake_tuple = dict_find(received, KEY_CONFIG_SHAKE);
@@ -535,8 +538,16 @@ void in_received_handler(DictionaryIterator *received, void *context) {
accel_tap_service_unsubscribe();
}
}
+ persist_write_bool(KEY_CONFIG_SHAKE, config_shake);
}
+ Tuple *interval = dict_find(received, KEY_CONFIG_INTERVAL);
+ if (interval) {
+ config_interval = interval->value->uint32;
+ if (config_interval)
+ schedule_update(config_interval*1000, MSG_PERIODIC_UPDATE);
+ persist_write_int(KEY_CONFIG_INTERVAL, config_interval);
+ }
// TODO location icon?
} else if (msg_type_tuple->value->uint8 == MSG_ERROR) {
@@ -551,6 +562,7 @@ void in_received_handler(DictionaryIterator *received, void *context) {
Tuple *content_tuple = dict_find(received, KEY_CONTENT);
if (content_tuple) {
memcpy(content, content_tuple->value->cstring, strlen(content_tuple->value->cstring) + 1);
+ persist_write_string(KEY_CONTENT, content);
Tuple *scroll_offset_tuple = dict_find(received, KEY_SCROLL);
uint8_t scroll_offset = DONT_SCROLL;
@@ -620,14 +632,11 @@ void in_received_handler(DictionaryIterator *received, void *context) {
}
}
- // schedule next update
- uint32_t delay = DEFAULT_REFRESH;
- Tuple *refresh = dict_find(received, KEY_REFRESH);
- if (refresh) {
- delay = refresh->value->uint32 * 1000;
- }
+ if (config_shake)
+ accel_tap_service_subscribe(handle_shake);
- schedule_update(delay, MSG_PERIODIC_UPDATE);
+ if (config_interval)
+ schedule_update(config_interval*1000, MSG_PERIODIC_UPDATE);
}
}
}
@@ -716,6 +725,15 @@ static void click_config_provider_updown(void *context) {
// prepare window!
static void window_load(Window *window) {
+ if (persist_exists(KEY_CONFIG_VIBRATE))
+ config_vibrate = persist_read_bool(KEY_CONFIG_VIBRATE);
+ if (persist_exists(KEY_CONFIG_SECONDS))
+ config_seconds = persist_read_bool(KEY_CONFIG_SECONDS);
+ if (persist_exists(KEY_CONFIG_SHAKE))
+ config_shake = persist_read_bool(KEY_CONFIG_SHAKE);
+ if (persist_exists(KEY_CONFIG_INTERVAL))
+ config_interval = persist_read_int(KEY_CONFIG_INTERVAL);
+
Layer *window_layer = window_get_root_layer(window);
// time layers
@@ -789,8 +807,16 @@ static void window_load(Window *window) {
bluetooth_connection_service_subscribe(&handle_bluetooth);
handle_bluetooth(bluetooth_connection_service_peek());
- tick_timer_service_subscribe(MINUTE_UNIT, handle_timer_tick);
+ if (config_seconds)
+ tick_timer_service_subscribe(SECOND_UNIT, handle_timer_tick);
+ else
+ tick_timer_service_subscribe(MINUTE_UNIT, handle_timer_tick);
handle_timer_tick(NULL, MINUTE_UNIT);
+
+ if (persist_exists(KEY_CONTENT)) {
+ persist_read_string(KEY_CONTENT, content, sizeof(content));
+ update_info_layer(content, 0, DONT_SCROLL, false);
+ }
}
static void window_unload(Window *window) {