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 '' >> 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;