update status
This commit is contained in:
parent
2c89f32c8d
commit
1941ab0c52
@ -1,31 +1,33 @@
|
|||||||
const EventEmitter = require('events')
|
const EventEmitter = require('events') // eslint-disable-line
|
||||||
const escpos = require('escpos')
|
const escpos = require('escpos')
|
||||||
const config = require('./config.json')
|
// const config = require('./config.json')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const iconv = require('iconv-lite')
|
const iconv = require('iconv-lite')
|
||||||
|
|
||||||
class PrinterDevice {
|
class PrinterDevice {
|
||||||
constructor() {
|
constructor () {
|
||||||
|
this._serial = ''
|
||||||
|
this._feed = 8
|
||||||
this._isOpen = false
|
this._isOpen = false
|
||||||
this._device = null
|
this._device = null
|
||||||
this._printer = null
|
this._printer = null
|
||||||
this._type = null // type = serial or console
|
this._type = null // type = serial or console
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeStr(str){
|
encodeStr (str) {
|
||||||
if(!str || typeof str != 'string') return false
|
if (!str || typeof str !== 'string') return false
|
||||||
return iconv.encode(str, 'big5')
|
return iconv.encode(str, 'big5')
|
||||||
}
|
}
|
||||||
|
|
||||||
async connect() {
|
async connect () {
|
||||||
let chkSerial = await new Promise((resolve, reject) => {
|
let chkSerial = await new Promise((resolve, reject) => {
|
||||||
fs.access(config.printer.serial, err => {
|
fs.access(this._serial, err => {
|
||||||
if (err) return resolve(false)
|
if (err) return resolve(false)
|
||||||
return resolve(true)
|
return resolve(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
if (chkSerial) {
|
if (chkSerial) {
|
||||||
this._device = new escpos.Serial(config.printer.serial)
|
this._device = new escpos.Serial(this._serial)
|
||||||
this._type = 'serial'
|
this._type = 'serial'
|
||||||
} else {
|
} else {
|
||||||
this._device = new escpos.Console()
|
this._device = new escpos.Console()
|
||||||
@ -35,8 +37,8 @@ class PrinterDevice {
|
|||||||
this.openSerial()
|
this.openSerial()
|
||||||
}
|
}
|
||||||
|
|
||||||
async openSerial() {
|
async openSerial () {
|
||||||
if (!this._device || this._type != 'serial') return
|
if (!this._device || this._type !== 'serial') return
|
||||||
this._isOpen = await new Promise((resolve, reject) => {
|
this._isOpen = await new Promise((resolve, reject) => {
|
||||||
this._device.open(err => {
|
this._device.open(err => {
|
||||||
if (err) return resolve(false)
|
if (err) return resolve(false)
|
||||||
@ -45,7 +47,7 @@ class PrinterDevice {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async printerString(str) {
|
async printerString (str) {
|
||||||
if (!this._isOpen || !this._printer) return false
|
if (!this._isOpen || !this._printer) return false
|
||||||
|
|
||||||
this._printer.font('a')
|
this._printer.font('a')
|
||||||
@ -66,8 +68,8 @@ class PrinterDevice {
|
|||||||
case 's':
|
case 's':
|
||||||
let size = tmp.substring(2)
|
let size = tmp.substring(2)
|
||||||
let sarr = size.trim().split(',')
|
let sarr = size.trim().split(',')
|
||||||
if (sarr.length != 2) break
|
if (sarr.length !== 2) break
|
||||||
if(!isFinite(sarr[0]) || !isFinite(sarr[1])) break
|
if (!isFinite(sarr[0]) || !isFinite(sarr[1])) break
|
||||||
sarr = sarr.map(t => Math.floor(t))
|
sarr = sarr.map(t => Math.floor(t))
|
||||||
this._printer.size(sarr[0], sarr[1])
|
this._printer.size(sarr[0], sarr[1])
|
||||||
break
|
break
|
||||||
@ -77,26 +79,50 @@ class PrinterDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._printer.cut(true, config.printer.cutFeed || 4)
|
this._printer.cut(true, this._feed || 4)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async close() {
|
async printTestPage () {
|
||||||
|
await this.connect()
|
||||||
|
if (!this._isOpen) return false
|
||||||
|
this._printer.align('ct')
|
||||||
|
this._printer.size(1, 1)
|
||||||
|
this._printer.text('Print Test Page')
|
||||||
|
this._printer.align('lt')
|
||||||
|
this._printer.size(1, 1)
|
||||||
|
this._printer.text('Test Page Content')
|
||||||
|
await this.close()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
async close () {
|
||||||
if (!this._device) return
|
if (!this._device) return
|
||||||
if (this._type == 'serial') {
|
if (this._type === 'serial') {
|
||||||
let self = this
|
let self = this
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
self._printer.close(() => {
|
self._printer.close(() => {
|
||||||
|
self._printer = null
|
||||||
|
self._isOpen = false
|
||||||
resolve(1)
|
resolve(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get isOpen() {
|
get isOpen () {
|
||||||
return this._isOpen ? true : false
|
return !!this._isOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
set serial (str) {
|
||||||
|
this._serial = str
|
||||||
|
}
|
||||||
|
|
||||||
|
set feed (str) {
|
||||||
|
if (!isFinite(str)) return
|
||||||
|
this._feed = Math.floor(parseInt(str))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new PrinterDevice()
|
module.exports = new PrinterDevice()
|
||||||
|
2
app.js
2
app.js
@ -1,2 +1,2 @@
|
|||||||
require('top-level-await')
|
require('top-level-await')
|
||||||
require('./server')
|
require('./server')
|
||||||
|
@ -12,7 +12,7 @@ const notifyDesciptor = new bleno.Descriptor({
|
|||||||
})
|
})
|
||||||
|
|
||||||
class DataCharacteristic extends bleno.Characteristic {
|
class DataCharacteristic extends bleno.Characteristic {
|
||||||
constructor() {
|
constructor () {
|
||||||
super({
|
super({
|
||||||
uuid: config.uuid.service.func.data,
|
uuid: config.uuid.service.func.data,
|
||||||
properties: ['write', 'writeWithoutResponse', 'notify'],
|
properties: ['write', 'writeWithoutResponse', 'notify'],
|
||||||
@ -23,15 +23,15 @@ class DataCharacteristic extends bleno.Characteristic {
|
|||||||
this._notifyFunc = null
|
this._notifyFunc = null
|
||||||
}
|
}
|
||||||
|
|
||||||
onWriteRequest(data, offset, withoutResponse, callback) {
|
onWriteRequest (data, offset, withoutResponse, callback) {
|
||||||
console.log(`offset :: ${offset} , withoutRes :: ${withoutResponse}`)
|
console.log(`offset :: ${offset} , withoutRes :: ${withoutResponse}`)
|
||||||
console.log(`get data`, data)
|
console.log(`get data`, data)
|
||||||
|
|
||||||
if (data.length == 1 && data[0] == 0x00) {
|
if (data.length === 1 && data[0] === 0x00) {
|
||||||
tmp = []
|
tmp = []
|
||||||
idx = 0
|
idx = 0
|
||||||
failFlag = false
|
failFlag = false
|
||||||
} else if (data.length == 1 && data[0] == 0xff) {
|
} else if (data.length === 1 && data[0] === 0xff) {
|
||||||
console.log(Buffer.from(tmp).toString())
|
console.log(Buffer.from(tmp).toString())
|
||||||
if (!failFlag) {
|
if (!failFlag) {
|
||||||
localEvent.emit('print', Buffer.from(tmp).toString())
|
localEvent.emit('print', Buffer.from(tmp).toString())
|
||||||
@ -53,17 +53,17 @@ class DataCharacteristic extends bleno.Characteristic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendNotidy(str) {
|
sendNotidy (str) {
|
||||||
if (!this._notifyFunc) return
|
if (!this._notifyFunc) return
|
||||||
this._notifyFunc(Buffer.from(str))
|
this._notifyFunc(Buffer.from(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubscribe(maxValueSize, cb) {
|
onSubscribe (maxValueSize, cb) {
|
||||||
console.log(maxValueSize)
|
console.log(maxValueSize)
|
||||||
this._notifyFunc = cb
|
this._notifyFunc = cb
|
||||||
}
|
}
|
||||||
|
|
||||||
onUnsubscribe() {
|
onUnsubscribe () {
|
||||||
this._notifyFunc = null
|
this._notifyFunc = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
ble/index.js
13
ble/index.js
@ -1,24 +1,21 @@
|
|||||||
|
const config = require('../config.json')
|
||||||
const bleno = require('bleno')
|
const bleno = require('bleno')
|
||||||
const adapterName = 'BLE_Printer'
|
const adapterName = 'BLE_Printer'
|
||||||
const serverUUID = config.uuid.main
|
const serverUUID = config.uuid.main
|
||||||
const localEvent = require('./localEvent')
|
const localEvent = require('./localEvent') //eslint-disable-line
|
||||||
const fs = require('fs')
|
|
||||||
const MainService = require('./main-service')
|
const MainService = require('./main-service')
|
||||||
|
|
||||||
bleno.on('stateChange', state => {
|
bleno.on('stateChange', state => {
|
||||||
console.log(`bt device state ${state}`)
|
console.log(`bt device state ${state}`)
|
||||||
if (state == 'poweredOn') {
|
if (state === 'poweredOn') {
|
||||||
|
bleno.startAdvertising(adapterName, [serverUUID])
|
||||||
bleno.startAdvertising(adapterName, [serverUUID], (error) => {
|
|
||||||
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
bleno.stopAdvertising()
|
bleno.stopAdvertising()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
bleno.on('advertisingStart', function (error) {
|
bleno.on('advertisingStart', function (error) {
|
||||||
console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'));
|
console.log('on -> advertisingStart: ' + (error ? 'error ' + error : 'success'))
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
bleno.setServices([new MainService()], error => {
|
bleno.setServices([new MainService()], error => {
|
||||||
|
@ -6,7 +6,7 @@ const GdataCharacteristic = require('./gdata-characteristic')
|
|||||||
const dataCharacteristic = new GdataCharacteristic()
|
const dataCharacteristic = new GdataCharacteristic()
|
||||||
|
|
||||||
class MainService extends bleno.PrimaryService {
|
class MainService extends bleno.PrimaryService {
|
||||||
constructor() {
|
constructor () {
|
||||||
super({
|
super({
|
||||||
uuid: config.uuid.service.id,
|
uuid: config.uuid.service.id,
|
||||||
characteristics: [
|
characteristics: [
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
const bleno = require('bleno')
|
|
||||||
const config = require('./config.json')
|
|
||||||
|
|
||||||
class TimeCharacteristic extends bleno.Characteristic {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
uuid: config.uuid.service.func.time,
|
|
||||||
properties: ['read'],
|
|
||||||
descriptors: [
|
|
||||||
new bleno.Descriptor({
|
|
||||||
uuid: '88ff',
|
|
||||||
value: 'Now Time'
|
|
||||||
})
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onReadRequest(offset, callback) {
|
|
||||||
console.log(`offset :: ${offset}`)
|
|
||||||
callback(this.RESULT_SUCCESS, new Buffer(`${Date.now()}`))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = TimeCharacteristic
|
|
@ -1,10 +1,10 @@
|
|||||||
const EventEmitter = require('events')
|
const EventEmitter = require('events')
|
||||||
const util = require('util')
|
const util = require('util') //eslint-disable-line
|
||||||
|
|
||||||
class LocalEvent extends EventEmitter {
|
class LocalEvent extends EventEmitter {
|
||||||
constructor(){
|
constructor () { // eslint-disable-line
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new LocalEvent()
|
module.exports = new LocalEvent()
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"check":"standard --fix --verbose"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bleno": "^0.4.2",
|
"bleno": "^0.4.2",
|
||||||
"escpos": "^2.4.3",
|
"escpos": "^2.4.3",
|
||||||
|
5
public/css/main.css
Normal file
5
public/css/main.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
html, body{
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
364
public/css/semantic.min.css
vendored
Executable file
364
public/css/semantic.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
4
public/js/jquery-3.2.1.min.js
vendored
Normal file
4
public/js/jquery-3.2.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/js/jquery-3.2.1.min.map
Normal file
1
public/js/jquery-3.2.1.min.map
Normal file
File diff suppressed because one or more lines are too long
19
public/js/semantic.min.js
vendored
Executable file
19
public/js/semantic.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
@ -1,12 +1,100 @@
|
|||||||
|
/* eslint-disable no-throw-literal */
|
||||||
const KoaRouter = require('koa-router')
|
const KoaRouter = require('koa-router')
|
||||||
const router = new KoaRouter()
|
const router = new KoaRouter()
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const Printer = require('../PrinterDev')
|
||||||
|
const KoaBody = require('koa-body')
|
||||||
|
const uuid = require('uuid')
|
||||||
|
|
||||||
|
router.use(async (c, n) => {
|
||||||
|
c.data = {
|
||||||
|
title: 'Printer System Setup'
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await n()
|
||||||
|
} catch (err) {
|
||||||
|
if (typeof err === 'string') {
|
||||||
|
c.body = err
|
||||||
|
} else {
|
||||||
|
c.body = err.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.async) {
|
||||||
|
c.body = {
|
||||||
|
status: 0,
|
||||||
|
msg: c.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
router
|
router
|
||||||
.get('/', async (c, n) => {
|
.get('/', async (c, n) => {
|
||||||
c.redirect('/install')
|
c.redirect('/install')
|
||||||
})
|
})
|
||||||
.all('/install', async (c, n) => {
|
.get('/install', async (c, n) => {
|
||||||
c.body = 'install'
|
// get ttys
|
||||||
|
let ttys = await new Promise((resolve, reject) => {
|
||||||
|
fs.readdir(path.resolve('/dev'), (err, list) => {
|
||||||
|
if (err) return resolve([])
|
||||||
|
let arr = []
|
||||||
|
for (let it of list) {
|
||||||
|
if (it.startsWith('tty')) {
|
||||||
|
arr.push(path.resolve('/dev', it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(arr)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
c.data.ttys = ttys
|
||||||
|
await c.render('install/index', c.data)
|
||||||
|
})
|
||||||
|
.post('/install/printer_test', KoaBody(), async (c, n) => {
|
||||||
|
c.async = true
|
||||||
|
let arr = c.request.body
|
||||||
|
if (!arr.device) throw '請輸入印表機連接埠'
|
||||||
|
let device = arr.device
|
||||||
|
let feed = arr.feed || 8
|
||||||
|
if (!isFinite(feed) || feed < 0) throw '切紙前換行必須是整數'
|
||||||
|
feed = typeof feed !== 'number' ? Math.floor(parseInt(feed)) : feed
|
||||||
|
|
||||||
|
Printer.serial = device
|
||||||
|
Printer.feed = feed
|
||||||
|
|
||||||
|
let status = await Printer.printTestPage()
|
||||||
|
|
||||||
|
if (!status) c.body = '測試失敗'
|
||||||
|
else c.body = '測試成功'
|
||||||
|
})
|
||||||
|
.post('/install/write_config', KoaBody(), async (c, n) => {
|
||||||
|
c.async = true
|
||||||
|
let arr = c.request.body
|
||||||
|
if (!arr.tty) throw '請輸入印表機連接埠'
|
||||||
|
if (!arr.ble || (arr.ble !== 'yes' && arr.ble !== 'no')) throw '請輸入藍牙啟用設定'
|
||||||
|
let feed = arr.feed || 8
|
||||||
|
if (!isFinite(feed) || feed < 0) throw '切紙前換行必須是整數'
|
||||||
|
feed = typeof feed !== 'number' ? Math.floor(parseInt(feed)) : feed
|
||||||
|
|
||||||
|
let json = {
|
||||||
|
ble: {
|
||||||
|
enable: false,
|
||||||
|
uuid: {
|
||||||
|
main: '',
|
||||||
|
service: '',
|
||||||
|
characteristic: ''
|
||||||
|
},
|
||||||
|
printer: {
|
||||||
|
serial: '',
|
||||||
|
feed: 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
json.ble.enable = arr.ble === 'yes'
|
||||||
|
json.ble.uuid.main = uuid.v4()
|
||||||
|
json.ble.uuid.service = uuid.v4()
|
||||||
|
json.ble.uuid.characteristic = uuid.v4()
|
||||||
})
|
})
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router
|
||||||
|
@ -26,7 +26,7 @@ try {
|
|||||||
resolve(1)
|
resolve(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
await chk
|
await chk //eslint-disable-line
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setupMode = true
|
setupMode = true
|
||||||
}
|
}
|
||||||
|
2
views/includes/footer.ejs
Normal file
2
views/includes/footer.ejs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
</body>
|
||||||
|
</html>
|
13
views/includes/header.ejs
Normal file
13
views/includes/header.ejs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title><%- title %></title>
|
||||||
|
<link rel="stylesheet" href="/css/semantic.min.css">
|
||||||
|
<link rel="stylesheet" href="/css/main.css">
|
||||||
|
<script src="/js/jquery-3.2.1.min.js"></script>
|
||||||
|
<script src="/js/semantic.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
38
views/install/index.ejs
Normal file
38
views/install/index.ejs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<%- include ../includes/header.ejs %>
|
||||||
|
|
||||||
|
<div class="ui container" style="padding-top: 20px;">
|
||||||
|
<h1 class="ui header">系統安裝設定</h1>
|
||||||
|
<form id="setup" class="ui form">
|
||||||
|
<h3 class="ui dividing header">印表機設定</h3>
|
||||||
|
<div class="field">
|
||||||
|
<label for="tty">印表機連接埠</label>
|
||||||
|
<select name="tty" id="tty">
|
||||||
|
<option value="">選擇裝置</option>
|
||||||
|
<% for(let i of ttys) { %>
|
||||||
|
<option value="<%= i %>"><%= i %></option>
|
||||||
|
<% } %>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="feed">切紙前空行</label>
|
||||||
|
<input type="text" name="feed" value="8" id="feed">
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<button class="ui button mini" type="button" id="test-printer">測試印表機</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="ui dividing header">藍芽列印設定</h3>
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<input type="checkbox" class="hidden" id="en-ble">
|
||||||
|
<label for="en-ble">啟用藍芽</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 40px; text-align: right;">
|
||||||
|
<button class="ui button blue" type="submit">送出設定</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%- include ../includes/footer.ejs %>
|
Loading…
Reference in New Issue
Block a user