-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #88 from entrylabs/feature/hwLite
하드웨어 웹연결 가이드 문서 추가
- Loading branch information
Showing
3 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
278 changes: 278 additions & 0 deletions
278
source/guide/entry-hw/2024-07-03-entry_hw_web_connect.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,278 @@ | ||
--- | ||
layout: page | ||
title: 브라우저로 연결하기에 하드웨어 등록 | ||
type: guide | ||
category: 'Entry HW' | ||
order: 6 | ||
--- | ||
|
||
## 브라우저로 연결하기란? | ||
'브라우저로 연결하기'이하 '하드웨어 웹연결'은 [web serial api](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API)을 사용하여 브라우저와 하드웨어 기기를 직접 연결하는 기능입니다. | ||
기존의 엔트리 하드웨어는 "사용자 기기 <=> [Entry HW 프로그램](https://playentry.org/download/hardware) <=> [엔트리 만들기 웹 페이지](https://playentry.org/ws/new)" 의 구조를 가지고 있습니다. | ||
하드웨어 웹연결은 Entry HW 프로그램을 사용하지 않고 "사용자 기기 <=> 엔트리 만들기 웹 페이지"의 구조를 가집니다. | ||
|
||
사용자 입장에서는 사용이 간편하고, 개발자 입장에서도 [entry-js](https://github.com/entrylabs/entryjs)의 코드만 관리하면 된다는 장점이 있습니다. | ||
하지만, 펌웨어와 드라이버 제공이 불가능하기에 하드웨어 제조사에서 별도의 안내를 해야하고 실험적이 기능이기에 연결이 불안정할 수도 있습니다 | ||
|
||
<br> | ||
|
||
## 유의사항 | ||
- 반드시 **자사 하드웨어 관련 파일만 수정**을 부탁드립니다. hw_Lite.js 나 기타 공용파일들 수정은 반영이 어렵습니다. | ||
- 하드웨어 웹연결에서는 기본적으로 펌웨어를 제공하지 않습니다. WS의 '펌웨어 다운로드' 버튼은 .hex파일을 다운로드하여 사용자가 직접 펌웨어 업데이트가 가능한 기기를 위한 기능입니다. | ||
- 하드웨어 웹연결 기능은 개발 초기 단계로 추후 **제공 함수나 연결 라이프사이클이 변경될 수 있습니다**. 경우에 따라서는 제조사측 코드를 수정해야 할 수 있으므로 미리 유의 부탁드립니다. | ||
|
||
<br> | ||
|
||
## PR 파일 간략 설명 | ||
![HwLite_select1](/images/entry-hw/HwLite_select1.png) | ||
|
||
이 단원에서는 최종적으로 제조사가 entryjs에 PR해야할 파일 작성시 유의사항과 간략한 역할을 기술합니다. | ||
하드웨어 웹연결을 지원하기 위해선 아래 3종류의 파일이 필수적으로 추가되어야 합니다. 아래 3파일을 작성후 entryjs의 develop-hw로 PR부탁드립니다. | ||
|
||
### block_모듈명 _lite.js | ||
- 반드시 entryjs > src > playground > blocks > hardwareLite 하위에 위치해야합니다. | ||
- 파일명은 반드시 block_ 모듈명 _lite.js 이어야 합니다. | ||
- 이 파일에서 하드웨어 웹연결에 필요한 정보를 담고있는 모듈클래스를 정의하게 됩니다. | ||
- 기존 하드웨어 연결에서 entryjs의 block_모듈명.js와 entry-hw의 모듈명.js의 역할을 모두 가지고 있습니다. | ||
|
||
### metadata_모듈명 _lite.json | ||
- 반드시 entryjs > src > playground > blocks > hardwareLite 하위에 위치해야합니다. | ||
- 파일명은 반드시 metadata_ 모듈명 _lite.json 이어야 합니다. | ||
- 웹연결 모듈에 대한 메타데이터를 가지고 있습니다. | ||
- 이 파일의 moduleId와 block_ 모듈명 _lite.js 의 클래스 내 id는 반드시 일치해야 합니다.(포맷이 다르므로 다른 하드웨어 웹연결 파일들을 예시로 참고해 주세요.) | ||
- 이 파일의 title, description은 WS에서 '브라우저로 연결하기' 클릭시 나타나는 위의 이미지화면에서 모듈카드의 정보를 가지고 있습니다. | ||
|
||
### 모듈명.png | ||
- 반드시 entryjs > images > hw_lite 하위에 위치해야 합니다. | ||
- '브라우저로 연결하기' 클릭시 나타나는 위의 이미지화면에서 보여지는 이미지 파일입니다. | ||
- 파일명은 block_ 모듈명 _lite.js 에서 정의한 클래스 생성자의 this.imageName과 일치해야 합니다. | ||
|
||
<br> | ||
|
||
## block_ 모듈명 _lite.js 구조 설명 | ||
WS가 실행되었을경우, Entry.모듈클래스 를 추가하는 함수가 즉시 실행됩니다. | ||
이 파일에 정의되는 모듈클래스 구조와 역할은 다음과 같습니다. | ||
|
||
### 모듈클래스 | ||
|
||
``` javascript | ||
'use strict'; | ||
|
||
(function () { | ||
Entry.ArduinoLite = new (class ArduinoLite { | ||
constructor() { | ||
this.id = '010101'; // id는 6자리 모두 입력해야 합니다. | ||
this.name = 'ArduinoLite'; | ||
this.url = 'http://www.arduino.cc/'; | ||
this.imageName = 'arduinolite.png'; | ||
this.title = { | ||
ko: '아두이노 우노', | ||
en: 'Arduino Uno', | ||
}; | ||
this.duration = 32; // 엔트리js에서 기기와 통신하는 함수를 호출하는 duration 간격입니다. | ||
this.blockMenuBlocks = [ | ||
'arduinolite_get_number_sensor_value', | ||
'arduinolite_get_digital_value', | ||
]; | ||
this.portData = { | ||
baudRate: 9600, | ||
duration: 32, // web serial api에서 기기와 통신하는 duration 간격입니다. | ||
dataBits: 8, | ||
parity: 'none', | ||
stopBits: 1, | ||
bufferSize: 512, | ||
constantServing: true, | ||
}; | ||
this.readablePorts = []; | ||
this.setZero(); | ||
} | ||
|
||
setZero() { | ||
this.port = new Array(14).fill(0); | ||
this.digitalValue = new Array(14).fill(0); | ||
this.remoteDigitalValue = new Array(14).fill(0); | ||
this.analogValue = new Array(6).fill(0); | ||
this.readablePorts = _range(0, 19); | ||
|
||
if (Entry.hwLite && Entry.hwLite.serial) { | ||
Entry.hwLite.serial.update(); | ||
} | ||
} | ||
|
||
// 디바이스에서 값을 읽어옵니다. | ||
handleLocalData(data) {} | ||
|
||
//디바이스에 값을 씁니다. | ||
requestLocalData() { | ||
const queryString = []; | ||
// ... | ||
return queryString; | ||
} | ||
|
||
setLanguage() { | ||
return { | ||
ko: { | ||
template: { | ||
arduinolite_text: '%1', | ||
arduinolite_get_sensor_number: '%1', | ||
arduinolite_get_port_number: '%1', | ||
}, | ||
Device: { | ||
arduinolite: '아두이노', | ||
}, | ||
Menus: { | ||
arduinolite: '아두이노', | ||
}, | ||
}, | ||
en: { | ||
template: { | ||
arduinolite_text: '%1', | ||
arduinolite_get_sensor_number: '%1', | ||
arduinolite_get_port_number: '%1', | ||
}, | ||
Device: { | ||
arduinolite: 'arduinolite', | ||
}, | ||
Menus: { | ||
arduinolite: 'ArduinoLite', | ||
}, | ||
}, | ||
}; | ||
} | ||
|
||
getBlocks() { | ||
return { | ||
arduinolite_get_sensor_number: { | ||
color: EntryStatic.colorSet.block.default.HARDWARE, | ||
outerLine: EntryStatic.colorSet.block.darken.HARDWARE, | ||
skeleton: 'basic_string_field', | ||
statements: [], | ||
params: [ | ||
{ | ||
type: 'Dropdown', | ||
options: [ | ||
['0', 'A0'], | ||
['1', 'A1'], | ||
['2', 'A2'], | ||
['3', 'A3'], | ||
['4', 'A4'], | ||
['5', 'A5'], | ||
], | ||
value: 'A0', | ||
fontSize: 11, | ||
bgColor: EntryStatic.colorSet.block.darken.HARDWARE, | ||
arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, | ||
}, | ||
], | ||
events: {}, | ||
def: { | ||
params: [null], | ||
}, | ||
paramsKeyMap: { | ||
PORT: 0, | ||
}, | ||
func(sprite, script) { | ||
return script.getStringField('PORT'); | ||
}, | ||
}, | ||
// ... | ||
}; | ||
} | ||
})(); | ||
})(); | ||
|
||
module.exports = Entry.ArduinoLite; | ||
|
||
|
||
|
||
``` | ||
|
||
- constructor | ||
- imageName : 샘플파일 이미지와 이름이 같아야 합니다 | ||
- portData : web-serial api를 사용해 브라우저로 기기와 통신하기위한 세팅값입니다. 연결이 불안정한경우가 아니라면 가급적 수정하지 않는것을 추천드립니다. | ||
- duration : 기기와 통신하는 간격입니다.(ms단위) | ||
- blockMenuBlocks : 블럭명세 정보입니다. | ||
|
||
- get monitorTemplate() : WS에서 하드웨어 연결시 좌측 ''오브젝트 추가하기'' 하단의 4번째 탭에 보여지는 센서 모니터링 툴을 사용하기 위한 함수입니다. 초기값 세팅 역할을 합니다. | ||
|
||
- getMonitorPort() : monitorTemplate()와 마찬가지로 모니터링 툴용 함수입니다. 실시간 값 갱신을 위한 함수입니다. | ||
|
||
- setZero() : 연결시작 및 연결해제시 기기상태를 초기화하기 위한 함수입니다. | ||
|
||
- handleLocalData(data) : 기기로부터 값을 읽어서 WS에 반영하는 함수입니다. (기기로부터 값 읽음) this.portData.constantServing일 경우 사용합니다. | ||
|
||
- requestLocalData() : WS의 블록동작의 명령을 기기에게 쓰는 함수입니다. (기기에 값 쓰기) this.portData.constantServing일 경우 사용합니다. | ||
|
||
- getBlocks() : 블럭 상세 정보 및 로직을 반환하는 함수입니다. | ||
|
||
|
||
|
||
<br> | ||
|
||
## 통신방법 | ||
디바이스와 통신하는 방법에는 아래 2가지가 있습니다. | ||
|
||
### 지속 통신 | ||
- 사용자 액션(블럭 실행)이 없어도 항상 지정된 duration간격만큼 지속통신하는 방법입니다. | ||
- block_ 모듈명 _lite.js 의 생성자에서 this.duration값을 지정하고, this.portData.constantServing 를 true로 세팅하게되면 handleLocalData(data)함수와 requestLocalData() 함수가 자동으로 실행되게 됩니다. | ||
- ex. [block_arduino_lite.js](https://github.com/entrylabs/entryjs/blob/develop/src/playground/blocks/hardwareLite/block_arduino_lite.js), [block_sensorboard_lite](https://github.com/entrylabs/entryjs/blob/develop/src/playground/blocks/hardwareLite/block_sensorboard_lite.js), [block_hamster_lite](https://github.com/entrylabs/entryjs/blob/develop/src/playground/blocks/hardwareLite/block_hamster_lite.js) | ||
|
||
### 단건 통신 | ||
- 사용자 액션(블럭 실행)이 있을때만 통신하는 방법입니다. | ||
- 필요할 때만 통신하므로 일반적으로 지속통신방법보다 부하가 적지만, '계속 반복하기' 블럭 안에서 하드웨어 블럭을 사용하는 것처럼(초당 60번 호출) 단기간에 많은 통신을 할 경우 문제가 발생할 수도 있습니다. | ||
- Entry.hwLite.serial.sendAsyncWithThrottle(기기에 입력할 값 : buffer | string, 리턴값 여부 | boolean)으로 호출할 수 있습니다. 첫번째 파라미터에는 기기에 입력할 버퍼, 두번째 파라미터를 false로 할 경우 기기로부터 받는 응답값을 받지 않습니다. 상세구조는 Entry.hwLite.serial.sendAsync() 함수를 확인 부탁드립니다. | ||
- ex. [block_microbit2_lite](https://github.com/entrylabs/entryjs/blob/develop/src/playground/blocks/hardwareLite/block_microbit2_lite.js) | ||
|
||
#### Entry.hwLite.serial.sendAsyncWithThrottle | ||
- Return : 기기로부터 리턴된 value값 | ||
|
||
| 파라미터 | 타입 | 선택적 | 설명 | | ||
| ---------- | ---------------- | ------ | ------------------------------------------------------------ | | ||
| data | Buffer \| string | | 기기에 송신할 데이터입니다. string 타입일경우 utf8로 인코딩되어 송신됩니다. | | ||
| isResetReq | boolean | ✔️ | 데이터를 송신한 이후에 기기로부터 응답을 받지 않고 함수를 종료합니다. | | ||
| callback | Function | ✔️ | 함수가 존재할경우, 송수신 완료 후 callback(value)값을 리턴합니다. | | ||
|
||
|
||
<br> | ||
|
||
## 기타 웹연결 관련 함수들 | ||
### Entry.playground.addHardwareLiteModule | ||
웹연결에 사용할 모듈을 선택하는 함수입니다. | ||
파라미터로 Entry.모듈명(ex. Entry.Neobot)을 넣으면 해당 하드웨어가 선택됩니다. | ||
실제 운영 엔트리WS에서는 '브라우저로 연결하기' => '팝업에서 모듈 선택 후 불러오기' 까지 진행하면 자동으로 이 함수가 실행되지만, entryjs만 사용한 개발환경에서는 위 팝업을 사용할 수 없기 때문에 직접 함수를 실행시켜주셔야 합니다. | ||
|
||
|
||
|
||
| 파라미터 | 타입 | 선택적 | 설명 | | ||
| -------- | ------------------------------------------------------------ | ------ | ------------------------------- | | ||
| module | [EntryHardwareBlockModule](https://github.com/entrylabs/entryjs/blob/edb5380602a0f035fb2b20eb9d2b7c8f1247f15d/types/index.d.ts#L180) | | 웹연결에 사용할 모듈객체입니다. | | ||
|
||
|
||
|
||
### Entry.hwLite.connect | ||
웹연결 연결실행 함수입니다. | ||
|
||
### Entry.hwLite.disconnect | ||
웹연결 연결해제 함수입니다. 가급적 직접 호출보다는 '연결 해제하기' 버튼을 사용해주세요. | ||
|
||
### Entry.hwLite.serial.handleConnectErrorInEngineRun | ||
연결중 기기가 멈추거나 화면이 멈추는 등, 강제종료가 필요한 상황에 사용하는 함수입니다. | ||
|
||
### Entry.hwLite.getConnectFailedMenu | ||
연결실패화면을 출력해야 할 때 사용합니다. | ||
|
||
![HwLite_failedMenu1](/images/entry-hw/HwLite_failedMenu1.png) | ||
|
||
<br> | ||
|
||
## 테스트하기 | ||
다음 2가지 방법으로 테스트하실수 있습니다. | ||
|
||
A. entryjs와 entry-tool을 함께 적용하고 계시다면 어려움없이 하드웨어 탭에서 '브라우저로 연결하기' > 모듈선택 > 포트선택으로 테스트하실수 있습니다. | ||
B. entryjs에서 yarn serve만으로 테스트하고 계시다면, 아래 순서로 진행해주세요 | ||
- 크롬 개발자도구에서 `Entry.playground.addHardwareLiteModule(Entry.모듈클래스명);`를 입력합니다. 사용자가 팝업창에서 해당모듈을 선택했을때 실행되는 동작입니다. | ||
- 크롬 개발자도구에서 `Entry.hwLite.connect();`를 입력합니다. 사용자가 연결하기 버튼을 클릭할때 실행되는 동작입니다. | ||
- 모듈이 연결된 포트를 선택하고 완료를 누르면 블록이 출력됩니다. | ||
|
||
혹시 연결이 정상적으로 진행되지 않는다면 Entry.모듈명과 Entry.HARDWARE_LITE_LIST['모듈ID'] 이 존재하는지 확인 부탁드립니다, 둘중 하나라도 없다면 정상동작하지 않습니다. 모듈의 name, id 등을 체크해주세요. | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.