diff --git a/config.js b/config.js index 2b7cc77..3a6c6fc 100644 --- a/config.js +++ b/config.js @@ -5,7 +5,8 @@ System.config({ "babelOptions": { "optional": [ "runtime" - ] + ], + "stage": 0 }, "paths": { "github:*": "jspm_packages/github/*", diff --git a/example/app.js b/example/app.js index a784ce4..0177d52 100644 --- a/example/app.js +++ b/example/app.js @@ -1,21 +1,88 @@ import Doodle3DManager from 'src/doodle3dmanager.js'; -var list = document.getElementById('list'); +let list = document.getElementById('list'); -var doodle3DManager = new Doodle3DManager(); +let doodle3DManager = new Doodle3DManager(); -doodle3DManager.addEventListener('boxappeared', (event) => { - var box = event.box; +doodle3DManager.addEventListener('boxappeared', async (event) => { + let box = event.box; - var node = document.createElement('li'); - node.innerHTML = box.boxData.wifiboxid; - list.appendChild(node); + var row = document.createElement('tr'); + row.style.color = 'black'; + + var id = document.createElement('td'); + var state = document.createElement('td'); + var localIP = document.createElement('td'); + var bed = document.createElement('td'); + var bedTarget = document.createElement('td'); + var bufferedLines = document.createElement('td'); + var currentLine = document.createElement('td'); + var hasControl = document.createElement('td'); + var hotend = document.createElement('td'); + var hotendTarget = document.createElement('td'); + var totalLines = document.createElement('td'); + + row.appendChild(id); + row.appendChild(localIP); + row.appendChild(state); + row.appendChild(currentLine); + row.appendChild(bufferedLines); + row.appendChild(totalLines); + row.appendChild(hotend); + row.appendChild(hotendTarget); + row.appendChild(bed); + row.appendChild(bedTarget); + row.appendChild(hasControl); + + id.innerHTML = box.boxData.wifiboxid; + localIP.innerHTML = box.boxData.localip; + + document.getElementById('table').appendChild(row); + + function update (event) { + let data = event.state; + state.innerHTML = data.state; + + if (data.state !== 'disconnected' && data.state !== 'connecting' && data.state !== 'unknown') { + bed.innerHTML = data.bed; + bedTarget.innerHTML = data.bed_target; + bufferedLines.innerHTML = data.buffered_lines; + currentLine.innerHTML = data.current_line; + hasControl.innerHTML = data.has_control; + hotend.innerHTML = data.hotend; + hotendTarget.innerHTML = data.hotend_target; + state.innerHTML = data.state; + totalLines.innerHTML = data.total_lines; + } + else { + bed.innerHTML = ''; + bedTarget.innerHTML = ''; + bufferedLines.innerHTML = ''; + currentLine.innerHTML = ''; + hasControl.innerHTML = ''; + hotend.innerHTML = ''; + hotendTarget.innerHTML = ''; + totalLines.innerHTML = ''; + } + }; + + box.setAutoUpdate(true, 1000); + + function update (event) { + console.log(event); + } + + box.addEventListener('update', update); + + box.addEventListener('disconnect', (event) => { + box.removeEventListener('update', update); + }); }); doodle3DManager.addEventListener('boxdisappeared', (event) => { - var box = event.box; + let box = event.box; - for (var node of list.children) { + for (let node of list.children) { if (node.innerHTML === box.boxData.wifiboxid) { list.removeChild(node); break; @@ -23,4 +90,4 @@ doodle3DManager.addEventListener('boxdisappeared', (event) => { } }); -doodle3DManager.setAutoUpdate(true); +doodle3DManager.setAutoUpdate(true, 1000); diff --git a/example/index.html b/example/index.html index 90d6884..c89c8a2 100644 --- a/example/index.html +++ b/example/index.html @@ -1,22 +1,45 @@ - + - Doodle3D Box +Doodle3D Box - - + - + + - - + -

Doodle3D WiFi-Boxes

+ - + + + + + + + + + + + + + + + + +
IDLocal IPStateCurrent LineBuffered LinesTotal LinesHotendHotend TargetBedBed TargetHas Control
- + + \ No newline at end of file diff --git a/src/configapi.js b/src/configapi.js index 6090b73..a7b5071 100644 --- a/src/configapi.js +++ b/src/configapi.js @@ -5,17 +5,17 @@ export default class { this.api = api; } - get (keys) { - return rest.get(this.api + 'config/?' + keys.join('=&') + '='); + get (...keys) { + return rest.get(`${this.api}config/?${keys.join('=&')}=`); } getAll () { - return rest.get(this.api + 'config/all'); + return rest.get(`${this.api}config/all`); } set (data) { var scope = this; - return rest.post(this.api + 'config', data); + return rest.post(`${this.api}config`, data); } } diff --git a/src/doodle3dapi.js b/src/doodle3dapi.js index 8466aad..343e24f 100644 --- a/src/doodle3dapi.js +++ b/src/doodle3dapi.js @@ -7,6 +7,7 @@ import PrinterAPI from './printerapi.js'; import SketchAPI from './sketchapi.js'; import SystemAPI from './systemapi.js'; import UpdateAPI from './updateapi.js'; +import {sleep} from './utils.js'; export default class extends EventDispatcher { constructor (boxData) { @@ -26,12 +27,14 @@ export default class extends EventDispatcher { this.alive = false; this.autoUpdate = false; - this.state = {}; + + this.maxBatchSize = 10*1024; + this.maxBufferSize = 1024*1024; + this.fullBufferTimeout = 10000; } setAutoUpdate (autoUpdate = true, updateInterval = 1000) { - this.updateInterval = updateInterval; if (this.autoUpdate === autoUpdate) { @@ -41,67 +44,115 @@ export default class extends EventDispatcher { this.autoUpdate = autoUpdate; if (autoUpdate) { - this._initLoop(); + this._update(); } return this; } - _initLoop () { - - var request = this.network.alive(); - - request.then(() => { - - this.alive = true; - - this.dispatchEvent({ - type: 'connect' - }); - - this._updateStateLoop(); - - }); - - request.catch((error) => { - - if (this.alive) { - - this.alive = false; + checkAlive () { + return new Promise(async (resolve, reject) => { + let alive; + try { + await this.network.alive(); + alive = true; + } + catch (error) { + alive = false; + } + if (alive !== this.alive) { this.dispatchEvent({ - type: 'disconnect' + type: alive ? 'connect' : 'disconnect' }); } - - setTimeout(() => { - this._initLoop(); - }, this.updateInterval); + + this.alive = alive; + resolve(alive); }); } - _updateStateLoop () { - - this.info.status().then((state) => { - this.state = state; - - this.dispatchEvent({ - type: 'update', - state - }); - - if (this.autoUpdate) { - setTimeout(() => { - this._updateStateLoop(); - }, this.updateInterval); + sendGCode (gcode) { + return new Promise(async (resolve, reject) => { + let printerState = await this.printer.state(); + if (printerState.state !== 'idle') { + reject(`Cannot print, print state is ${printerState.state}`); + return; } - }).catch((error) => { - if (this.autoUpdate) { - setTimeout(() => { - this._initLoop(); - }, this.updateInterval); + if (!gcode.endsWith('\n')) { + gcode += '\n'; } + + this._currentBatch = 0; + + let lastIndex = 0; + let start = true; + while (lastIndex !== gcode.length) { + let index = gcode.lastIndexOf('\n', lastIndex + this.maxBatchSize); + let batch = gcode.substring(lastIndex, index); + + let progress = await this.printer.progress(); + + if (progress['buffered_lines'] + batch.length < this.maxBufferSize) { + lastIndex = index + 1; //skip next \n + + await this._sendBatch(batch, start); + + start = false; + } + else { + await sleep(this.fullBufferTimeout); + } + } + + resolve(); }); } -} \ No newline at end of file + + async _update () { + let alive = await this.checkAlive(); + if (alive) { + while (this.autoUpdate) { + try { + this.state = await this.info.status(); + + this.dispatchEvent({ + type: 'update', + state: this.state + }); + + await sleep(this.updateInterval); + } + catch (error) { + this._update(); + break; + } + } + } + else { + await sleep(this.updateInterval); + + this._update(); + } + } + + _sendBatch (gcode, index) { + return new Promise (async (resolve, reject) => { + try { + let start = index === 0; + let first = start; + let printRequest = await this.printer.print(gcode, first, start); + + console.log(`batch sent: ${index}`, printRequest); + } + catch (error) { + await sleep(1000); + + await this._sendBatch(gcode, index); + } + + resolve(); + }); + } +} diff --git a/src/doodle3dmanager.js b/src/doodle3dmanager.js index 51fc774..5d8fe1b 100644 --- a/src/doodle3dmanager.js +++ b/src/doodle3dmanager.js @@ -1,43 +1,97 @@ import * as rest from './restapi.js'; import Doodle3DAPI from './doodle3dapi.js'; import EventDispatcher from 'casperlamboo/EventDispatcher'; +import {sleep} from './utils.js'; export default class extends EventDispatcher { constructor () { super(); + this.api = 'http://connect.doodle3d.com/api/'; + this.boxes = []; + this.nonServerBoxes = [{ wifiboxid: 'Wired Printer', localip: '192.168.5.1' - }, { + }/*, { wifiboxid: 'Node JS Server', - localip: '127.0.0.1:2000' - }]; + localip: '127.0.0.1:3000' + }*/]; this.checkNonServerBoxes = true; - this.api = 'http://connect.doodle3d.com/api/'; + + this.autoUpdate = false; } - setAutoUpdate (autoUpdate = true, rate = 5000) { + setAutoUpdate (autoUpdate = true, updateInterval = 1000) { + this.updateInterval = updateInterval; + + if (this.autoUpdate === autoUpdate) { + return; + } + + this.autoUpdate = autoUpdate; + if (autoUpdate) { this._update(); - - if (this.interval !== undefined) { - clearInterval(this.interval); - } - - this.interval = setInterval(() => { - this._update(); - }, rate); - } - else if (this.interval !== undefined) { - clearInterval(this.interval); - delete this.interval; } return this; } + async _update () { + while (this.autoUpdate) { + await this._checkAlive(); + await this._checkNew(); + + await sleep(this.updateInterval); + } + } + + _checkAlive () { + return new Promise(async (resolve, reject) => { + for (let box of this.boxes) { + let alive = await box.checkAlive(); + + if (!alive) { + this._removeBox(box); + } + } + resolve(); + }); + } + + _checkNew () { + return new Promise(async (resolve, reject) => { + try { + let boxes = await rest.get(`${this.api}list.php`); + + if (this.checkNonServerBoxes) { + boxes = boxes.concat(this.nonServerBoxes); + } + + let knownIPs = this.boxes.map((box) => box.boxData.localip); + + for (let boxData of boxes) { + if (knownIPs.indexOf(boxData.localip) === -1) { + let box = new Doodle3DAPI(boxData); + + let alive = await box.checkAlive(); + + if (alive) { + this._addBox(box); + } + } + } + + resolve(); + } + catch (error) { + console.warn('fail connecting to Doodle3D server'); + } + }); + } + _addBox (box) { this.boxes.push(box); @@ -48,7 +102,7 @@ export default class extends EventDispatcher { } _removeBox (box) { - var index = this.boxes.indexOf(box); + let index = this.boxes.indexOf(box); if (index !== -1) { this.boxes.splice(index, 1); this.dispatchEvent({ @@ -57,52 +111,4 @@ export default class extends EventDispatcher { }); } } - - _update () { - this._checkAlive(); - this._checkNew(); - } - - _checkAlive () { - for (var box of this.boxes) { - ((box) => { - var request = box.network.alive(); - request.catch(() => { - this._removeBox(box); - }); - })(box); - } - } - - _checkNew () { - - var request = rest.get(this.api + 'list.php'); - request.then((boxes) => { - - if (this.checkNonServerBoxes) { - boxes = boxes.concat(this.nonServerBoxes); - } - - var knownIPs = this.boxes.map((box) => box.boxData.localip); - - for (var boxData of boxes) { - if (knownIPs.indexOf(boxData.localip) === -1) { - var box = new Doodle3DAPI(boxData); - ((box) => { - var request = box.network.alive(); - request.then((data, msg) => { - this._addBox(box); - }); - request.catch(() => { - console.log(`failed to connect with ${box.boxData.wifiboxid}`); - }); - - })(box); - } - } - }); - request.catch(() => { - console.warn('fail connecting to Doodle3D server'); - }); - } -} \ No newline at end of file +} diff --git a/src/infoapi.js b/src/infoapi.js index 99b17d9..8193845 100644 --- a/src/infoapi.js +++ b/src/infoapi.js @@ -6,18 +6,18 @@ export default class { } get () { - return rest.get(this.api + 'info'); + return rest.get(`${this.api}info`); } status () { - return rest.get(this.api + 'info/status'); + return rest.get(`${this.api}info/status`); } downloadLogFiles () { - window.location = this.api + 'info/logfiles'; + window.location = `${this.api}info/logfiles`; } acces () { - return rest.get(this.api + 'info/access'); + return rest.get(`${this.api}info/access`); } -} \ No newline at end of file +} diff --git a/src/networkapi.js b/src/networkapi.js index d75b368..1f3bd59 100644 --- a/src/networkapi.js +++ b/src/networkapi.js @@ -6,47 +6,50 @@ export default class { } scan () { - return rest.get(this.api + 'network/scan'); + return rest.get(`${this.api}network/scan`); } known () { - return rest.get(this.api + 'network/known'); + return rest.get(`${this.api}network/known`); } status () { - return rest.get(this.api + 'network/status'); + return rest.get(`${this.api}network/status`); } - assosiate (ssid, phrase = null, recreate = false) { - var data = {ssid, recreate}; - if (phrase) data.phrase = phrase; + assosiate (ssid, phrase, recreate = false) { + var data = { + ssid, + recreate, + phrase + }; - return rest.post(this.api + 'network/associate', data); + return rest.post(`${this.api}network/associate`, data); } disassosiate () { //not tested - return rest.post(this.api + 'network/disassociate', {}); + return rest.post(`${this.api}network/disassociate`, {}); } openAccesPoint () { //not tested - return rest.post(this.api + 'network/openap', {}); + return rest.post(`${this.api}network/openap`, {}); } remove (ssid) { - return rest.post(this.api + 'network/remove', { + return rest.post(`${this.api}network/remove`, { 'ssid': ssid }); } signin () { - return rest.get(this.api + 'network/signin'); + return rest.get(`${this.api}network/signin`); } alive () { - return rest.get(this.api + 'network/alive'); + return rest.get(`${this.api}network/alive`); } -} \ No newline at end of file +} diff --git a/src/printerapi.js b/src/printerapi.js index cad58e1..ef649a8 100644 --- a/src/printerapi.js +++ b/src/printerapi.js @@ -3,106 +3,43 @@ import * as rest from './restapi.js'; export default class { constructor (api) { this.api = api; - - this._printBatches = []; - this._currentBatch = 0; - - this.maxBatchSize = 10*1024; - this.maxBufferedLines = 1024*1024; - this.fullBufferTimeout = 10000; } temperature () { - return rest.get(this.api + 'printer/temperature'); + return rest.get(`${this.api}printer/temperature`); } progress () { - return rest.get(this.api + 'printer/progress'); + return rest.get(`${this.api}printer/progress`); } state () { - return rest.get(this.api + 'printer/state'); + return rest.get(`${this.api}printer/state`); } listAll () { - return rest.get(this.api + 'printer/listall'); + return rest.get(`${this.api}printer/listall`); } heatup () { - return rest.post(this.api + 'printer/heatup', {}); + return rest.post(`${this.api}printer/heatup`, {}); } - sendGCode (gcode) { - if (!gcode.endsWith('\n')) { - gcode += '\n'; - } + print (gcode = '', first = false, start = false, last) { + let data = { + gcode, + first, + start, + last + }; - this._currentBatch = 0; - - var lastIndex = 0; - while (lastIndex !== gcode.length) { - var index = gcode.lastIndexOf('\n', lastIndex + this.maxBatchSize); - var batch = gcode.substring(lastIndex, index); - lastIndex = index + 1; //skip next return - - this._printBatches.push(batch); - } - - this._sendBatch(); - } - - _sendBatch () { - var gcode = this._printBatches.shift(); - var start = (this._currentBatch === 0) ? true : false; - var first = (this._currentBatch === 0) ? true : false; - var last = (this._printBatches.length === 0) ? true : false; //only for the node js server - - var printRequest = this.print(gcode, start, first, last); - printRequest.then((data) => { - - console.log('batch sent: ' + this._currentBatch, data); - - var progressRequest = this.progress() - progressRequest.then((progress) => { - - if (this._printBatches.length > 0) { - if (progress['buffered_lines'] + this.maxBatchSize < this.maxBufferedLines) { - this._currentBatch ++; - this._sendBatch(); - } - else { - setTimeout(() => { - this._sendBatch(); - }, this.fullBufferTimeout); - } - - } - else { - console.log('Finish sending gcode to printer'); - } - - }); - }); - printRequest.catch((error) => { - this._printBatches.unshift(gcode); - - setTimeout(() => { - this._sendBatch(); - }, 1000); - }); - } - - print (gcode = '', first = false, start = false, last = false) { - var data = {gcode, first, start} - if (last) data.last = last; - - return rest.post(this.api + 'printer/print', data); + return rest.post(`${this.api}printer/print`, data); } stop (gcode = '') { this._currentBatch = 0; this._printBatches = []; - return rest.post(this.api + 'printer/stop', {gcode}); + return rest.post(`${this.api}printer/stop`, {gcode}); } -} \ No newline at end of file +} diff --git a/src/restapi.js b/src/restapi.js index 0f00c52..32371f7 100644 --- a/src/restapi.js +++ b/src/restapi.js @@ -1,15 +1,12 @@ import $ from 'jquery'; export function get (url) { - return new Promise((resolve, reject) => { - $.ajax({ url: url, dataType: 'json', timeout: 5000, success: (response) => { - if (response.status === 'success') { resolve(response.data, response.msg); } @@ -17,15 +14,12 @@ export function get (url) { reject(response.msg); } } - }).fail(reject); - + }).fail(reject); }); } export function post (url, data) { - return new Promise((resolve, reject) => { - $.ajax({ url: url, type: 'POST', @@ -33,14 +27,12 @@ export function post (url, data) { dataType: 'json', timeout: 10000, success: (response) => { - if (response.status === 'success') { resolve(response.data); } else { reject(response.msg); } - } }).fail(reject); }); diff --git a/src/sketchapi.js b/src/sketchapi.js index c8b8e94..c22d46c 100644 --- a/src/sketchapi.js +++ b/src/sketchapi.js @@ -6,20 +6,20 @@ export default class { } getSketch (id) { - return rest.get(this.api + 'sketch/?id=' + id); + return rest.get(`${this.api}sketch/?id=${id}`); } set (data = '') { - return rest.post(this.api + 'sketch', { + return rest.post(`${this.api}sketch`, { data }); } status () { - return rest.get(this.api + 'sketch/status'); + return rest.get(`${this.api}sketch/status`); } clear () { - return rest.post(this.api + 'sketch/clear'); + return rest.post(`${this.api}sketch/clear`); } -} \ No newline at end of file +} diff --git a/src/systemapi.js b/src/systemapi.js index 15c4eda..b2b4e37 100644 --- a/src/systemapi.js +++ b/src/systemapi.js @@ -6,6 +6,6 @@ export default class { } versions () { - return rest.get(this.api + 'system/fwversions'); + return rest.get(`${this.api}system/fwversions`); } -} \ No newline at end of file +} diff --git a/src/updateapi.js b/src/updateapi.js index 9dbdd93..88f980c 100644 --- a/src/updateapi.js +++ b/src/updateapi.js @@ -6,24 +6,24 @@ export default class { } status () { - return rest.get(this.api + 'update/status'); + return rest.get(`${this.api}update/status`); } download () { //not tested - return rest.post(this.api + 'update/download', {}); + return rest.post(`${this.api}update/download`, {}); } install () { //not tested - return rest.post(this.api + 'update/install', {}); + return rest.post(`${this.api}update/install`, {}); } clear () { //not tested - return rest.post(this.api + 'update/clear', {}); + return rest.post(`${this.api}update/clear`, {}); } -} \ No newline at end of file +} diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..1489a75 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,7 @@ +export function sleep (time) { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, time); + }); +}