summaryrefslogtreecommitdiffstats
path: root/htdocs/webiopi.js
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2013-12-25 13:25:16 +0100
committermanuel <manuel@mausz.at>2013-12-25 13:25:16 +0100
commit0c8c9ad976879f7c90f9915a60845ccb0cdb337d (patch)
tree162951b4713f3836f4114958a423e2c90ecf9c6b /htdocs/webiopi.js
downloadwebiopi-0c8c9ad976879f7c90f9915a60845ccb0cdb337d.tar.gz
webiopi-0c8c9ad976879f7c90f9915a60845ccb0cdb337d.tar.bz2
webiopi-0c8c9ad976879f7c90f9915a60845ccb0cdb337d.zip
initial commit
Diffstat (limited to 'htdocs/webiopi.js')
-rw-r--r--htdocs/webiopi.js1448
1 files changed, 1448 insertions, 0 deletions
diff --git a/htdocs/webiopi.js b/htdocs/webiopi.js
new file mode 100644
index 0000000..c7eae66
--- /dev/null
+++ b/htdocs/webiopi.js
@@ -0,0 +1,1448 @@
1/*
2 Copyright 2012-2013 Eric Ptak - trouch.com
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17var _gaq = _gaq || [];
18var _webiopi;
19
20function w() {
21 if (_webiopi == undefined) {
22 _webiopi = new WebIOPi();
23 }
24
25 return _webiopi;
26}
27
28function webiopi() {
29 return w();
30}
31
32function isMobileUserAgent(a) {
33 if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))
34 return true
35}
36
37var _isMobile = undefined;
38function isMobile() {
39 if (_isMobile == undefined) {
40 _isMobile = ((navigator.userAgent != undefined && isMobileUserAgent(navigator.userAgent))
41 || (navigator.vendor != undefined && isMobileUserAgent(navigator.vendor))
42 || (window.opera != undefined && isMobileUserAgent(window.opera)))
43 }
44 return _isMobile
45}
46
47function WebIOPi() {
48 this.readyCallback = null;
49 this.context = "/";
50 this.GPIO = Array(54);
51 this.PINS = Array(27);
52
53 this.TYPE = {
54 DNC: {value: 0, style: "DNC", label: "--"},
55 GND: {value: 1, style: "GND", label: "GROUND"},
56 V33: {value: 2, style: "V33", label: "3.3V"},
57 V50: {value: 3, style: "V50", label: "5.0V"},
58 GPIO: {value: 4, style: "GPIO", label: "GPIO"}
59 };
60
61 this.ALT = {
62 I2C: {name: "I2C", enabled: false, gpios: []},
63 SPI: {name: "SPI", enabled: false, gpios: []},
64 UART: {name: "UART", enabled: false, gpios: []},
65 ONEWIRE: {name: "ONEWIRE", enabled: false, gpios: []}
66 };
67
68 // init GPIOs
69 for (var i=0; i<this.GPIO.length; i++) {
70 var gpio = Object();
71 gpio.value = 0;
72 gpio.func = "IN";
73 gpio.mapped = false;
74 this.GPIO[i] = gpio;
75 }
76
77 // get context
78 var reg = new RegExp("http://" + window.location.host + "(.*)webiopi.js");
79 var scripts = document.getElementsByTagName("script");
80 for(var i = 0; i < scripts.length; i++) {
81 var res = reg.exec(scripts[i].src);
82 if (res && (res.length > 1)) {
83 script = scripts[i];
84 this.context = res[1];
85
86 }
87 }
88
89 var head = document.getElementsByTagName('head')[0];
90
91 var jquery = document.createElement('script');
92 jquery.type = 'text/javascript';
93 jquery.src = '/jquery.js';
94 if (!isMobile()) {
95 jquery.onload = function() {
96 w().init();
97 };
98 }
99 head.appendChild(jquery);
100
101 if (isMobile()) {
102 console.log("load jquery mobile");
103 var mobile = document.createElement('script');
104 mobile.type = 'text/javascript';
105 mobile.src = '/jquery-mobile.js';
106 mobile.onload = function() {
107 w().initMobile()
108 };
109 head.appendChild(mobile);
110 }
111
112 // GA
113 _gaq.push(['_setAccount', 'UA-33979593-2']);
114 _gaq.push(['_trackPageview']);
115
116 var ga = document.createElement('script');
117 ga.type = 'text/javascript';
118 ga.async = false;
119 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
120 head.appendChild(ga);
121
122 var style = document.createElement('link');
123 style.rel = "stylesheet";
124 style.type = 'text/css';
125 style.href = '/webiopi.css';
126 head.appendChild(style);
127
128 if (isMobile()) {
129 var style = document.createElement('link');
130 style.rel = "stylesheet";
131 style.type = 'text/css';
132 style.href = '/jquery-mobile.css';
133 head.appendChild(style);
134 }
135
136 // init ALTs
137 this.addALT(this.ALT.I2C, 0, "SDA");
138 this.addALT(this.ALT.I2C, 1, "SCL");
139 this.addALT(this.ALT.I2C, 2, "SDA");
140 this.addALT(this.ALT.I2C, 3, "SCL");
141
142 this.addALT(this.ALT.SPI, 7, "CE1");
143 this.addALT(this.ALT.SPI, 8, "CE0");
144 this.addALT(this.ALT.SPI, 9, "MISO");
145 this.addALT(this.ALT.SPI, 10, "MOSI");
146 this.addALT(this.ALT.SPI, 11, "SCLK");
147
148 this.addALT(this.ALT.UART, 14, "TX");
149 this.addALT(this.ALT.UART, 15, "RX");
150
151 this.addALT(this.ALT.ONEWIRE, 4, "");
152}
153
154WebIOPi.prototype.init = function() {
155 $.getJSON(w().context + "map", function(data) {
156 var count = w().PINS.length;
157 for (i = 0; i<count-1; i++) {
158 var type = w().TYPE.GPIO;
159 var label = data[i];
160
161 if (label == "DNC") {
162 type = w().TYPE.DNC;
163 }
164 else if (label == "GND") {
165 type = w().TYPE.GND;
166 }
167 else if (label == "V33") {
168 type = w().TYPE.V33;
169 }
170 else if (label == "V50") {
171 type = w().TYPE.V50;
172 }
173
174 if (type.value != w().TYPE.GPIO.value) {
175 label = type.label;
176 }
177
178 w().map(i+1, type, label);
179 }
180 if (w().readyCallback != null) {
181 w().readyCallback();
182 }
183
184 w().checkVersion();
185 });
186}
187
188WebIOPi.prototype.initMobile = function() {
189 webiopi().init();
190}
191
192WebIOPi.prototype.ready = function (cb) {
193 w().readyCallback = cb;
194}
195
196WebIOPi.prototype.map = function (pin, type, value) {
197 w().PINS[pin] = Object();
198 w().PINS[pin].type = type
199 w().PINS[pin].value = value;
200
201 if (type.value == w().TYPE.GPIO.value) {
202 w().GPIO[value].mapped = true;
203 }
204}
205
206WebIOPi.prototype.addALT = function (alt, gpio, name) {
207 var o = Object();
208 o.gpio = gpio;
209 o.name = name;
210 alt.gpios.push(o);
211}
212
213WebIOPi.prototype.updateValue = function (gpio, value) {
214 w().GPIO[gpio].value = value;
215 var style = (value == 1) ? "HIGH" : "LOW";
216 $("#gpio"+gpio).attr("class", style);
217}
218
219WebIOPi.prototype.updateFunction = function (gpio, func) {
220 w().GPIO[gpio].func = func;
221 $("#function"+gpio).val(func);
222 $("#function"+gpio).text(func);
223}
224
225WebIOPi.prototype.updateSlider = function (gpio, slider, value) {
226 $("#"+slider+gpio).val(value);
227}
228
229WebIOPi.prototype.updateALT = function (alt, enable) {
230 for (var p in alt.gpios) {
231 gpio = alt.gpios[p].gpio;
232 $("#description"+gpio).empty();
233 if (enable) {
234 $("#description"+gpio).append(alt.name + " " + alt.gpios[p].name);
235 $("#gpio"+gpio).attr("class", alt.name);
236 $("#function"+gpio).attr("class", "FunctionSpecial");
237 }
238 else {
239 $("#description"+gpio).append("GPIO " + gpio);
240 $("#gpio"+gpio).attr("class", "");
241 $("#function"+gpio).attr("class", "FunctionBasic");
242 }
243 }
244 alt.enabled = enable;
245}
246
247WebIOPi.prototype.refreshGPIO = function (repeat) {
248 $.getJSON(w().context + "*", function(data) {
249 w().updateALT(w().ALT.I2C, data["I2C"]);
250 w().updateALT(w().ALT.SPI, data["SPI"]);
251 w().updateALT(w().ALT.UART, data["UART"]);
252 w().updateALT(w().ALT.ONEWIRE, data["ONEWIRE"]);
253
254 $.each(data["GPIO"], function(gpio, data) {
255 w().updateFunction(gpio, data["function"]);
256 if ( ((gpio != 4) && ((data["function"] == "IN") || (data["function"] == "OUT"))
257 || ((gpio == 4) && (w().ALT.ONEWIRE["enabled"] == false)))){
258 w().updateValue(gpio, data["value"]);
259 }
260 else if (data["function"] == "PWM") {
261 w().updateSlider(gpio, "ratio", data["ratio"]);
262 w().updateSlider(gpio, "angle", data["angle"]);
263 }
264
265 });
266 });
267 if (repeat === true) {
268 setTimeout(function(){w().refreshGPIO(repeat)}, 1000);
269 }
270}
271
272
273WebIOPi.prototype.checkVersion = function () {
274 var version;
275
276 $.get(w().context + "version", function(data) {
277 _gaq.push(['_trackEvent', 'version', data]);
278// version = data.split("/")[2];
279//
280// $.get("http://webiopi.trouch.com/version.php", function(data) {
281// var lines = data.split("\n");
282// var c = version.split(".");
283// var n = lines[0].split(".");
284// var updated = false;
285// for (i=0; i<Math.min(c.length, n.length); i++) {
286// if (n[i]>c[i]) {
287// updated = true;
288// }
289// }
290// if (updated || (n.length > c.length)) {
291// var div = $('<div id="update"><a href="' + lines[1] + '">Update available</a></div>');
292// $("body").append(div);
293// }
294// });
295 });
296}
297
298WebIOPi.prototype.digitalRead = function (gpio, callback) {
299 if (callback != undefined) {
300 $.get(w().context + 'GPIO/' + gpio + "/value", function(data) {
301 w().updateValue(gpio, data);
302 callback(gpio, data);
303 });
304 }
305 return w().GPIO[gpio].value;
306}
307
308WebIOPi.prototype.digitalWrite = function (gpio, value, callback) {
309 if (w().GPIO[gpio].func.toUpperCase()=="OUT") {
310 $.post(w().context + 'GPIO/' + gpio + "/value/" + value, function(data) {
311 w().updateValue(gpio, data);
312 if (callback != undefined) {
313 callback(gpio, data);
314 }
315 });
316 }
317 else {
318 //console.log(w().GPIO[gpio].func);
319 }
320}
321
322WebIOPi.prototype.getFunction = function (gpio, callback) {
323 if (callback != undefined) {
324 $.get(w().context + 'GPIO/' + gpio + "/function", function(data) {
325 w().updateFunction(gpio, data);
326 callback(gpio, data);
327 });
328 }
329 return w().GPIO[gpio].func;
330}
331WebIOPi.prototype.setFunction = function (gpio, func, callback) {
332 $.post(w().context + 'GPIO/' + gpio + "/function/" + func, function(data) {
333 w().updateFunction(gpio, data);
334 if (callback != undefined) {
335 callback(gpio, data);
336 }
337 });
338}
339
340WebIOPi.prototype.toggleValue = function (gpio) {
341 var value = (w().GPIO[gpio].value == 1) ? 0 : 1;
342 w().digitalWrite(gpio, value);
343}
344
345WebIOPi.prototype.toggleFunction = function (gpio) {
346 var value = (w().GPIO[gpio].func == "IN") ? "OUT" : "IN";
347 w().setFunction(gpio, value)
348}
349
350WebIOPi.prototype.outputSequence = function (gpio, period, sequence, callback) {
351 $.post(w().context + 'GPIO/' + gpio + "/sequence/" + period + "," + sequence, function(data) {
352 w().updateValue(gpio, data);
353 if (callback != undefined) {
354 callback(gpio, data);
355 }
356 });
357}
358
359WebIOPi.prototype.callMacro = function (macro, args, callback) {
360 if (args == undefined) {
361 args = "";
362 }
363 $.post(w().context + 'macros/' + macro + "/" + args, function(data) {
364 if (callback != undefined) {
365 callback(macro, args, data);
366 }
367 });
368}
369
370WebIOPi.prototype.enablePWM = function(gpio, callback) {
371 $.post(w().context + 'GPIO/' + gpio + "/pwm/enable", function(data) {
372 if (callback != undefined) {
373 callback(gpio, data);
374 }
375 });
376}
377
378WebIOPi.prototype.disablePWM = function(gpio, callback) {
379 $.post(w().context + 'GPIO/' + gpio + "/pwm/disable", function(data) {
380 if (callback != undefined) {
381 callback(gpio, data);
382 }
383 });
384}
385
386WebIOPi.prototype.pulse = function(gpio, callback) {
387 $.post(w().context + 'GPIO/' + gpio + "/pulse/", function(data) {
388 if (callback != undefined) {
389 callback(gpio, data);
390 }
391 });
392}
393
394WebIOPi.prototype.pulseRatio = function(gpio, ratio, callback) {
395 $.post(w().context + 'GPIO/' + gpio + "/pulseRatio/" + ratio, function(data) {
396 if (callback != undefined) {
397 callback(gpio, data);
398 }
399 });
400}
401
402WebIOPi.prototype.pulseAngle = function(gpio, angle, callback) {
403 $.post(w().context + 'GPIO/' + gpio + "/pulseAngle/" + angle, function(data) {
404 if (callback != undefined) {
405 callback(gpio, data);
406 }
407 });
408}
409
410WebIOPi.prototype.setLabel = function (id, label) {
411 $("#" + id).val(label);
412 $("#" + id).text(label);
413}
414
415WebIOPi.prototype.setClass = function (id, cssClass) {
416 $("#" + id).attr("class", cssClass);
417}
418
419WebIOPi.prototype.createButton = function (id, label, callback, callbackUp) {
420 var button = $('<button type="button" class="Default">');
421 button.attr("id", id);
422 button.text(label);
423 if ((callback != undefined) && (callbackUp == undefined)) {
424 button.bind("click", callback);
425 }
426 else if ((callback != undefined) && (callbackUp != undefined)) {
427 if (isMobile()) {
428 button.bind("vmousedown", callback);
429 button.bind("vmouseup", callbackUp);
430 }
431 else {
432 button.bind("mousedown", callback);
433 button.bind("mouseup", callbackUp);
434 }
435 }
436 return button;
437}
438
439WebIOPi.prototype.createGPIOButton = function (gpio, label) {
440 var button = w().createButton("gpio" + gpio, label);
441 button.bind("click", function(event) {
442 w().toggleValue(gpio);
443 });
444 return button;
445}
446
447WebIOPi.prototype.createFunctionButton = function (gpio) {
448 var button = w().createButton("function" + gpio, " ");
449 button.attr("class", "FunctionBasic");
450 button.bind("click", function(event) {
451 w().toggleFunction(gpio);
452 });
453 return button;
454}
455
456WebIOPi.prototype.createPulseButton = function (id, label, gpio) {
457 var button = webiopi().createButton(id, label);
458 button.bind("click", function(event) {
459 webiopi().pulse(gpio);
460 });
461 return button;
462}
463
464WebIOPi.prototype.createMacroButton = function (id, label, macro, args) {
465 var button = webiopi().createButton(id, label);
466 button.bind("click", function(event) {
467 webiopi().callMacro(macro, args);
468 });
469 return button;
470}
471
472WebIOPi.prototype.createSequenceButton = function (id, label, gpio, period, sequence) {
473 var button = webiopi().createButton(id, label);
474 button.bind("click", function(event) {
475 webiopi().outputSequence(gpio, period, sequence);
476 });
477 return button;
478}
479
480WebIOPi.prototype.createRatioSlider = function(gpio) {
481 var slider = $('<input type="range" min="0.0" max="1.0" step="0.01">');
482 slider.attr("id", "ratio"+gpio);
483 slider.bind("change", function() {
484 w().pulseRatio(gpio, slider.val());
485 });
486 return slider;
487}
488
489WebIOPi.prototype.createAngleSlider = function(gpio) {
490 var slider = $('<input type="range" min="-45" max="45" step="1">');
491 slider.attr("id", "angle"+gpio);
492 slider.bind("change", function() {
493 w().pulseAngle(gpio, slider.val());
494 });
495 return slider;
496}
497
498WebIOPi.prototype.RPiHeader = function () {
499 if (w()._header == undefined) {
500 w()._header = new RPiHeader();
501 }
502 return w()._header;
503}
504
505function RPiHeader() {
506
507}
508
509RPiHeader.prototype.getPinCell = function (pin) {
510 var cell = $('<td align="center">');
511 var button;
512 if (w().PINS[pin].type.value == w().TYPE.GPIO.value) {
513 button = w().createGPIOButton(w().PINS[pin].value, pin);
514 }
515 else {
516 var button = $('<button type="button">');
517 button.val(pin);
518 button.text(pin);
519 button.attr("class", w().PINS[pin].type.style);
520 }
521 cell.append(button);
522 return cell;
523}
524
525RPiHeader.prototype.getDescriptionCell = function (pin, align) {
526 var cell = $('<td>');
527 cell.attr("align", align);
528
529 var div = $('<div>');
530 div.attr("class", "Description");
531 if (w().PINS[pin].type.value != w().TYPE.GPIO.value) {
532 div.append(w().PINS[pin].value);
533 }
534 else {
535 div.attr("id", "description"+w().PINS[pin].value);
536 div.append("GPIO " + w().PINS[pin].value);
537 }
538
539 cell.append(div);
540
541 return cell;
542}
543
544RPiHeader.prototype.getFunctionCell = function (pin) {
545 var cell = $('<td align="center">');
546 if (w().PINS[pin].type.value == w().TYPE.GPIO.value) {
547 var button = w().createFunctionButton(w().PINS[pin].value);
548 cell.append(button);
549 }
550 return cell;
551}
552
553RPiHeader.prototype.createTable = function (containerId) {
554 var table = $("<table>");
555 table.attr("id", "RPiHeader")
556 for (var pin=1; pin<=26; pin++) {
557 var line = $('<tr>');
558 line.append(this.getFunctionCell(pin))
559 line.append(this.getDescriptionCell(pin, "right"))
560 line.append(this.getPinCell(pin));
561
562 pin++;
563 line.append(this.getPinCell(pin));
564 line.append(this.getDescriptionCell(pin, "left"))
565 line.append(this.getFunctionCell(pin))
566
567 table.append(line);
568 }
569
570 if (containerId != undefined) {
571 $("#"+containerId).append(table);
572 }
573
574 return table;
575}
576
577WebIOPi.prototype.Expert = function () {
578 if (w()._expert == undefined) {
579 w()._expert = new Expert();
580 }
581 return w()._expert;
582}
583
584function Expert() {
585
586}
587
588Expert.prototype.createGPIO = function (gpio) {
589 var box = $("<div>");
590 box.append(w().createFunctionButton(gpio));
591 box.append(w().createGPIOButton(gpio, gpio));
592
593 div = $('<div>');
594 div.attr("id", "description"+gpio);
595 div.attr("class", "Description");
596 div.append("GPIO " + gpio);
597 box.append(div);
598
599 return box;
600}
601
602Expert.prototype.createList = function (containerId) {
603 var box = $('<div>');
604
605 for (i = 0; i<w().GPIO.length; i++) {
606 if (w().GPIO[i].mapped == true) {
607 var gpio = w().Expert().createGPIO(i);
608 box.append(gpio);
609 }
610 }
611
612 if (containerId != undefined) {
613 $("#"+containerId).append(box);
614 }
615
616 return box;
617}
618
619WebIOPi.prototype.Serial = function(device) {
620 return new Serial(device);
621}
622
623function Serial(device) {
624 this.device = device;
625 this.url = "/devices/" + device
626}
627
628Serial.prototype.write = function(data) {
629 $.post(this.url, data);
630}
631
632Serial.prototype.read = function(callback) {
633 $.get(this.url, callback);
634}
635
636WebIOPi.prototype.newDevice = function(type, name) {
637 if (type == "ADC") {
638 return new ADC(name);
639 }
640
641 if (type == "DAC") {
642 return new DAC(name);
643 }
644
645 if (type == "PWM") {
646 return new PWM(name);
647 }
648
649 if (type == "GPIOPort") {
650 return new GPIOPort(name);
651 }
652
653 if (type == "Temperature") {
654 return new Temperature(name);
655 }
656
657 if (type == "Pressure") {
658 return new Pressure(name);
659 }
660
661 if (type == "Luminosity") {
662 return new Luminosity(name);
663 }
664
665 if (type == "Distance") {
666 return new Distance(name);
667 }
668
669 if (type == "PiFaceDigital") {
670 return new PiFaceDigital(name);
671 }
672
673 return undefined;
674}
675
676function GPIOPort(name) {
677 this.name = name;
678 this.url = "/devices/" + name;
679 this.onready = null;
680 this.channelCount = 0;
681 this.refreshTime = 1000;
682
683 var port = this;
684 $.get(this.url + "/count", function(data) {
685 port.channelCount = parseInt(data);
686 });
687
688}
689
690GPIOPort.prototype.isReady = function() {
691 return (this.channelCount > 0);
692}
693
694GPIOPort.prototype.toString = function() {
695 if (this.channelCount > 0)
696 return this.name + ": GPIO Port (" + this.channelCount + "-bits)";
697 return this.name + ": GPIO Port";
698}
699
700GPIOPort.prototype.digitalRead = function(channel, callback) {
701 var name = this.name;
702 $.get(this.url + "/" + channel + "/value", function(data) {
703 callback(name, channel, data);
704 });
705}
706
707GPIOPort.prototype.digitalWrite = function(channel, value, callback) {
708 var name = this.name;
709 $.post(this.url + "/" + channel + "/value/" + value, function(data) {
710 callback(name, channel, data);
711 });
712}
713
714GPIOPort.prototype.setFunction = function(channel, func, callback) {
715 var name = this.name;
716 $.post(this.url + "/" + channel + "/function/" + func, function(data) {
717 callback(name, channel, data);
718 });
719}
720
721GPIOPort.prototype.readAll = function(callback) {
722 var name = this.name;
723 $.get(this.url+ "/*", function(data) {
724 callback(name, data);
725 });
726}
727
728GPIOPort.prototype.refreshUI = function() {
729 var port = this;
730 var element = this.element;
731 if ((element != undefined) && (element.header == undefined)) {
732 element.header = $("<h3>" + this + "</h3>");
733 element.append(element.header);
734 }
735
736 if ((element != undefined) && (element.table == undefined) && this.isReady()) {
737 element.header.text(this)
738 element.table = $("<table>");
739 element.append(element.table);
740
741 var line = $("<tr>");
742 for (var i = this.channelCount-1; i>=0; i--) {
743 var cell = $("<td>");
744 cell.text(1<<i);
745 line.append(cell);
746 }
747 element.table.append(line);
748
749 line = $("<tr>");
750 for (var i = this.channelCount-1; i>=0; i--) {
751 var cell = $("<td>");
752 var button = webiopi().createButton(this.name + "_" + i + "_value", i, function() {
753 if ($("#" + port.name + "_" + $(this).attr("channel") + "_value").attr("class") == "LOW") {
754 value = 1;
755 }
756 else {
757 value = 0;
758 }
759 port.digitalWrite($(this).attr("channel"), value, function(name, channel, data) {
760 if (data == "1") {
761 $("#" + name + "_" + channel + "_value").attr("class", "HIGH")
762 }
763 else {
764 $("#" + name + "_" + channel + "_value").attr("class", "LOW")
765 }
766 });
767 });
768 button.attr("channel", i);
769 button.attr("class", "LOW");
770 cell.append(button);
771 line.append(cell);
772 }
773 element.table.append(line);
774
775 line = $("<tr>");
776 for (var i = this.channelCount-1; i>=0; i--) {
777 var cell = $("<td>");
778 var button = webiopi().createButton(port.name + "_" + i + "_func", "IN", function() {
779 var func = $(this).text();
780 console.log(func);
781 if (func == "IN") {
782 func = "OUT";
783 }
784 else {
785 func = "IN";
786 }
787 port.setFunction($(this).attr("channel"), func, function(name, channel, func) {
788 $("#" + port.name + "_" + channel + "_func").text(func);
789 });
790 });
791 button.attr("class", "FunctionBasic");
792 button.attr("channel", i);
793 cell.append(button);
794 line.append(cell);
795 }
796 element.table.append(line);
797 }
798
799 this.readAll(function(name, data) {
800 for (i in data) {
801 $("#" + name + "_" + i + "_value").attr("class", data[i]["value"] == "1" ? "HIGH" : "LOW");
802 $("#" + name + "_" + i + "_func").text(data[i]["function"]);
803 }
804 setTimeout(function(){port.refreshUI()}, port.refreshTime);
805 });
806}
807
808function ADC(name) {
809 this.name = name;
810 this.url = "/devices/" + name + "/analog";
811 this.channelCount = 0;
812 this.maxInteger = 0;
813 this.resolution = 0;
814 this.refreshTime = 1000;
815
816 var adc = this;
817 $.get(this.url + "/count", function(data) {
818 adc.channelCount = parseInt(data);
819 });
820
821 $.get(this.url + "/max", function(data) {
822 adc.maxInteger = parseInt(data);
823 });
824
825 $.get(this.url + "/resolution", function(data) {
826 adc.resolution = parseInt(data);
827 });
828}
829
830ADC.prototype.isReady = function() {
831 return (this.channelCount > 0 && this.maxInteger > 0 && this.resolution > 0 );
832}
833
834ADC.prototype.toString = function() {
835 if (this.channelCount > 0 && this.resolution> 0)
836 return this.name + ": ADC (" + this.resolution + "-bits, " + this.channelCount + "-channels)";
837 return this.name + ": ADC";
838}
839
840ADC.prototype.readInteger = function(channel, callback) {
841 var name = this.name;
842 $.get(this.url + "/" + channel + "/integer", function(data) {
843 callback(name, channel, data);
844 });
845}
846
847ADC.prototype.readFloat = function(channel, callback) {
848 var name = this.name;
849 $.get(this.url + "/" + channel + "/float", function(data) {
850 callback(name, channel, data);
851 });
852}
853
854ADC.prototype.readVolt = function(channel, callback) {
855 var name = this.name;
856 $.get(this.url + "/" + channel + "/volt", function(data) {
857 callback(name, channel, data);
858 });
859}
860
861ADC.prototype.readAllInteger = function(callback) {
862 var name = this.name;
863 $.get(this.url + "/*/integer", function(data) {
864 callback(name, data);
865 });
866}
867
868ADC.prototype.readAllFloat = function(callback) {
869 var name = this.name;
870 $.get(this.url + "/*/float", function(data) {
871 callback(name, data);
872 });
873}
874
875ADC.prototype.readAllVolt = function(callback) {
876 var name = this.name;
877 $.get(this.url + "/*/volt", function(data) {
878 callback(name, data);
879 });
880}
881
882ADC.prototype.refreshUI = function () {
883 var adc = this;
884 var element = this.element;
885
886 if ((element != undefined) && (element.header == undefined)) {
887 element.header = $("<h3>" + this + "</h3>");
888 element.append(element.header);
889 }
890
891 if ((element != undefined) && (element.channels == undefined) && this.isReady()) {
892 element.header.text(this);
893 element.channels = Array();
894 for (i = 0; i<this.channelCount; i++) {
895 var div = $("<div>");
896 div.text("Channel-" + i);
897 element.append(div);
898 element.channels[i] = div;
899
900 }
901 }
902 this.readAllVolt(function(name, data) {
903 for (i in data) {
904 if ((element != undefined) && (element.channels != undefined)) {
905 var div = element.channels[i];
906 div.text("Channel-" + i + ": " + parseFloat(data[i]).toFixed(2) + "V")
907 }
908 }
909 setTimeout(function(){adc.refreshUI()}, adc.refreshTime);
910 });
911}
912
913
914function DAC(name) {
915 this.name = name;
916 this.url = "/devices/" + name + "/analog";
917 this.channelCount = 0;
918 this.maxInteger = 0;
919 this.resolution = 0;
920
921 var dac = this;
922 $.get(this.url + "/count", function(data) {
923 dac.channelCount = parseInt(data);
924 });
925
926 $.get(this.url + "/max", function(data) {
927 dac.maxInteger = parseInt(data);
928 });
929
930 $.get(this.url + "/resolution", function(data) {
931 dac.resolution = parseInt(data);
932 });
933}
934
935DAC.prototype.isReady = function() {
936 return (this.channelCount > 0 && this.maxInteger > 0 && this.resolution > 0 );
937}
938
939DAC.prototype.toString = function() {
940 if (this.channelCount > 0 && this.resolution> 0)
941 return this.name + ": DAC (" + this.resolution + "-bits, " + this.channelCount + "-channels)";
942 return this.name + ": DAC";
943}
944
945DAC.prototype.writeInteger = function(channel, value, callback) {
946 var name = this.name;
947 $.post(this.url + "/" + channel + "/integer/" + value, function(data) {
948 callback(name, channel, data);
949 });
950}
951
952DAC.prototype.writeFloat = function(channel, value, callback) {
953 var name = this.name;
954 $.post(this.url + "/" + channel + "/float/" + value, function(data) {
955 callback(name, channel, data);
956 });
957}
958
959DAC.prototype.readAllInteger = function(callback) {
960 var name = this.name;
961 $.get(this.url + "/*/integer", function(data) {
962 callback(name, data);
963 });
964}
965
966DAC.prototype.readAllFloat = function(callback) {
967 var name = this.name;
968 $.get(this.url + "/*/float", function(data) {
969 callback(name, data);
970 });
971}
972
973DAC.prototype.refreshUI = function() {
974 var dac = this;
975 var element = this.element;
976
977 if ((element != undefined) && (element.header == undefined)) {
978 element.header = $("<h3>" + this + "</h3>");
979 element.append(element.header);
980 }
981
982 if ((element != undefined) && (element.table == undefined) && this.isReady()) {
983 element.header.text(this);
984 element.table = $("<table>");
985 element.append(element.table);
986 for (var i = 0; i<this.channelCount; i++) {
987 var line = $("<tr>");
988 var cell
989 cell = $("<td>");
990 cell.text("Channel-" + i);
991 line.append(cell);
992
993 cell = $("<td>");
994 var slider = $('<input type="range" min="0" max="100" step="1" value="0">')
995 slider.attr("channel", i);
996 slider.attr("id", "slider_" + this.name + "_" + i);
997 cell.append(slider);
998 line.append(cell);
999
1000 cell = $("<td>");
1001 var span = $('<span>');
1002 span.attr("id", "span_" + this.name + "_" + i);
1003 cell.append(span);
1004 line.append(cell);
1005
1006 slider.bind("change", function() {
1007 dac.writeFloat($(this).attr("channel"), $(this).val()/100, function(name, channel, data) {
1008 var val = (data*100).toFixed(0);
1009 var volts = (data*3.3).toFixed(2);
1010 $("#span_" + name + "_" + channel).text(volts + "V - " + val + "%");
1011 $("#slider_" + name + "_" + channel).val(val);
1012 });
1013 });
1014
1015 element.table.append(line);
1016 }
1017 this.readAllFloat(function(name, data) {
1018 for (i in data) {
1019 var val = (data[i]*100).toFixed(0);
1020 var volts = (data[i]*3.3).toFixed(2);
1021 $("#span_" + name + "_" + i).text(volts + "V - " + val + "%");
1022 $("#slider_" + name + "_" + i).val(val);
1023 }
1024 });
1025 }
1026 else {
1027 setTimeout(function(){dac.refreshUI()}, 1000);
1028 }
1029
1030}
1031
1032function PWM(name) {
1033 this.name = name;
1034 this.url = "/devices/" + name + "/pwm";
1035 this.channelCount = 0;
1036 this.maxInteger = 0;
1037 this.resolution = 0;
1038 this.refreshTime = 1000;
1039
1040 var pwm = this;
1041 $.get(this.url + "/count", function(data) {
1042 pwm.channelCount = parseInt(data);
1043 });
1044
1045 $.get(this.url + "/max", function(data) {
1046 pwm.maxInteger = parseInt(data);
1047 });
1048
1049 $.get(this.url + "/resolution", function(data) {
1050 pwm.resolution = parseInt(data);
1051 });
1052}
1053
1054PWM.prototype.isReady = function() {
1055 return (this.channelCount > 0 && this.maxInteger > 0 && this.resolution > 0 );
1056}
1057
1058PWM.prototype.toString = function() {
1059 if (this.channelCount > 0 && this.resolution> 0)
1060 return this.name + ": PWM (" + this.resolution + "-bits, " + this.channelCount + "-channels)";
1061 return this.name + ": PWM";
1062}
1063
1064PWM.prototype.writeInteger = function(channel, value, callback) {
1065 var name = this.name;
1066 $.post(this.url + "/" + channel + "/integer/" + value, function(data) {
1067 callback(name, channel, data);
1068 });
1069}
1070
1071PWM.prototype.writeFloat = function(channel, value, callback) {
1072 var name = this.name;
1073 $.post(this.url + "/" + channel + "/float/" + value, function(data) {
1074 callback(name, channel, data);
1075 });
1076}
1077
1078PWM.prototype.writeAngle = function(channel, value, callback) {
1079 var name = this.name;
1080 $.post(this.url + "/" + channel + "/angle/" + value, function(data) {
1081 callback(name, channel, data);
1082 });
1083}
1084
1085PWM.prototype.readAllInteger = function(callback) {
1086 var name = this.name;
1087 $.get(this.url + "/*/integer", function(data) {
1088 callback(name, data);
1089 });
1090}
1091
1092PWM.prototype.readAllFloat = function(callback) {
1093 var name = this.name;
1094 $.get(this.url + "/*/float", function(data) {
1095 callback(name, data);
1096 });
1097}
1098
1099PWM.prototype.readAll = function(callback) {
1100 var name = this.name;
1101 $.get(this.url + "/*", function(data) {
1102 callback(name, data);
1103 });
1104}
1105
1106PWM.prototype.refreshUI = function() {
1107 var pwm = this;
1108 var element = this.element;
1109 if ((element != undefined) && (element.header == undefined)) {
1110 element.header = $("<h3>" + this + "</h3>");
1111 element.append(element.header);
1112 }
1113
1114 if ((element != undefined) && (element.table == undefined) && this.isReady()) {
1115 element.header.text(this);
1116 element.table = $("<table>");
1117 element.append(element.table);
1118
1119 for (var i = 0; i<this.channelCount; i++) {
1120 var line = $("<tr>");
1121 var cell
1122 cell = $("<td>");
1123 cell.text("Channel-" + i);
1124 line.append(cell);
1125
1126 cell = $("<td>");
1127 var checkbox = $('<input type="checkbox">');
1128 checkbox.attr("id", "checkbox_" + this.name + "_" + i);
1129 checkbox.attr("channel", i);
1130
1131 var cblabel = $('<label>');
1132 cblabel.append(checkbox);
1133 cblabel.append("Servo");
1134 cell.append(cblabel);
1135 line.append(cell);
1136
1137 cell = $("<td>");
1138 var slider = $('<input type="range" min="0" max="100" step="1" value="0">')
1139 slider.attr("channel", i);
1140 slider.attr("id", "slider_" + this.name + "_" + i);
1141 cell.append(slider);
1142 line.append(cell);
1143
1144 cell = $("<td>");
1145 var span = $('<span>');
1146 span.attr("id", "span_" + this.name + "_" + i);
1147 cell.append(span);
1148 line.append(cell);
1149
1150 checkbox.bind("change", function() {
1151 var slider = $("#slider_" + pwm.name + "_" + $(this).attr("channel"))
1152 slider.attr("servo", $(this).is(":checked"));
1153 });
1154
1155 slider.bind("change", function() {
1156 if ($(this).attr("servo") == "true") {
1157 pwm.writeAngle($(this).attr("channel"), $(this).val(), function(name, channel, data) {
1158 var val = data;
1159 $("#span_" + name + "_" + channel).text(val + "°");
1160 $("#slider_" + name + "_" + channel).val(val);
1161 });
1162 }
1163 else {
1164 pwm.writeFloat($(this).attr("channel"), $(this).val()/100, function(name, channel, data) {
1165 var val = (data*100).toFixed(0);
1166 $("#span_" + name + "_" + channel).text(val + "%");
1167 $("#slider_" + name + "_" + channel).val(val);
1168 });
1169 }
1170 });
1171
1172 element.table.append(line);
1173 }
1174 }
1175
1176 this.readAll(function(name, data) {
1177 for (i in data) {
1178 var slider = $("#slider_" + name + "_" + i);
1179 var span = $("#span_" + name + "_" + i);
1180 var val = 0;
1181
1182 if (slider.attr("servo") == "true") {
1183 slider.attr("min", -45);
1184 slider.attr("max", 45);
1185 val = data[i]["angle"];
1186 span.text(val + "°");
1187 }
1188 else {
1189 slider.attr("min", 0);
1190 slider.attr("max", 100);
1191 val = (data[i]["float"]*100).toFixed(0);
1192 span.text(val + "%");
1193 }
1194 slider.val(val);
1195
1196 }
1197 setTimeout(function(){pwm.refreshUI()}, pwm.refreshTime);
1198 });
1199}
1200
1201function Temperature(name) {
1202 this.name = name;
1203 this.url = "/devices/" + name + "/sensor";
1204 this.refreshTime = 5000;
1205}
1206
1207Temperature.prototype.toString = function() {
1208 return this.name + ": Temperature";
1209}
1210
1211Temperature.prototype.getKelvin = function(callback) {
1212 $.get(this.url + "/temperature/k", function(data) {
1213 callback(this.name, data);
1214 });
1215}
1216
1217Temperature.prototype.getCelsius = function(callback) {
1218 $.get(this.url + "/temperature/c", function(data) {
1219 callback(this.name, data);
1220 });
1221}
1222
1223Temperature.prototype.getFahrenheit = function(callback) {
1224 $.get(this.url + "/temperature/f", function(data) {
1225 callback(this.name, data);
1226 });
1227}
1228
1229Temperature.prototype.refreshUI = function() {
1230 var temp = this;
1231 var element = this.element;
1232 if ((element != undefined) && (element.header == undefined)) {
1233 element.header = $("<h3>" + this + "</h3>");
1234 element.append(element.header);
1235 }
1236
1237 this.getCelsius(function(name, data){
1238 if (element != undefined) {
1239 element.header.text(temp + ": " + data + "°C");
1240 }
1241 setTimeout(function(){temp.refreshUI()}, temp.refreshTime);
1242 });
1243}
1244
1245function Pressure(name) {
1246 this.name = name;
1247 this.url = "/devices/" + name + "/sensor";
1248 this.refreshTime = 5000;
1249}
1250
1251Pressure.prototype.toString = function() {
1252 return this.name + ": Pressure";
1253}
1254
1255Pressure.prototype.getPascal = function(callback) {
1256 $.get(this.url + "/pressure/pa", function(data) {
1257 callback(this.name, data);
1258 });
1259}
1260
1261Pressure.prototype.getHectoPascal = function(callback) {
1262 $.get(this.url + "/pressure/hpa", function(data) {
1263 callback(this.name, data);
1264 });
1265}
1266
1267Pressure.prototype.refreshUI = function() {
1268 var pressure = this;
1269 var element = this.element;
1270 if ((element != undefined) && (element.header == undefined)) {
1271 element.header = $("<h3>" + this + "</h3>");
1272 element.append(element.header);
1273 }
1274
1275 pressure.getHectoPascal(function(name, data){
1276 if (element != undefined) {
1277 element.header.text(pressure + ": " + data + "hPa");
1278 }
1279 setTimeout(function(){pressure.refreshUI()}, pressure.refreshTime);
1280 });
1281}
1282
1283
1284function Luminosity(name) {
1285 this.name = name;
1286 this.url = "/devices/" + name + "/sensor";
1287 this.refreshTime = 1000;
1288}
1289
1290Luminosity.prototype.toString = function() {
1291 return this.name + ": Luminosity";
1292}
1293
1294Luminosity.prototype.getLux = function(callback) {
1295 $.get(this.url + "/luminosity/lx", function(data) {
1296 callback(this.name, data);
1297 });
1298}
1299
1300Luminosity.prototype.refreshUI = function() {
1301 var lum = this;
1302 var element = this.element;
1303
1304 if ((element != undefined) && (element.header == undefined)) {
1305 element.header = $("<h3>" + this + "</h3>");
1306 element.append(element.header);
1307 }
1308
1309 this.getLux(function(name, data){
1310 if (element != undefined) {
1311 element.header.text(lum + ": " + data + "lx");
1312 }
1313 setTimeout(function(){lum.refreshUI()}, lum.refreshTime);
1314 });
1315}
1316
1317function Distance(name) {
1318 this.name = name;
1319 this.url = "/devices/" + name + "/sensor";
1320 this.refreshTime = 1000;
1321}
1322
1323Distance.prototype.toString = function() {
1324 return this.name + ": Distance";
1325}
1326
1327Distance.prototype.getMillimeter = function(callback) {
1328 $.get(this.url + "/distance/mm", function(data) {
1329 callback(this.name, data);
1330 });
1331}
1332
1333Distance.prototype.refreshUI = function() {
1334 var dist = this;
1335 var element = this.element;
1336
1337 if ((element != undefined) && (element.header == undefined)) {
1338 element.header = $("<h3>" + this + "</h3>");
1339 element.append(element.header);
1340 }
1341
1342 this.getMillimeter(function(name, data){
1343 if (element != undefined) {
1344 element.header.text(dist + ": " + data + "mm");
1345 }
1346 setTimeout(function(){dist.refreshUI()}, dist.refreshTime);
1347 });
1348}
1349
1350function PiFaceDigital(name) {
1351 this.name = name;
1352 this.url = "/devices/" + name + "/digital";
1353 this.onready = null;
1354 this.refreshTime = 1000;
1355}
1356
1357PiFaceDigital.prototype.toString = function() {
1358 return "PiFaceDigital";
1359}
1360
1361PiFaceDigital.prototype.input = function(channel, callback) {
1362 var name = this.name;
1363 $.get(this.url + "/input/" + channel, function(data) {
1364 callback(name, channel, data);
1365 });
1366}
1367
1368PiFaceDigital.prototype.output = function(channel, value, callback) {
1369 var name = this.name;
1370 $.post(this.url + "/output/" + channel + "/" + value, function(data) {
1371 callback(name, channel, data);
1372 });
1373}
1374
1375PiFaceDigital.prototype.readAll = function(callback) {
1376 var name = this.name;
1377 $.get(this.url+ "/*", function(data) {
1378 callback(name, data);
1379 });
1380}
1381
1382PiFaceDigital.prototype.refreshUI = function() {
1383 var port = this;
1384 var element = this.element;
1385 if ((element != undefined) && (element.header == undefined)) {
1386 element.header = $("<h3>" + this + "</h3>");
1387 element.append(element.header);
1388 }
1389
1390 if ((element != undefined) && (element.table == undefined)) {
1391 element.header.text(this)
1392 element.table = $("<table>");
1393 element.append(element.table);
1394
1395 var line = $("<tr>");
1396 line.append($("<td><b>Outputs</b></td>"))
1397 for (var i = 7; i>=0; i--) {
1398 var cell = $("<td>");
1399 var button = webiopi().createButton(this.name + "_output_" + i, i, function() {
1400 if ($("#" + port.name + "_output_" + $(this).attr("channel")).attr("class") == "LOW") {
1401 value = 1;
1402 }
1403 else {
1404 value = 0;
1405 }
1406 port.output($(this).attr("channel"), value, function(name, channel, data) {
1407 var button = $("#" + name + "_output_" + channel);
1408 if (data == "1") {
1409 button.attr("class", "HIGH")
1410 }
1411 else {
1412 button.attr("class", "LOW")
1413 }
1414 });
1415 });
1416 button.attr("channel", i);
1417 button.attr("class", "LOW");
1418 cell.append(button);
1419 line.append(cell);
1420 }
1421 element.table.append(line);
1422
1423 line = $("<tr>");
1424 line.append($("<td><b>Inputs</b></td>"))
1425 for (var i = 7; i>=0; i--) {
1426 var cell = $("<td>");
1427 var button = webiopi().createButton(this.name + "_input_" + i, i, function() {
1428 });
1429 button.attr("channel", i);
1430 button.attr("class", "LOW");
1431 cell.append(button);
1432 line.append(cell);
1433 }
1434 element.table.append(line);
1435
1436 }
1437
1438 this.readAll(function(name, data) {
1439 for (i in data["input"]) {
1440 $("#" + name + "_input_" + i).attr("class", data["input"][i] == "1" ? "HIGH" : "LOW");
1441 }
1442 for (i in data["output"]) {
1443 $("#" + name + "_output_" + i).attr("class", data["output"][i] == "1" ? "HIGH" : "LOW");
1444 }
1445 setTimeout(function(){port.refreshUI()}, port.refreshTime);
1446 });
1447}
1448