Initial Pavlok integration

This commit is contained in:
2026-08-18 00:11:00 -04:00
parent 692077f4c4
commit 04bf4b2c45
6 changed files with 168 additions and 4 deletions
+20 -3
View File
@@ -2,14 +2,28 @@
"name": "trigalarm",
"author": "RandyTheSilly",
"version": "1.0.0",
"keywords": ["alarm", "math", "trigonometry", "trig", "triangle"],
"keywords": [
"alarm",
"math",
"trigonometry",
"trig",
"triangle",
"pavlok",
"shock",
"zap"
],
"capabilities": [
"configurable"
],
"private": true,
"dependencies": {},
"dependencies": {
"@rebble/clay": "^1.0.10"
},
"pebble": {
"displayName": "Trigalarm",
"uuid": "293cd38c-4e8c-46ae-a3dc-c789d7ce93ab",
"sdkVersion": "3",
"enableMultiJS": false,
"enableMultiJS": true,
"targetPlatforms": [
"emery",
"gabbro"
@@ -18,6 +32,9 @@
"watchface": false
},
"messageKeys": [
"PKJS_READY",
"PKJS_PAVLOK_ENABLE",
"PKJS_PAVLOK_ENGAGE"
],
"resources": {
"media": [
+36 -1
View File
@@ -170,6 +170,34 @@ static void push_status_window(StatusWindowPurpose purpose) {
window_stack_push(s_status_window, true);
}
////////////////////// PKJS //////////////////////
static void inbox_received_handler(DictionaryIterator *iter, void *context) {
Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_PKJS_READY);
if (ready_tuple) {
return; // TODO use ready signal better
}
Tuple *clay_tuple = dict_find(iter, MESSAGE_KEY_PKJS_PAVLOK_ENABLE);
if (clay_tuple) {
persist_write_bool(STORAGE_KEY_PAVLOK_ENABLED, clay_tuple->value->uint8);
return;
}
}
static void send_stimulus() {
DictionaryIterator *out;
AppMessageResult result = app_message_outbox_begin(&out);
if (result != APP_MSG_OK) {
return;
}
dict_write_uint8(out, MESSAGE_KEY_PKJS_PAVLOK_ENGAGE, 1);
result = app_message_outbox_send();
if (result != APP_MSG_OK) {
return;
}
}
////////////////////// MISC //////////////////////
static bool schedule_alarm(WakeupReason schedule_reason) {
@@ -247,8 +275,11 @@ static void alarm_seconds_handler(struct tm *tick_time, TimeUnits units_changed)
if (s_stopwatch_time[1] == 59) {
s_stopwatch_time[1] = 0;
s_stopwatch_time[0]++;
// zap Pavlok user as punishment for being a total failure
if (persist_read_bool(STORAGE_KEY_PAVLOK_ENABLED) == true) {
send_stimulus();
}
// fall back to main alarm and resume vibes
// if the user fails to solve within a minute
if (s_alarming_for_awareness) {
s_alarming_for_awareness = false;
}
@@ -928,6 +959,10 @@ static void init() {
the_time.HourSet = the_time.HourWIP;
the_time.MinuteSet = the_time.MinuteWIP;
// initialize pkjs TODO maybe only do in alarm mode?
app_message_register_inbox_received(inbox_received_handler);
app_message_open(64, 64); // TODO tighten sizes
switch (launch_reason()) {
case APP_LAUNCH_PHONE: // DEBUG, REMOVE PRIOR TO RELEASE!
case APP_LAUNCH_WAKEUP:
+1
View File
@@ -4,6 +4,7 @@
#define STORAGE_KEY_ALARM_MINUTE 1
#define STORAGE_KEY_ALARMING_FOR_AWARENESS 2
#define STORAGE_KEY_DISABLE_TUTORIAL 3
#define STORAGE_KEY_PAVLOK_ENABLED 4
typedef enum
{
+52
View File
@@ -0,0 +1,52 @@
module.exports = [
{
"type": "heading",
"defaultValue": "Trigalarm | Settings"
},
{
"type": "section",
"items": [
{
"type": "heading",
"size": 3,
"defaultValue": "Pavlok Integration"
},
{
"id": "pavlok_enable",
"type": "toggle",
"messageKey": "PKJS_PAVLOK_ENABLE",
"defaultValue": false,
"label": "Enabled"
},
{
"id": "pavlok_api_key",
"type": "input",
"messageKey": "PKJS_PAVLOK_API_KEY",
"label": "API Key"
},
{
"id": "pavlok_zap_intensity",
"type": "slider",
"messageKey": "PKJS_PAVLOK_ZAP_INTENSITY",
defaultValue: 30,
min: 5,
max: 100,
step: 5,
"label": "Zap Intensity"
},
{
"id": "pavlok_interval",
"type": "slider",
"messageKey": "PKJS_PAVLOK_INTERVAL",
defaultValue: 5,
min: 1,
max: 60,
"label": "Zap Repeat Interval (Seconds - NOT IMPLEMENTED)"
}
]
},
{
"type": "submit",
"defaultValue": "Save Settings"
}
];
+24
View File
@@ -0,0 +1,24 @@
module.exports = function (minified) {
var clayConfig = this;
var _ = minified._;
var $ = minified.$;
var HTML = minified.HTML;
function togglePavlokIntegration() {
if (this.get()) {
clayConfig.getItemById('pavlok_api_key').show();
clayConfig.getItemById('pavlok_zap_intensity').show();
clayConfig.getItemById('pavlok_interval').show();
} else {
clayConfig.getItemById('pavlok_api_key').hide();
clayConfig.getItemById('pavlok_zap_intensity').hide();
clayConfig.getItemById('pavlok_interval').hide();
}
}
clayConfig.on(clayConfig.EVENTS.AFTER_BUILD, function () {
var pavlokIntegrationToggle = clayConfig.getItemById('pavlok_enable');
togglePavlokIntegration.call(pavlokIntegrationToggle);
pavlokIntegrationToggle.on('change', togglePavlokIntegration);
});
};
+35
View File
@@ -0,0 +1,35 @@
var Clay = require('@rebble/clay');
var clayConfig = require('./config');
var customClay = require('./customClay');
new Clay(clayConfig, customClay);
Pebble.addEventListener("ready", function () {
Pebble.sendAppMessage({ PKJS_READY: 1 });
});
Pebble.addEventListener("appmessage", function (dict) {
if (dict.payload["PKJS_PAVLOK_ENGAGE"]) {
const cfg = JSON.parse(localStorage.getItem('clay-settings'));
callAPI(cfg.PKJS_PAVLOK_API_KEY, cfg.PKJS_PAVLOK_ZAP_INTENSITY);
}
});
function callAPI(apiKey, zap_intensity) {
const data = JSON.stringify({
stimulus: {
stimulusType: 'zap',
stimulusValue: zap_intensity,
reason: 'Trigalarm'
}
});
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open('POST', 'https://api.pavlok.com/api/v5/stimulus/send');
xhr.setRequestHeader('accept', 'application/json');
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('Authorization', 'Bearer ' + apiKey);
xhr.send(data);
}