@skylord123/node-red-pebble-timeline 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(xargs:*)",
5
+ "Bash(find:*)",
6
+ "WebSearch",
7
+ "WebFetch(domain:developer.rebble.io)",
8
+ "WebFetch(domain:github.com)"
9
+ ]
10
+ }
11
+ }
@@ -0,0 +1,124 @@
1
+ [
2
+ {
3
+ "id": "sync-flow-tab",
4
+ "type": "tab",
5
+ "label": "Rebble Timeline Sync",
6
+ "disabled": false,
7
+ "info": "Flow to fetch timeline pins from Rebble sync endpoint"
8
+ },
9
+ {
10
+ "id": "inject-token",
11
+ "type": "inject",
12
+ "z": "sync-flow-tab",
13
+ "name": "Set Access Token",
14
+ "props": [
15
+ {
16
+ "p": "access_token",
17
+ "v": "YOUR_ACCESS_TOKEN_HERE",
18
+ "vt": "str"
19
+ }
20
+ ],
21
+ "repeat": "",
22
+ "crontab": "",
23
+ "once": false,
24
+ "onceDelay": 0.1,
25
+ "topic": "",
26
+ "x": 140,
27
+ "y": 100,
28
+ "wires": [
29
+ ["setup-request"]
30
+ ]
31
+ },
32
+ {
33
+ "id": "setup-request",
34
+ "type": "function",
35
+ "z": "sync-flow-tab",
36
+ "name": "Setup Request",
37
+ "func": "msg.url = 'https://timeline-sync.rebble.io/v1/sync';\nmsg.headers = {\n 'Authorization': 'Bearer ' + msg.access_token\n};\n\n// Optional: pass timeline/glance cursor for incremental sync\nif (msg.timeline) {\n msg.url += '?timeline=' + msg.timeline;\n if (msg.glance) {\n msg.url += '&glance=' + msg.glance;\n }\n} else if (msg.glance) {\n msg.url += '?glance=' + msg.glance;\n}\n\nreturn msg;",
38
+ "outputs": 1,
39
+ "timeout": "",
40
+ "noerr": 0,
41
+ "initialize": "",
42
+ "finalize": "",
43
+ "libs": [],
44
+ "x": 340,
45
+ "y": 100,
46
+ "wires": [
47
+ ["http-request"]
48
+ ]
49
+ },
50
+ {
51
+ "id": "http-request",
52
+ "type": "http request",
53
+ "z": "sync-flow-tab",
54
+ "name": "GET /v1/sync",
55
+ "method": "GET",
56
+ "ret": "obj",
57
+ "paytoqs": "ignore",
58
+ "url": "",
59
+ "tls": "",
60
+ "persist": false,
61
+ "proxy": "",
62
+ "insecureHTTPParser": false,
63
+ "authType": "",
64
+ "senderr": false,
65
+ "headers": [],
66
+ "x": 530,
67
+ "y": 100,
68
+ "wires": [
69
+ ["debug-output", "parse-response"]
70
+ ]
71
+ },
72
+ {
73
+ "id": "debug-output",
74
+ "type": "debug",
75
+ "z": "sync-flow-tab",
76
+ "name": "Sync Response",
77
+ "active": true,
78
+ "tosidebar": true,
79
+ "console": false,
80
+ "tostatus": false,
81
+ "complete": "payload",
82
+ "targetType": "msg",
83
+ "statusVal": "",
84
+ "statusType": "auto",
85
+ "x": 740,
86
+ "y": 60,
87
+ "wires": []
88
+ },
89
+ {
90
+ "id": "parse-response",
91
+ "type": "function",
92
+ "z": "sync-flow-tab",
93
+ "name": "Parse Updates",
94
+ "func": "// Extract updates array and syncURL for next request\nlet response = msg.payload;\n\nif (response.updates && response.updates.length > 0) {\n node.status({fill: 'green', shape: 'dot', text: response.updates.length + ' updates'});\n} else {\n node.status({fill: 'yellow', shape: 'ring', text: 'No updates'});\n}\n\n// Store syncURL for subsequent requests\nmsg.syncURL = response.syncURL;\nmsg.updates = response.updates || [];\n\nreturn msg;",
95
+ "outputs": 1,
96
+ "timeout": "",
97
+ "noerr": 0,
98
+ "initialize": "",
99
+ "finalize": "",
100
+ "libs": [],
101
+ "x": 740,
102
+ "y": 140,
103
+ "wires": [
104
+ ["debug-updates"]
105
+ ]
106
+ },
107
+ {
108
+ "id": "debug-updates",
109
+ "type": "debug",
110
+ "z": "sync-flow-tab",
111
+ "name": "Parsed Updates",
112
+ "active": true,
113
+ "tosidebar": true,
114
+ "console": false,
115
+ "tostatus": false,
116
+ "complete": "true",
117
+ "targetType": "full",
118
+ "statusVal": "",
119
+ "statusType": "auto",
120
+ "x": 940,
121
+ "y": 140,
122
+ "wires": []
123
+ }
124
+ ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skylord123/node-red-pebble-timeline",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Node-RED nodes for interacting with the Pebble Timeline API",
5
5
  "keywords": [
6
6
  "node-red",
@@ -19,7 +19,9 @@
19
19
  }
20
20
  },
