diff --git a/.github/workflows/deploy-config.yml b/.github/workflows/deploy-config.yml
new file mode 100644
index 0000000..2e68c8e
--- /dev/null
+++ b/.github/workflows/deploy-config.yml
@@ -0,0 +1,81 @@
+name: Deploy Config UI
+
+on:
+ push:
+ branches: [ battery-reporting ]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ build-and-deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout main repo
+ uses: actions/checkout@v4
+ with:
+ path: main-repo
+
+ - name: Checkout freakified config
+ uses: actions/checkout@v4
+ with:
+ repository: freakified/TimeStylePebble
+ ref: gh-pages
+ path: config-source
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Copy and modify config files
+ run: |
+ mkdir -p main-repo/config
+
+ # Copy all config files
+ cp config-source/config_*.html main-repo/config/
+ cp -r config-source/_includes main-repo/config/
+ cp -r config-source/_layouts main-repo/config/
+ cp -r config-source/images main-repo/config/
+ cp config-source/*.html main-repo/config/ 2>/dev/null || true
+
+ # Add battery sync section to config_common_options.html
+ if [ -f "main-repo/config/_includes/config_common_options.html" ]; then
+ echo '
' >> main-repo/config/_includes/config_common_options.html
+ echo '
' >> main-repo/config/_includes/config_common_options.html
+ echo '' >> main-repo/config/_includes/config_common_options.html
+ echo ' Send battery status updates to a remote HTTP endpoint (e.g., Home Assistant webhook). Leave empty to disable.' >> main-repo/config/_includes/config_common_options.html
+ echo '
' >> main-repo/config/_includes/config_common_options.html
+ echo '' >> main-repo/config/_includes/config_common_options.html
+ echo '' >> main-repo/config/_includes/config_common_options.html
+ echo '
' >> main-repo/config/_includes/config_common_options.html
+ echo '' >> main-repo/config/_includes/config_common_options.html
+ echo '' >> main-repo/config/_includes/config_common_options.html
+ fi
+
+ - name: Update BASE_CONFIG_URL in index.js
+ run: |
+ # Update BASE_CONFIG_URL to point to this repo's GitHub Pages
+ sed -i "s|http://YOUR_CONFIG_HOST_HERE/|https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/|g" main-repo/src/pkjs/index.js
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v5
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: main-repo/config
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/package.json b/package.json
index e3c8b7a..d1c4ec2 100755
--- a/package.json
+++ b/package.json
@@ -63,7 +63,9 @@
"WeatherUseNightIcon",
"SettingWidget0ID",
"SettingWidget1ID",
- "SettingWidget2ID"
+ "SettingWidget2ID",
+ "BatteryPercent",
+ "IsCharging"
],
"resources": {
"media": [
diff --git a/src/c/main.c b/src/c/main.c
index 41808e6..e7c907d 100755
--- a/src/c/main.c
+++ b/src/c/main.c
@@ -146,9 +146,12 @@ void bluetoothStateChanged(bool newConnectionState) {
Sidebar_redraw();
}
-// force the sidebar to redraw any time the battery state changes
+// force the sidebar to redraw any time the battery state changes and send battery data to phone for remote reporting
void batteryStateChanged(BatteryChargeState charge_state) {
+ // Redraw sidebar to show updated battery icon
Sidebar_redraw();
+ // Send battery data to phone for remote reporting
+ messaging_sendBatteryData(charge_state.charge_percent, charge_state.is_charging);
}
// fixes for disappearing elements after notifications
diff --git a/src/c/messaging.c b/src/c/messaging.c
index 6350f6a..cbc41f8 100755
--- a/src/c/messaging.c
+++ b/src/c/messaging.c
@@ -13,6 +13,16 @@ void messaging_requestNewWeatherData() {
app_message_outbox_send();
}
+void messaging_sendBatteryData(uint8_t batteryPercent, bool isCharging) {
+ DictionaryIterator *iter;
+ app_message_outbox_begin(&iter);
+
+ dict_write_uint8(iter, MESSAGE_KEY_BatteryPercent, batteryPercent);
+ dict_write_uint8(iter, MESSAGE_KEY_IsCharging, isCharging ? 1 : 0);
+
+ app_message_outbox_send();
+}
+
void messaging_init(void (*processed_callback)(void)) {
// register my custom callback
message_processed_callback = processed_callback;
diff --git a/src/c/messaging.h b/src/c/messaging.h
index 534513b..c1ea04e 100755
--- a/src/c/messaging.h
+++ b/src/c/messaging.h
@@ -2,6 +2,7 @@
#include
void messaging_requestNewWeatherData();
+void messaging_sendBatteryData(uint8_t batteryPercent, bool isCharging);
void messaging_init(void (*message_processed_callback)(void));
void inbox_received_callback(DictionaryIterator *iterator, void *context);
diff --git a/src/pkjs/index.js b/src/pkjs/index.js
index 670e37f..038a1bc 100755
--- a/src/pkjs/index.js
+++ b/src/pkjs/index.js
@@ -1,9 +1,59 @@
var weather = require('./weather');
-var CONFIG_VERSION = 9;
+var CONFIG_VERSION = 10;
// var BASE_CONFIG_URL = 'http://localhost:3001/';
-var BASE_CONFIG_URL = 'http://freakified.github.io/TimeStylePebble/';
+var BASE_CONFIG_URL = 'https://caco3.github.io/TimeStylePebble/';
+
+// Remote battery endpoint configuration
+var remoteEndpointUrl = '';
+var remoteEndpointToken = '';
+
+// Check if remote endpoint is configured
+function isEndpointConfigured() {
+ return remoteEndpointUrl && remoteEndpointUrl.trim() !== '';
+}
+
+// Send battery data to remote endpoint via HTTP POST with Bearer token
+function sendBatteryToEndpoint(batteryPercent, isCharging) {
+ if (!isEndpointConfigured()) {
+ console.log('Remote endpoint not configured, skipping battery sync');
+ return;
+ }
+
+ console.log('Sending battery data to remote endpoint: ' + batteryPercent + '% (charging: ' + isCharging + ')');
+
+ var req = new XMLHttpRequest();
+ req.open('POST', remoteEndpointUrl, true);
+ req.setRequestHeader('Content-Type', 'application/json');
+
+ // Add Bearer token authorization if provided
+ if (remoteEndpointToken && remoteEndpointToken.trim() !== '') {
+ req.setRequestHeader('Authorization', 'Bearer ' + remoteEndpointToken.trim());
+ }
+
+ req.onload = function() {
+ if (req.readyState === 4) {
+ if (req.status >= 200 && req.status < 300) {
+ console.log('Battery data sent successfully to remote endpoint');
+ } else {
+ console.log('Failed to send battery data to remote endpoint. Status: ' + req.status);
+ }
+ }
+ };
+
+ req.onerror = function() {
+ console.log('Network error sending battery data to remote endpoint');
+ };
+
+ var payload = JSON.stringify({
+ battery_percent: batteryPercent,
+ is_charging: isCharging,
+ timestamp: new Date().toISOString()
+ });
+
+ req.send(payload);
+}
// Listen for when the watchface is opened
Pebble.addEventListener('ready',
@@ -15,6 +65,14 @@ Pebble.addEventListener('ready',
window.localStorage.setItem('disable_weather', 'no');
}
+ // Load remote endpoint configuration from localStorage
+ if (window.localStorage.getItem('remote_endpoint_url')) {
+ remoteEndpointUrl = window.localStorage.getItem('remote_endpoint_url');
+ }
+ if (window.localStorage.getItem('remote_endpoint_token')) {
+ remoteEndpointToken = window.localStorage.getItem('remote_endpoint_token');
+ }
+
console.log('the wdisabled value is: "' + window.localStorage.getItem('disable_weather') + '"');
// if applicable, get the weather data
if (window.localStorage.getItem('disable_weather') != 'yes') {
@@ -29,6 +87,11 @@ Pebble.addEventListener('appmessage',
function (msg) {
console.log('Recieved message: ' + JSON.stringify(msg.payload));
+ // Check if this is a battery status update
+ if (msg.payload.battery_percent !== undefined && msg.payload.is_charging !== undefined) {
+ sendBatteryToEndpoint(msg.payload.battery_percent, msg.payload.is_charging);
+ }
+
// in the case of recieving this, we assume the watch does, in fact, need weather data
window.localStorage.setItem('disable_weather', 'no');
weather.updateWeather();
@@ -244,6 +307,17 @@ Pebble.addEventListener('webviewclosed', function (e) {
}
}
+ // remote battery endpoint settings
+ if (configData.remote_endpoint_url) {
+ remoteEndpointUrl = configData.remote_endpoint_url;
+ window.localStorage.setItem('remote_endpoint_url', configData.remote_endpoint_url);
+ }
+
+ if (configData.remote_endpoint_token) {
+ remoteEndpointToken = configData.remote_endpoint_token;
+ window.localStorage.setItem('remote_endpoint_token', configData.remote_endpoint_token);
+ }
+
// determine whether or not the weather checking should be enabled
var disableWeather;