totalsync-webinterface 0.1.1__py3-none-any.whl

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.
Files changed (32) hide show
  1. totalsync_webinterface/__init__.py +8 -0
  2. totalsync_webinterface/camera.py +163 -0
  3. totalsync_webinterface/curses_interface.py +142 -0
  4. totalsync_webinterface/fake_picamera.py +81 -0
  5. totalsync_webinterface/packet.py +194 -0
  6. totalsync_webinterface/pin_sheet.py +101 -0
  7. totalsync_webinterface/serial_dummy.py +92 -0
  8. totalsync_webinterface/serial_dump.py +66 -0
  9. totalsync_webinterface/teensy_commander.py +490 -0
  10. totalsync_webinterface/web/CanvasCamera.js +33 -0
  11. totalsync_webinterface/web/CanvasPlot.js +71 -0
  12. totalsync_webinterface/web/favicon.ico +0 -0
  13. totalsync_webinterface/web/index.html +31 -0
  14. totalsync_webinterface/web/interface.js +342 -0
  15. totalsync_webinterface/web/reconnecting-websocket/LICENSE.txt +21 -0
  16. totalsync_webinterface/web/reconnecting-websocket/README.md +149 -0
  17. totalsync_webinterface/web/reconnecting-websocket/package.json +19 -0
  18. totalsync_webinterface/web/reconnecting-websocket/reconnecting-websocket.js +365 -0
  19. totalsync_webinterface/web/style.css +165 -0
  20. totalsync_webinterface/web/webgl-plot/LICENSE +21 -0
  21. totalsync_webinterface/web/webgl-plot/README.md +184 -0
  22. totalsync_webinterface/web/webgl-plot/dist/webglplot.esm.js +619 -0
  23. totalsync_webinterface/web/webgl-plot/package.json +42 -0
  24. totalsync_webinterface/web_interface.py +268 -0
  25. totalsync_webinterface/websocket_server/LICENSE +21 -0
  26. totalsync_webinterface/websocket_server/__init__.py +1 -0
  27. totalsync_webinterface/websocket_server/websocket_server.py +377 -0
  28. totalsync_webinterface-0.1.1.dist-info/METADATA +41 -0
  29. totalsync_webinterface-0.1.1.dist-info/RECORD +32 -0
  30. totalsync_webinterface-0.1.1.dist-info/WHEEL +4 -0
  31. totalsync_webinterface-0.1.1.dist-info/entry_points.txt +2 -0
  32. totalsync_webinterface-0.1.1.dist-info/licenses/LICENSE +676 -0