21
21
  "dependencies": {
22
- "axios": "^1.3.4",
22
+ "axios": "1.12.0",
23
23
  "fs-extra": "^11.1.0"
24
24
  }
25
25
  }
26
+
27
+
@@ -187,6 +187,7 @@
187
187
  label: function() {
188
188
  return this.name || "Add Timeline Pin";
189
189
  },
190
+ paletteLabel: "Add Timeline Pin",
190
191
  oneditprepare: function() {
191
192
  // Setup TypedInput for server override options
192
193
  $("#node-input-apiUrl").typedInput({
@@ -23,6 +23,7 @@
23
23
  label: function () {
24
24
  return this.name || "Delete Timeline Pin";
25
25
  },
26
+ paletteLabel: "Delete Timeline Pin",
26
27
  oneditprepare: function () {
27
28
  // Setup TypedInput for server override options
28
29
  $("#node-input-apiUrl").typedInput({
@@ -115,17 +115,37 @@ module.exports = function(RED) {
115
115
  if (done) done();
116
116
  })
117
117
  .catch(error => {
118
- node.status({fill: "red", shape: "dot", text: "Error: " + (error.response ? error.response.status : error.message)});
119
-
120
- msg.payload = {
121
- success: false,
122
- pinId: pinId,
123
- error: error.message,
124
- response: error.response ? error.response.data : null
125
- };
126
-
127
- send(msg);
128
- if (done) done(error);
118
+ // Handle 404 - pin already deleted
119
+ if (error.response && error.response.status === 404) {
120
+ node.warn(`Pin ${pinId} not found on server (404) - assuming already deleted`);
121
+ node.status({fill: "yellow", shape: "dot", text: "Pin already deleted"});
122
+
123
+ // Remove from local storage anyway
124
+ removePin(pinId, timelineToken);
125
+
126
+ msg.payload = {
127
+ success: true,
128
+ pinId: pinId,
129
+ alreadyDeleted: true,
130
+ message: "Pin not found on server, removed from local storage"
131
+ };
132
+
133
+ send(msg);
134
+ if (done) done();
135
+ } else {
136
+ // Other errors
137
+ node.status({fill: "red", shape: "dot", text: "Error: " + (error.response ? error.response.status : error.message)});
138
+
139
+ msg.payload = {
140
+ success: false,
141
+ pinId: pinId,
142
+ error: error.message,
143
+ response: error.response ? error.response.data : null
144
+ };
145
+
146
+ send(msg);
147
+ if (done) done(error);
148
+ }
129
149
  });
130
150
  }).catch(err => {
131
151
  if (done) done(err);
@@ -26,6 +26,7 @@
26
26
  label: function () {
27
27
  return this.name || "List Timeline Pins";
28
28
  },
29
+ paletteLabel: "List Timeline Pins",
29
30
  oneditprepare: function () {
30
31
  // Setup TypedInput for server override options
31
32
  $("#node-input-apiUrl").typedInput({
@@ -107,7 +108,7 @@
107
108
  </script>
108
109
 
109
110
  <script type="text/html" data-help-name="pebble-timeline-list">
110
- <p>Lists pins that have been added to the Pebble Timeline.</p>
111
+ <p>Lists pins from the local storage file that tracks pins added via Node-RED.</p>
111
112
 
112
113
  <h3>Inputs</h3>
113
114
  <dl class="message-properties">
@@ -128,9 +129,13 @@
128
129
  </dl>
129
130
 
130
131
  <h3>Details</h3>
131
- <p>This node lists pins that have been successfully added to the Pebble Timeline. The pins are stored locally in the
132
- Node-RED installation directory, organized by timeline token.</p>
133
- <p>Only pins associated with the current timeline token will be listed. Each token maintains its own separate list of pins.</p>
132
+ <p><strong>Important:</strong> This node does <strong>not</strong> fetch pins from the remote Pebble Timeline server.
133
+ Instead, it reads from a local file (<code>timeline-pins.json</code>) stored in the Node-RED user directory.</p>
134
+ <p>The local file is automatically updated whenever you use the <strong>pebble-timeline-add</strong> or
135
+ <strong>pebble-timeline-delete</strong> nodes. This provides a local record of pins that have been
136
+ added or removed via Node-RED.</p>
137
+ <p>Pins are organized by timeline token in the storage file. Only pins associated with the current timeline
138
+ token will be listed. Each token maintains its own separate list of pins.</p>
134
139
  <p>You can filter the pins by start and end times. The times should be in ISO date-time format (e.g.,
135
140
  2023-01-01T12:00:00Z).</p>
136
141
  <p>By default, if no filters are specified, all pins for the current token will be returned.</p>
@@ -138,9 +143,10 @@
138
143
 
139
144
  <h4>Example Use Cases</h4>
140
145
  <ul>
141
- <li>List all upcoming events for the day</li>
146
+ <li>List all upcoming events for the day that were added via Node-RED</li>
142
147
  <li>Filter pins for a specific date range for reporting</li>
143
148
  <li>Show pins for a specific event type based on time criteria</li>
149
+ <li>Track what pins have been sent to the Pebble Timeline</li>
144
150
  </ul>
145
151
 
146
152
  <h3>References</h3>