@@ -0,0 +1,71 @@
1
+ import {WebglPlot, ColorRGBA, WebglLine} from "./webgl-plot/dist/webglplot.esm.js";
2
+
3
+ // TODO: Input buffer + downsampling for extended periods
4
+ // TODO: Interactivity (pause, zoom, select, time on axis)
5
+
6
+ export class Plot {
7
+ constructor(canvasID, numX, cfg) {
8
+ this.canvasID = canvasID;
9
+ this.canvas = document.getElementById(`canvas_${canvasID}`);
10
+ const devicePixelRatio = window.devicePixelRatio || 1;
11
+ this.canvas.width = this.canvas.clientWidth * devicePixelRatio;
12
+ this.canvas.height = this.canvas.clientHeight * devicePixelRatio;
13
+ console.log(`Plot on canvas ${canvasID}: ${this.canvas.width} x ${this.canvas.height}`);
14
+
15
+ this.numX = numX;
16
+ this.cfg = cfg[this.canvasID];
17
+
18
+ this.numLines = this.cfg.numLines;
19
+
20
+ this.plot = new WebglPlot(this.canvas);
21
+ this.plot.removeAllLines();
22
+ this.lines = [];
23
+
24
+ let nLine = 0;
25
+ for (const [partitionID, partition] of Object.entries(this.cfg.partitions)) {
26
+ for (let i = 0; i < partition.numLines; i++) {
27
+ const rgb = getColor(document.getElementById(`${partitionID}_${i}`).style.backgroundColor)
28
+ const color = new ColorRGBA(rgb[0], rgb[1], rgb[2], 1);
29
+
30
+ const line = new WebglLine(color, this.numX);
31
+ line.lineSpaceX(-1, 2 / this.numX); // fill x with numX -1...1 array
32
+ line.offsetY = 2*(this.numLines-nLine-1)/(this.numLines)-1;
33
+ line.scaleY = partition.scaleFactors ? partition.scaleFactors[i] : 1;
34
+ this.plot.addLine(line);
35
+ this.lines.push(line);
36
+ nLine++;
37
+ }
38
+ }
39
+
40
+ // fill with zeros at start
41
+ let data = new Array(numX).fill(0);
42
+ this.lines.forEach((line) => {
43
+ line.shiftAdd(data);
44
+ });
45
+ this.plot.gScaleX = 1;
46
+ }
47
+
48
+ update_data(packets) {
49
+ if (packets == null) return;
50
+ let nLine = 0;
51
+ for (const [partitionID, partition] of Object.entries(this.cfg.partitions)) {
52
+ for (let i=0; i < partition.numLines; i++) {
53
+ const data = [];
54
+ packets.forEach((packet) => {
55
+ data.push(packet[partition.dataID][i]);
56
+ });
57
+ this.lines[nLine].shiftAdd(data);
58
+ nLine++;
59
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+ function getColor(rgb) {
65
+ let sep = rgb.indexOf(",") > -1 ? "," : " ";
66
+ rgb = rgb.substring(4).split(")")[0].split(sep);
67
+ let r = parseInt(rgb[0]),
68
+ g = parseInt(rgb[1]),
69
+ b = parseInt(rgb[2]);
70
+ return [r / 255, g / 255, b / 255];
71
+ }
Binary file
@@ -0,0 +1,31 @@
1
+ <!DOCTYPE html>
2
+
3
+ <meta charset="UTF-8">
4
+
5
+ <html lang="en-us">
6
+ <script type="text/javascript" src="reconnecting-websocket/reconnecting-websocket.js"></script>
7
+ <head>
8
+ <link rel="stylesheet" href="style.css">
9
+ <title>Data logger interface</title>
10
+ </head>
11
+ <body>
12
+ <div class="container-grid">
13
+ <div class="chart" id="chart_analog">
14
+ <canvas id="canvas_analog"></canvas>
15
+ </div>
16
+ <div class="label-grid" id="grid_analog" style="background-color:#ccc"></div>
17
+
18
+ <div class="videoStreamContainer">
19
+ <img id="videoStream" src="" alt="No Stream" style="width: 100%; height:100%;object-fit:contain">
20
+ <button id="videoStreamButton">Reconnect</button>
21
+ </div>
22
+
23
+ <div class="chart" id="chart_digital">
24
+ <canvas id="canvas_digital"></canvas>
25
+ </div>
26
+ <div class="label-grid" id="grid_digital" style="background-color:#ccc"></div>
27
+
28
+ </div>
29
+ </body>
30
+ <script type="module" src="interface.js"></script>
31
+ </html>
@@ -0,0 +1,342 @@
1
+ // noinspection DuplicatedCode
2
+
3
+ import {Plot} from "./CanvasPlot.js";
4
+ //import {Game} from "./CanvasGame.js";
5
+ import {CameraView} from "./CanvasCamera.js";
6
+
7
+
8
+ let countUpdateTextDisplay = 0;
9
+ let updateModulator = 1; // only update every xth time the update function is called
10
+ let allLabels = [];
11
+ let numPoints = 2000;
12
+ const downsamplingFactor = 5;
13
+ const numAnalogIn = 8;
14
+ const numStates = 8;
15
+ const numDigitalIn = 16;
16
+ const numDigitalOut = 16;
17
+
18
+ const plotConfig = {
19
+ analog: {
20
+ numLines: numAnalogIn + numStates,
21
+ partitions: {
22
+ analog_input: {
23
+ dataID: 'analog',
24
+ numLines: numAnalogIn,
25
+ hasButton: false,
26
+ hasIndicator: false,
27
+ scaleFactors: new Array(numAnalogIn).fill(2 ** -13 * -0.9),
28
+ units: new Array(numAnalogIn).fill('V'),
29
+ unitFormat: (x) => `${(x * 2 ** -12 * 3.3).toFixed(2)}`,
30
+ colorFormat: (i, numLines) => `hsl(${180 / numLines * i}, 80%, 60%)`
31
+ },
32
+ states: {
33
+ dataID: 'states',
34
+ numLines: numStates,
35
+ hasButton: false,
36
+ hasIndicator: false,
37
+ scaleFactors: new Array(numAnalogIn).fill(2 ** -15 * 0.9), //[2 ** -16.5, 2 ** -10, 2 ** -12, 2 ** -12, 1 / 25, 2 ** -22, 2 ** -22, 2 ** -22],
38
+ units: ['turn', '', '', '', '', '', '', ''],
39
+ unitFormat: (x) => `${x >= 0 ? '0' : ''}${(x).toFixed(2)}`,
40
+ colorFormat: (i, numLines) => `hsl(${180 / numLines * i + 180}, 40%, 50%)`
41
+ },
42
+ }
43
+ },
44
+ digital: {
45
+ numLines: numDigitalIn + numDigitalOut,
46
+ partitions: {
47
+ digital_input: {
48
+ dataID: 'digitalIn',
49
+ numLines: numDigitalIn,
50
+ hasButton: false,
51
+ hasIndicator: '#0F0',
52
+ colorFormat: (i, numLines) => `hsl(${90 / numLines * i}, 80%, 60%)`,
53
+ scaleFactors: new Array(numDigitalIn).fill(1 / (15))
54
+ },
55
+ digital_output: {
56
+ dataID: 'digitalOut',
57
+ numLines: numDigitalOut,
58
+ hasButton: true,
59
+ hasIndicator: '#F00',
60
+ colorFormat: (i, numLines) => `hsl(${120 / numLines * i + 120}, 80%, 60%)`,
61
+ scaleFactors: new Array(numDigitalIn).fill(1 / (15))
62
+ },
63
+ }
64
+ }
65
+ };
66
+
67
+ let wgl_plots = [];
68
+ //let game_plot = new GamePlot();
69
+
70
+ let host_url;
71
+ let ws;
72
+ let message_queue = [];
73
+
74
+ //let game;
75
+ let camera;
76
+
77
+ // Labels from the pin sheet totalsync was started with, keyed by channel name:
78
+ // {"digital_input_2": "Wheel Encoder A", ...}. The server bakes these into
79
+ // index.html (see web_interface.send_index), so they are here before the first line
80
+ // is drawn; empty when totalsync was started without --pinsheet.
81
+ const channelLabels = window.CHANNEL_LABELS ?? {};
82
+ // Says in the console whether the labels reached the page, so "the names are not
83
+ // showing" can be told apart from "totalsync was started without --pinsheet" without
84
+ // having to read the DOM.
85
+ console.info(`Channel labels from pin sheet: ${Object.keys(channelLabels).length}`);
86
+
87
+ createUI(channelLabels);
88
+ init();
89
+
90
+ // Resize Handling, to prevent recalculation spam during event
91
+ let resizeId;
92
+ window.addEventListener("resize", () => {
93
+ window.clearTimeout(resizeId);
94
+ resizeId = window.setTimeout(doneResizing, 500);
95
+ });
96
+
97
+ function processMessages() {
98
+ // are we buffering too much?
99
+ if (message_queue.length > 10000) {
100
+ message_queue = [];
101
+ }
102
+ let packets = [];
103
+ let dsPackets = [];
104
+ while (message_queue.length >= downsamplingFactor) {
105
+ packets = message_queue.splice(0, downsamplingFactor);
106
+ dsPackets.push(packets[packets.length - 1]);
107
+ }
108
+
109
+ if (!dsPackets.length) return;
110
+ updateTextDisplay(dsPackets[dsPackets.length - 1]);
111
+ //game.update(dsPackets[dsPackets.length - 1]);
112
+ wgl_plots.forEach((plot) => {
113
+ plot.update_data(dsPackets);
114
+ plot.plot.update();
115
+ });
116
+ }
117
+
118
+ // Animation/update_data ticks, maybe lower to 30 fps?
119
+ function newFrame() {
120
+ processMessages();
121
+ requestAnimationFrame(newFrame);
122
+ }
123
+
124
+ requestAnimationFrame(newFrame);
125
+
126
+ function add_label(grid, channel_name, color, box = null, buttons = null, labels = {}) {
127
+ const div = document.createElement("div");
128
+ div.className = "label";
129
+ div.id = channel_name;
130
+ div.style.backgroundColor = color;
131
+ // Hovering the row still tells you which channel it is when a pin sheet label
132
+ // has replaced the name. It goes on the row, not on the text: .channel_name is
133
+ // pointer-events:none, and an element that takes no pointer events shows no
134
+ // tooltip either.
135
+ div.title = channel_name;
136
+ const p = document.createElement("div");
137
+ p.className = "channel_name";
138
+ p.id = channel_name;
139
+ // What the pin is wired to, when the pin sheet says so. Only the displayed text
140
+ // changes: the element ids stay as they are, because the buttons and the value
141
+ // fields are addressed through them, and so is the channel order in the plot.
142
+ p.textContent = labels[channel_name] ?? channel_name;
143
+
144
+ if (box != null) {
145
+ div.appendChild(box);
146
+ }
147
+ div.appendChild(p);
148
+ if (buttons != null) {
149
+ for (const btn of buttons) div.appendChild(btn);
150
+ }
151
+ grid.appendChild(div);
152
+ return div;
153
+ }
154
+
155
+ function add_spaceholder(grid, channel_name, numLines, numLines_max) {
156
+ const div = document.createElement("div");
157
+ div.className = "generalLabel";
158
+ div.id = channel_name;
159
+ div.style.backgroundColor = '#000';
160
+ if (channel_name.includes('analog')){
161
+ div.style.gridRow = "span " + numLines + " / " + numLines;
162
+ div.innerHTML = "Analog In";
163
+ }else if(channel_name.includes('states')){
164
+ div.style.gridRow = "span " + numLines + " / " + numLines_max;
165
+ div.innerHTML = "States";
166
+ }else if(channel_name.includes('digital_input')){
167
+ div.style.gridRow = "span " + numLines + " / " + numLines;
168
+ div.innerHTML = "Digital In";
169
+ }else if(channel_name.includes('digital_output')){
170
+ div.style.gridRow = "span " + numLines + " / " + numLines_max;
171
+ div.innerHTML = "Digital Out";
172
+ }
173
+ div.style.gridColumn = "2";
174
+ grid.appendChild(div);
175
+ return div;
176
+ }
177
+
178
+ function createUI(labels = {}) {
179
+ let addholder = true;
180
+ for (const [canvasID, cfg] of Object.entries(plotConfig)) {
181
+ let numLines_max = cfg.numLines;
182
+ const label_grid = document.querySelector(`#grid_${canvasID}`);
183
+ for (const [partitionID, partition] of Object.entries(cfg.partitions)) {
184
+ for (let i = 0; i < partition.numLines; i++) {
185
+ if (!i){
186
+ add_spaceholder(label_grid, `${partitionID}_merge`, partition.numLines, numLines_max);
187
+ }
188
+ let color = partition.colorFormat(i, partition.numLines);
189
+ let box;
190
+ let buttons;
191
+
192
+ // unit labels for analog channels and states
193
+ if (partition.units) {
194
+ box = document.createElement('div');
195
+ box.id = `${partitionID}_${i}`;
196
+ box.className = `unit_field ${partitionID}`
197
+ }
198
+
199
+ // digital indicator box
200
+ if (partition.hasIndicator) {
201
+ box = document.createElement('div');
202
+ box.className = "indicator";
203
+ box.id = `${partitionID}_${i}`;
204
+ }
205
+
206
+ // toggle buttons for digital output channels
207
+ if (partition.hasButton) {
208
+ const button_labels = {'toggle': 'TOGGLE', 'low': 'OFF', 'high': 'ON'};
209
+ buttons = Object.entries(button_labels).map(([btn_type, btn_label]) => {
210
+ const btn = document.createElement('button');
211
+ let text = document.createTextNode(btn_label);
212
+ btn.appendChild(text);
213
+ btn.className = "digital_button";
214
+ btn.id = `${partitionID}_${btn_type}_${i}`;
215
+ btn.onmousedown = btn_clicked;
216
+ return btn;
217
+ });
218
+ }
219
+ add_label(label_grid, `${partitionID}_${i}`, color, box, buttons, labels);
220
+
221
+
222
+ }
223
+
224
+ }
225
+ }
226
+ }
227
+
228
+ function init() {
229
+ host_url = window.location.hostname;
230
+ // One Plot per Canvas
231
+ for (const canvasID of Object.keys(plotConfig)) {
232
+ const webgl_plot = new Plot(canvasID, numPoints, plotConfig);
233
+ wgl_plots.push(webgl_plot);
234
+ }
235
+
236
+ // Start Game
237
+ //game = new Game();
238
+ camera = new CameraView("169.254.1.97");
239
+
240
+
241
+ // start accepting messages
242
+ ws = start_websocket(5678);
243
+ ws.onmessage = ws_message_receive;
244
+
245
+
246
+ getLabels();
247
+ }
248
+
249
+ function doneResizing() {
250
+ //wglp.viewport(0, 0, canv.width, canv.height);
251
+ }
252
+
253
+
254
+ function start_websocket(ws_port) {
255
+ const ws = new ReconnectingWebSocket(`ws://${host_url}:${ws_port.toString()}`);
256
+ ws.reconnectInterval = 500;
257
+ ws.maxReconnectInterval = 1000;
258
+ ws.timeoutInterval = 400;
259
+ return ws;
260
+ }
261
+
262
+ function ws_message_receive(event) {
263
+ if (typeof event.data !== 'string') return;
264
+
265
+ let packet;
266
+ try {
267
+ packet = JSON.parse(event.data);
268
+ } catch (e) {
269
+ console.error(e);
270
+ console.log(event.data);
271
+ return;
272
+ }
273
+ message_queue.push(packet);
274
+ }
275
+
276
+ function getLabels(){
277
+ let j = 0;
278
+ for (const [canvasID, cfg] of Object.entries(plotConfig)) {
279
+ for (const [partitionID, partition] of Object.entries(cfg.partitions)) {
280
+ let labelarray = [];
281
+ for (let i = 0; i < partition.numLines; i++) {
282
+ // let x;
283
+ // try {
284
+ // x = packet[partition.dataID][i];
285
+ // } catch (e) {
286
+ // console.error(e);
287
+ // console.debug(partition.dataID);
288
+ // console.debug(partition)
289
+ // }
290
+ if (partition.units) {
291
+ const lbl = document.querySelector(`.unit_field#${partitionID}_${i}`);
292
+ labelarray.push(lbl);
293
+ }
294
+ if (partition.hasIndicator) {
295
+ const indicator = document.querySelector(`.indicator#${partitionID}_${i}`);
296
+ labelarray.push(indicator);
297
+ }
298
+ }
299
+ allLabels[j] = {partitionId: partitionID, partition: partition, label: labelarray};
300
+ j += 1;
301
+ }
302
+ }
303
+ }
304
+
305
+ function updateTextDisplay(packet) {
306
+ countUpdateTextDisplay += 1;
307
+ if (countUpdateTextDisplay%updateModulator) return;
308
+ if (!packet) return;
309
+
310
+ for (let z = 0; z < allLabels.length; z++) {
311
+ for (let i = 0; i < allLabels[z].partition.numLines; i++) {
312
+ let x;
313
+ try {
314
+ x = packet[allLabels[z].partition.dataID][i];
315
+ } catch (e) {
316
+ console.error(e);
317
+ console.debug(allLabels[z].partition.dataID);
318
+ console.debug(allLabels[z].partition)
319
+ }
320
+ if (allLabels[z].partition.units) {
321
+ const lbl = allLabels[z].label[i];
322
+ let lblText = allLabels[z].partition.unitFormat ? allLabels[z].partition.unitFormat(x) : x.toFixed(2);
323
+ if (allLabels[z].partition.units) {
324
+ lblText = lblText + ' ' + allLabels[z].partition.units[i];
325
+ }
326
+ lbl.textContent = lblText;
327
+ }
328
+ if (allLabels[z].partition.hasIndicator) {
329
+ let bg_color = x ? allLabels[z].partition.hasIndicator : '#000'; // hasIndicator is flag and ON color
330
+ const indicator = allLabels[z].label[i];
331
+ indicator.style.backgroundColor = bg_color;
332
+ }
333
+ }
334
+ }
335
+ }
336
+
337
+ function btn_clicked(event) {
338
+ console.log(event.target.id);
339
+ if (ws) {
340
+ ws.send(event.target.id);
341
+ }
342
+ }
@@ -0,0 +1,21 @@
1
+ MIT License:
2
+
3
+ Copyright (c) 2010-2012, Joe Walnes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,149 @@
1
+ ReconnectingWebSocket
2
+ =====================
3
+
4
+ A small JavaScript library that decorates the WebSocket API to provide a WebSocket connection that will automatically reconnect if the connection is dropped.
5
+
6
+ It is API compatible, so when you have:
7
+
8
+ ```javascript
9
+ var ws = new WebSocket('ws://....');
10
+ ```
11
+
12
+ you can replace with:
13
+
14
+ ```javascript
15
+ var ws = new ReconnectingWebSocket('ws://....');
16
+ ```
17
+
18
+ Minified library with gzip compression is less than 600 bytes.
19
+
20
+ How reconnections occur
21
+ -----------------------
22
+
23
+ With the standard `WebSocket` API, the events you receive from the WebSocket instance are typically:
24
+
25
+ onopen
26
+ onmessage
27
+ onmessage
28
+ onmessage
29
+ onclose // At this point the WebSocket instance is dead.
30
+
31
+ With a `ReconnectingWebSocket`, after an `onclose` event is called it will automatically attempt to reconnect. In addition, a connection is attempted repeatedly (with a small pause) until it succeeds. So the events you receive may look something more like:
32
+
33
+ onopen
34
+ onmessage
35
+ onmessage
36
+ onmessage
37
+ onclose
38
+ // ReconnectingWebSocket attempts to reconnect
39
+ onopen
40
+ onmessage
41
+ onmessage
42
+ onmessage
43
+ onclose
44
+ // ReconnectingWebSocket attempts to reconnect
45
+ onopen
46
+ onmessage
47
+ onmessage
48
+ onmessage
49
+ onclose
50
+
51
+ This is all handled automatically for you by the library.
52
+
53
+ ## Parameters
54
+
55
+ ```javascript
56
+ var socket = new ReconnectingWebSocket(url, protocols, options);
57
+ ```
58
+
59
+ #### `url`
60
+ - The URL you are connecting to.
61
+ - https://html.spec.whatwg.org/multipage/comms.html#network
62
+
63
+ #### `protocols`
64
+ - Optional string or array of protocols per the WebSocket spec.
65
+ - https://tools.ietf.org/html/rfc6455
66
+
67
+ #### `options`
68
+ - Options (see below)
69
+
70
+ ## Options
71
+
72
+ Options can either be passed as the 3rd parameter upon instantiation or set directly on the object after instantiation:
73
+
74
+ ```javascript
75
+ var socket = new ReconnectingWebSocket(url, null, {debug: true, reconnectInterval: 3000});
76
+ ```
77
+
78
+ or
79
+
80
+ ```javascript
81
+ var socket = new ReconnectingWebSocket(url);
82
+ socket.debug = true;
83
+ socket.timeoutInterval = 5400;
84
+ ```
85
+
86
+ #### `debug`
87
+ - Whether this instance should log debug messages or not. Debug messages are printed to `console.debug()`.
88
+ - Accepts `true` or `false`
89
+ - Default value: `false`
90
+
91
+ #### `automaticOpen`
92
+ - Whether or not the websocket should attempt to connect immediately upon instantiation. The socket can be manually opened or closed at any time using ws.open() and ws.close().
93
+ - Accepts `true` or `false`
94
+ - Default value: `true`
95
+
96
+ #### `reconnectInterval`
97
+ - The number of milliseconds to delay before attempting to reconnect.
98
+ - Accepts `integer`
99
+ - Default: `1000`
100
+
101
+ #### `maxReconnectInterval`
102
+ - The maximum number of milliseconds to delay a reconnection attempt.
103
+ - Accepts `integer`
104
+ - Default: `30000`
105
+
106
+ ####`reconnectDecay`
107
+ - The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist.
108
+ - Accepts `integer` or `float`
109
+ - Default: `1.5`
110
+
111
+ #### `timeoutInterval`
112
+ - The maximum time in milliseconds to wait for a connection to succeed before closing and retrying.
113
+ - Accepts `integer`
114
+ - Default: `2000`
115
+
116
+ #### `maxReconnectAttempts`
117
+ - The maximum number of reconnection attempts that will be made before giving up. If null, reconnection attempts will be continue to be made forever.
118
+ - Accepts `integer` or `null`.
119
+ - Default: `null`
120
+
121
+ #### `binaryType`
122
+ - The binary type is required by some applications.
123
+ - Accepts strings `'blob'` or `'arraybuffer'`.
124
+ - Default: `'blob'`
125
+
126
+ ---
127
+
128
+ ## Methods
129
+
130
+ #### `ws.open()`
131
+ - Open the Reconnecting Websocket
132
+
133
+ #### `ws.close(code, reason)`
134
+ - Closes the WebSocket connection or connection attempt, if any. If the connection is already CLOSED, this method does nothing.
135
+ - `code` is optional the closing code (default value 1000). [https://tools.ietf.org/html/rfc6455#section-7.4.1](https://tools.ietf.org/html/rfc6455#section-7.4.1)
136
+ - `reason` is the optional reason that the socket is being closed. [https://tools.ietf.org/html/rfc6455#section-7.1.6](https://tools.ietf.org/html/rfc6455#section-7.1.6)
137
+
138
+ #### `ws.refresh()`
139
+ - Refresh the connection if still open (close and then re-open it).
140
+
141
+ #### `ws.send(data)`
142
+ - Transmits data to the server over the WebSocket connection.
143
+ - Accepts @param data a text string, ArrayBuffer or Blob
144
+
145
+ Like this? Check out [websocketd](https://github.com/joewalnes/websocketd) for the simplest way to create WebSocket backends from any programming language.
146
+
147
+ [Follow @joewalnes](https://twitter.com/joewalnes)
148
+
149
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/joewalnes/reconnecting-websocket/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "ReconnectingWebSocket",
3
+ "version": "1.0.1",
4
+ "description": "A small JavaScript library that decorates the WebSocket API to provide a WebSocket connection that will automatically reconnect if the connection is dropped.",
5
+ "main": "reconnecting-websocket.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git://github.com/joewalnes/reconnecting-websocket.git"
12
+ },
13
+ "author": "Joe Walnes",
14
+ "license": "MIT",
15
+ "bugs": {
16
+ "url": "https://github.com/joewalnes/reconnecting-websocket/issues"
17
+ },
18
+ "homepage": "https://github.com/joewalnes/reconnecting-websocket"
19
+ }