From 5f975b4479856573e13764225d6e6d92cbb12086 Mon Sep 17 00:00:00 2001 From: oopchoi Date: Thu, 11 Apr 2024 16:19:30 +0900 Subject: [PATCH] =?UTF-8?q?feature/=EB=B8=8C=EB=9D=BC=EC=9A=B0=EC=A0=80?= =?UTF-8?q?=EB=A1=9C=20=EC=97=B0=EA=B2=B0=ED=95=98=EA=B8=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- images/hw_lite/codewizlite.png | Bin 0 -> 123478 bytes .../blocks/hardwareLite/block_codewiz_lite.js | 6719 +++++++++++++++++ .../hardwareLite/metadata_codewiz_lite.json | 9 + 3 files changed, 6728 insertions(+) create mode 100644 images/hw_lite/codewizlite.png create mode 100644 src/playground/blocks/hardwareLite/block_codewiz_lite.js create mode 100644 src/playground/blocks/hardwareLite/metadata_codewiz_lite.json diff --git a/images/hw_lite/codewizlite.png b/images/hw_lite/codewizlite.png new file mode 100644 index 0000000000000000000000000000000000000000..2169d1ca0019fd0549b94288cc19af4d62a3c382 GIT binary patch literal 123478 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 literal 0 HcmV?d00001 diff --git a/src/playground/blocks/hardwareLite/block_codewiz_lite.js b/src/playground/blocks/hardwareLite/block_codewiz_lite.js new file mode 100644 index 0000000000..ab40ebcc77 --- /dev/null +++ b/src/playground/blocks/hardwareLite/block_codewiz_lite.js @@ -0,0 +1,6719 @@ +'use strict'; + +(function() { + Entry.CodeWizLite = new (class CodeWizLite { + constructor() { + this.id = '011201'; + this.name = 'CodeWizLite'; + this.url = 'https://www.codable.co.kr'; + this.imageName = 'codewizlite.png'; + this.title = { + ko: '코드위즈', + en: 'CodeWiz', + }; + this.duration = 32; + + this.portData = { + baudRate: 115200, + duration: 32, + dataBits: 8, + parity: 'none', + stopBits: 1, + bufferSize: 512, + constantServing: true, + }; + + this.receiveType = { + SENSOR_TYPE1: 0, + SENSOR_TYPE2: 1, + HUSKY_RESULTS: 2, + BOOLEAN: 3, + INT: 4, + FLOAT: 5, + RUN_OK: 6, + }; + + this.defaultSensorList = ['SOUND', 'LIGHT', 'DIST', 'HALL']; + this.defaultSensorList2 = [ + 'touchPin_13', + 'touchPin_14', + 'touchPin_15', + 'touchPin_27', + 'touchPin_32', + 'touchPin_33', + 'switchButton_4', + 'switchButton_26', + 'GYRO_X', + 'GYRO_Y', + 'GYRO_Z', + 'tempSensor', + ]; + + this.isDraing = false; + this.isFirst = true; + + this.blockMenuBlocks = [ + 'CodeWizLite_sensor_title', + 'CodeWizLite_get_sensor', + 'CodeWizLite_get_gyroSensor', + 'CodeWizLite_isPushedButton', + 'CodeWizLite_touchPin', + + 'CodeWizLite_buzzer_title', + 'CodeWizLite_default_buzzer', + + 'CodeWizLite_neopixel_title', + 'CodeWizLite_neopixel_init', + 'CodeWizLite_neopixel_brightness', + 'CodeWizLite_neopixel_setColor_one', + 'CodeWizLite_neopixel_setColor_one2', + 'CodeWizLite_neopixel_off_one', + 'CodeWizLite_neopixel_setColor_all', + 'CodeWizLite_neopixel_setColor_all2', + 'CodeWizLite_neopixel_off_all', + 'CodeWizLite_neopixel_OnPixelRandomColor', + 'CodeWizLite_neopixel_fillRandom', + 'CodeWizLite_neopixel_rotate', + 'CodeWizLite_neopixel_shift', + 'CodeWizLite_neopixel_gradationRGB', + 'CodeWizLite_neopixel_gradationHSL', + 'CodeWizLite_neopixel_wheeeeeeel', + + 'CodeWizLite_OLED_title', + 'CodeWizLite_OLED_clear', + 'CodeWizLite_OLED_mirror', + 'CodeWizLite_OLED_setSize', + 'CodeWizLite_OLED_setPosition', + 'CodeWizLite_OLED_println', + 'CodeWizLite_OLED_isCollision', + 'CodeWizLite_OLED_specialChar', + 'CodeWizLite_OLED_setFont', + 'CodeWizLite_OLED_startScroll', + 'CodeWizLite_OLED_stopScroll', + 'CodeWizLite_OLED_drawPoint', + 'CodeWizLite_OLED_drawLine1', + 'CodeWizLite_OLED_drawLine2', + 'CodeWizLite_OLED_drawLine3', + 'CodeWizLite_OLED_drawRect', + 'CodeWizLite_OLED_drawCircle', + 'CodeWizLite_OLED_drawPoligon', + 'CodeWizLite_OLED_printHG', + + 'CodeWizLite_DIGITAL_OUTPUT_title', + 'CodeWizLite_DIGITAL_OUTPUT_digitalWrite', + 'CodeWizLite_DIGITAL_OUTPUT_pwmWrite', + + 'CodeWizLite_OzEye_title', + 'CodeWizLite_OzEye_initOzEye', + 'CodeWizLite_OzEye_setModeOfOzEye', + 'CodeWizLite_OzEye_readOzEye', + 'CodeWizLite_OzEye_isLearnedOzEye', + 'CodeWizLite_OzEye_isContainOzEye', + 'CodeWizLite_OzEye_getCountLearnedOzEye', + 'CodeWizLite_OzEye_hasTypeOzEye', + 'CodeWizLite_OzEye_getArrowInfoOzEye', + 'CodeWizLite_OzEye_getBoxInfoOzEye2', + 'CodeWizLite_OzEye_getBoxInfoOzEye', + // 'CodeWizLite_OzEye_writeTextOzEye', + // 'CodeWizLite_OzEye_clearTextOzEye', + 'CodeWizLite_OzEye_setLightLevel', + 'CodeWizLite_OzEye_LightOff', + + 'CodeWizLite_HuskyLens_title', + 'CodeWizLite_HuskyLens_initHuskyLens', + 'CodeWizLite_HuskyLens_setModeOfHuskyLens', + 'CodeWizLite_HuskyLens_readHuskyLens', + 'CodeWizLite_HuskyLens_isLearnedHuskyLens', + 'CodeWizLite_HuskyLens_isContainHuskyLens', + 'CodeWizLite_HuskyLens_getCountLearnedHuskyLens', + 'CodeWizLite_HuskyLens_hasTypeHuskyLens', + 'CodeWizLite_HuskyLens_getArrowInfoHuskyLens', + 'CodeWizLite_HuskyLens_getBoxInfoHuskyLens2', + 'CodeWizLite_HuskyLens_getBoxInfoHuskyLens', + 'CodeWizLite_HuskyLens_writeTextHuskyLens', + 'CodeWizLite_HuskyLens_clearTextHuskyLens', + + 'CodeWizLite_Servo_title', + 'CodeWizLite_Servo_setAngle', + 'CodeWizLite_Servo_menuSpeed', + 'CodeWizLite_Servo_customSpeed', + + 'CodeWizLite_Dc_title', + 'CodeWizLite_Dc_setCarSpeed', + 'CodeWizLite_Dc_setValue_Waterpump', + + 'CodeWizLite_DotMatrix_title', + 'CodeWizLite_DotMatrix_init', + 'CodeWizLite_DotMatrix_setBrightness', + 'CodeWizLite_DotMatrix_printString', + 'CodeWizLite_DotMatrix_setLine', + // 'CodeWizLite_DotMatrix_Show_Custom_Image', + 'CodeWizLite_DotMatrix_setDot', + 'CodeWizLite_DotMatrix_clear', + 'CodeWizLite_DotMatrix_clearAll', + + 'CodeWizLite_ColorSensor_title', + 'CodeWizLite_ColorSensor_isColor', + 'CodeWizLite_ColorSensor_getColorValue', + + 'CodeWizLite_DHT_title', + 'CodeWizLite_DHT_init', + 'CodeWizLite_DHT_getValue', + + 'CodeWizLite_Joystick_title', + 'CodeWizLite_Joystick_setPin', + 'CodeWizLite_Joystick_readAxis', + 'CodeWizLite_Joystick_readButton', + + 'CodeWizLite_etcReadSensor_title', + 'CodeWizLite_etcReadSensor_mconRead', + 'CodeWizLite_etcReadSensor_digitalRead', + 'CodeWizLite_etcReadSensor_InfraredThermometerRead', + ]; + + this.sensorTypes = { + READ: 1, + WRITE: 0, + }; + + this.setZero(); + } + + __sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + // 하드웨어 연결 후 초기화를 위한 함수입니다. + async initialHandshake() { + const runApp0 = [0xc0, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0]; + // DTR과 RTS 설정 + await Entry.hwLite.serial.port.setSignals({ + dataTerminalReady: false, + requestToSend: true, + }); + // console.log('Successfully set DTR false and RTS true.'); + await this.__sleep(200); + + await Entry.hwLite.serial.port.setSignals({ + dataTerminalReady: true, + requestToSend: false, + }); + // console.log('Successfully set DTR true and RTS false.'); + await this.__sleep(800); + + await Entry.hwLite.serial.port.setSignals({ + dataTerminalReady: false, + requestToSend: false, + }); + // console.log('Successfully set DTR false and RTS false.'); + await this.__sleep(1000); + + await Entry.hwLite.serial.sendAsync(runApp0); + + return true; + } + + // 시작하기 및 정지하기 시 기기상태를 초기화하기 위한 함수입니다. + setZero() { + this.sendBuffers = []; + this.recvBuffers = []; + + this.sensorData = { + SOUND: 0, + LIGHT: 0, + DIST: 0, + HALL: 0, + touchPin_13: 0, + touchPin_14: 0, + touchPin_15: 0, + touchPin_27: 0, + touchPin_32: 0, + touchPin_33: 0, + switchButton_4: 0, + switchButton_26: 0, + tempSensor: 0.0, + GYRO_X: 0, + GYRO_Y: 0, + GYRO_Z: 0, + HUSKY_READ: { + _type: 0, + _count: 0, + _list: [], + }, + }; + + this.HUSKY = { + CENT_X: 160, + CENT_Y: 120, + getDist: function(x, y) { + return Math.sqrt(Math.pow(this.CENT_X - x, 2) + Math.pow(this.CENT_Y - y, 2)); + }, + }; + + this.sendQueue = { + ORDER: {}, + RESET: 1, + }; + + if (Entry.hwLite && Entry.hwLite.serial) { + const reset = [254, 255, 3, 1, 0]; + Entry.hwLite.serial.sendAsync(reset); + } + } + + // 기기로부터 값을 읽어서 WS에 반영하는 함수입니다. (기기로부터값 읽음) + //this.portData.constantServing일 경우 사용합니다. + handleLocalData(data) { + const datas = this.getDataByBuffer(data); + + datas.forEach((readData) => { + let value; + switch (readData[1]) { + case this.receiveType.SENSOR_TYPE1: { + for (let i = 1; 2 * i < readData.length; ++i) { + value = (readData[i * 2] << 8) | readData[i * 2 + 1]; + if (i === 3) { + if (value < 3000) { + Entry.CodeWizLite.sensorData.DIST = value; + } + } else if (i === 4) { + Entry.CodeWizLite.sensorData.HALL = value - 300; + } else { + this.sensorData[this.defaultSensorList[i - 1]] = value; + } + } + this.shouldUpdateSensor1 = true; + return; + } + case this.receiveType.SENSOR_TYPE2: { + let _value; + for (let i = 0; i < 8; ++i) { + _value = (readData[2] >> i) & 1; + this.sensorData[this.defaultSensorList2[i]] = _value === 1; + } + for (let i = 8; i < 8 + 3; ++i) { + _value = readData[i - 5]; + if (_value <= 180) { + this.sensorData[this.defaultSensorList2[i]] = _value - 90; + } + } + //temperature + _value = (readData[6] << 8) | readData[7]; + _value -= 400; + _value /= 10.0; + if (_value < 81) { + this.sensorData[this.defaultSensorList2[11]] = _value; + } + this.shouldUpdateSensor2 = true; + return; + } + case this.receiveType.HUSKY_RESULTS: { + Entry.CodeWizLite.sensorData.HUSKY_READ._type = readData[2]; + Entry.CodeWizLite.sensorData.HUSKY_READ._count = readData[3]; + Entry.CodeWizLite.sensorData.HUSKY_READ._list = []; + for (let i = 0; i < readData[3]; ++i) { + Entry.CodeWizLite.sensorData.HUSKY_READ._list.push([ + readData[9 * i + 4], + (readData[9 * i + 5] << 8) | readData[9 * i + 6], + (readData[9 * i + 7] << 8) | readData[9 * i + 8], + (readData[9 * i + 9] << 8) | readData[9 * i + 10], + (readData[9 * i + 11] << 8) | readData[9 * i + 12], + ]); + } + this.shouldUpdateHusky = true; + return; + } + case this.receiveType.RUN_OK: { + // this.handler.write(this.curId, { value: 'runOK' }); + this.sensorData[this.curId] = { value: 'runOK' }; + + return; + } + case this.receiveType.BOOLEAN: { + // this.handler.write(this.curId, { value: readData[2] === 1 }); + this.sensorData[this.curId] = { value: readData[2] === 1 }; + return; + } + case this.receiveType.INT: { + let _sign = readData[2] === 1; + let _value = (readData[3] << 8) | readData[4]; + if (_sign) { + _value *= -1; + } + // this.handler.write(this.curId, { value: _value }); + this.sensorData[this.curId] = { value: _value }; + return; + } + case this.receiveType.FLOAT: { + let _sign = readData[2] & 0x80; // -: 1, +:0 + let firstData = readData[2] & 0x7f; + let _value = (firstData << 8) | readData[3]; + if (_sign === 1) { + _value *= -1; + } + _value /= 10; + // this.handler.write(this.curId, { value: _value }); + this.sensorData[this.curId] = { value: _value }; + return; + } + default: { + return; + } + } + }); + } + + /* + 하드웨어 기기에 전달할 데이터를 반환합니다. + slave 모드인 경우 duration 속성 간격으로 지속적으로 기기에 요청을 보냅니다. + */ + + //WS의 블록동작의 명령을 기기에게 쓰는 함수입니다. (기기에 값 쓰기) + //this.portData.constantServing일 경우 사용합니다 + requestLocalData() { + if (this.sendBuffers.length > 0) { + const dataToSend = this.sendBuffers.shift(); + return dataToSend; + } + return null; + } + + getHashKey(opcode) { + // let key = new Date().getSeconds().toString(16); + // if (key.length === 1) { + // key += ((Math.random() * 16) | 0).toString(16); + // } + // return Entry.generateHash(6) + opcode; + // Symbol을 쓰면 hw로 넘길수있나 -> 있으면 지금과 비교해서 속도는? + return ( + Date.now() + .toString() + .substring(6) + opcode + ); + } + + // 코드위즈에 보낼 데이터를 만드는 함수입니다. + sendOrder(order) { + Entry.CodeWizLite.intervalId = true; + const id = this.getHashKey(order.value.opcode); + this.sendQueue.ORDER[id] = order; + Entry.hwLite.serial.update(); + + let buffer = null; + if (this.sendQueue.ORDER) { + const keys = Object.keys(this.sendQueue.ORDER); + keys.forEach((id) => { + const data = this.sendQueue.ORDER[id]; + if (data) { + buffer = this.makeSendMessage(data.type, data.value); + if (buffer?.length > 0) { + this.sendBuffers.push(buffer); + this.curId = id; + } + } + }); + } + this.deleteOrder(id); + + return id; + } + + deleteOrder(id) { + Entry.CodeWizLite.sensorData[id] = { value: null }; + delete this.sendQueue.ORDER[id]; + Entry.hwLite.serial.update(); + } + + getOffsetX(str) { + return this.getByteLength(str) * 1.5 - 18; + } + + getByteLength(s, b, i, c) { + if (!s) { + return; + } + for (b = i = 0; (c = s.charCodeAt(i++)); b += c >> 11 ? 3 : c >> 7 ? 2 : 1); + return b; + } + + getMonitorPort() { + return { ...this.sensorData }; + } + + get monitorTemplate() { + return { + imgPath: 'hw_lite/codewizlite.png', + width: 200, + height: 200, + + mode: 'both', + }; + } + + processData(dataArr) { + let retVal = []; + for (let i = 0; i < dataArr.length; ++i) { + retVal.push(...this.strToAscii('' + dataArr[i])); + } + return retVal; + } + + strToAscii(str) { + if (!str) { + return []; + } + // let ret = [str.length]; + let ret = []; + for (let i = 0; i < str.length; ++i) { + // ret.push(str[i].charCodeAt()); + let c = str[i].charCodeAt(); + if (c > 0xff) { + ret.push(0x08, c >> 8, c & 0xff); + } else { + ret.push(c); + } + } + ret.unshift(ret.length); + return ret; + } + + makeSendMessage(type, data) { + if (!$.isPlainObject(data)) { + return null; + } + let buffer = this.addHeader(type, [data.opcode, ...this.processData(data.params)]); + // console.log('makeSendMessage:', buffer); + return buffer; + } + + addHeader(actionType, data) { + return [254, 255, data.length + 2, actionType, ...data]; + } + + getDataByBuffer(buffer) { + this.recvBuffers.push(...buffer); + let datas = []; + let lastIdx = 0; + this.recvBuffers.forEach((value, idx, d) => { + if (value === 0xff && d[idx + 1] === 0xfe) { + lastIdx = idx + 2 + d[idx + 2]; + datas.push(d.slice(idx + 2, lastIdx)); + } + }); + this.recvBuffers.splice(0, lastIdx); + return datas; + } + + preWait() { + return new Promise((resolve) => { + let tmp = setInterval(() => { + // console.log('preWait:', Entry.CodeWizLite.intervalId); + if (!Entry.CodeWizLite.intervalId) { + clearInterval(tmp); + // Entry.CodeWizLite.preWaitResult = Entry.CodeWizLite.preWaitList.shift() || null; + resolve(); + } + }, 11); + }); + } + + checkComplete(timeout, id) { + let _promise = new Promise((resolve) => { + timeout = timeout ?? 1000; + Entry.CodeWizLite.intervalId = setInterval(() => { + // console.log(Entry.CodeWizLite.intervalId, 'runOK:', Entry.CodeWizLite.sensorData[id]); + let ret = Entry.CodeWizLite.sensorData[id]?.value; + if (ret !== undefined && ret !== null) { + clearInterval(Entry.CodeWizLite.intervalId); + clearTimeout(Entry.CodeWizLite.timeoutId); + Entry.CodeWizLite.intervalId = null; + Entry.CodeWizLite.timeoutId = null; + resolve(); + } + }, 7); + Entry.CodeWizLite.timeoutId = setTimeout(() => { + clearInterval(Entry.CodeWizLite.intervalId); + // console.log(Entry.CodeWizLite.intervalId, 'timeOut'); + Entry.CodeWizLite.intervalId = null; + Entry.CodeWizLite.timeoutId = null; + // throw new Entry.Utils.AsyncError('TimeOutOccurred'); + resolve(); + }, timeout); + }); + return _promise; + } + + setLanguage() { + return { + ko: { + template: { + CodeWizLite_sensor_title: '기본 센서', + CodeWizLite_get_sensor: '%1센서 값', + CodeWizLite_get_gyroSensor: '3축 센서 %1값', + CodeWizLite_isPushedButton: '%1 스위치 버튼 값', + CodeWizLite_touchPin: '터치핀 %1 값', + + CodeWizLite_buzzer_title: '스피커', + CodeWizLite_default_buzzer: + '스피커를 %1옥타브, %2음, %3분음표로 연주하기 %4', + + CodeWizLite_neopixel_title: '네오픽셀', + CodeWizLite_neopixel_init: '네오픽셀 %1에 %2개로 시작설정%3', + CodeWizLite_neopixel_brightness: '네오픽셀 밝기를 %1로 설정(0~255)%2', + CodeWizLite_neopixel_setColor_one: '네오픽셀 %1번 LED를 %2(으)로 켜기%3', + CodeWizLite_neopixel_setColor_one2: + '네오픽셀 %1번 LED를 빨강%2초록%3파랑%4(으)로 켜기%5', + CodeWizLite_neopixel_off_one: '네오픽셀 %1번 LED 끄기%2', + CodeWizLite_neopixel_setColor_all: '네오픽셀 %1(으)로 모두 켜기%2', + CodeWizLite_neopixel_setColor_all2: + '네오픽셀 빨강%1초록%2파랑%3(으)로 모두 켜기%4', + CodeWizLite_neopixel_off_all: '네오픽셀 모두 끄기%1', + CodeWizLite_neopixel_OnPixelRandomColor: + '네오픽셀 %1번 LED 무작위 색으로 켜기%2', + CodeWizLite_neopixel_fillRandom: '네오픽셀 무작위 색으로 채우기%1', + CodeWizLite_neopixel_rotate: '네오픽셀 LED %1으로 회전시키기%2', + CodeWizLite_neopixel_shift: '네오픽셀 LED %1으로 밀기%2', + CodeWizLite_neopixel_gradationRGB: + '네오픽셀 %1번부터 %2번까지 RGB그라데이션(%3,%4)으로 켜기%5', + CodeWizLite_neopixel_gradationHSL: + '네오픽셀 %1번부터 %2번까지 HSL그라데이션(%3,%4)으로 켜기%5', + CodeWizLite_neopixel_wheeeeeeel: '네오픽셀 휠%1', + + CodeWizLite_OLED_title: 'OLED', + CodeWizLite_OLED_clear: 'OLED 지우기%1', + CodeWizLite_OLED_mirror: 'OLED 반전 모드%1 %2', + CodeWizLite_OLED_setSize: 'OLED 문자 크기를 %1(으)로 설정%2', + CodeWizLite_OLED_setPosition: 'OLED 커서위치(%1,%2)(으)로 지정%3', + CodeWizLite_OLED_println: 'OLED에 %1 출력%2', + CodeWizLite_OLED_isCollision: 'OLED 자동 줄바꿈%1%2', + CodeWizLite_OLED_specialChar: 'OLED에 기호%1 출력하기%2', + CodeWizLite_OLED_setFont: 'OLED 폰트%1를 크기%2(으)로 설정%3', + CodeWizLite_OLED_startScroll: 'OLED 스크롤 시키기%1 시작%2~종료%3(0~7)%4', + CodeWizLite_OLED_stopScroll: 'OLED 스크롤 멈추기%1', + CodeWizLite_OLED_drawPoint: 'OLED 점찍기 (%1,%2)%3%4', + CodeWizLite_OLED_drawLine1: 'OLED 선 그리기 시작(%1,%2) 끝(%3,%4)%5%6', + CodeWizLite_OLED_drawLine2: 'OLED 수직선 시작(%1,%2) 길이%3%4%5', + CodeWizLite_OLED_drawLine3: 'OLED 수평선 시작(%1,%2) 길이%3%4%5', + CodeWizLite_OLED_drawRect: 'OLED 직사각형 시작(%1,%2) 가로%3세로%4%5%6%7', + CodeWizLite_OLED_drawCircle: 'OLED 원 중심(%1,%2) 반지름%3%4%5%6', + CodeWizLite_OLED_drawPoligon: + 'OLED 삼각형 점1(%1,%2)점2(%3,%4)점3(%5,%6)%7%8%9', + CodeWizLite_OLED_printHG: 'OLED에 한글포함%1 출력, 줄바꿈%2%3', + + CodeWizLite_DIGITAL_OUTPUT_title: '기본 출력', + CodeWizLite_DIGITAL_OUTPUT_digitalWrite: 'PIN%1(으)로 %2내보내기%3', + CodeWizLite_DIGITAL_OUTPUT_pwmWrite: 'PIN%1(으)로 PWM %2내보내기(0~1023)%3', + + CodeWizLite_OzEye_title: '오즈아이', + CodeWizLite_OzEye_initOzEye: '오즈아이 시작설정%1', + CodeWizLite_OzEye_setModeOfOzEye: '오즈아이 %1알고리즘으로 설정%2', + CodeWizLite_OzEye_readOzEye: '오즈아이 데이터 요청시작%1', + CodeWizLite_OzEye_isLearnedOzEye: + '오즈아이 ID가%1인 데이터를 학습했는가?%2', + CodeWizLite_OzEye_getCountLearnedOzEye: '오즈아이가 감지한 학습데이터 수%1', + CodeWizLite_OzEye_isContainOzEye: + '오즈아이 ID:%1로 인식한 %2데이터가 있는가?%3', + CodeWizLite_OzEye_hasTypeOzEye: '오즈아이가 읽은 데이터 타입이%1인가?%2', + CodeWizLite_OzEye_getArrowInfoOzEye: + '오즈아이가 읽은 ID%1인 화살표정보%2%3', + CodeWizLite_OzEye_getBoxInfoOzEye2: '오즈아이가 읽은 ID%1인 사각형정보%2%3', + CodeWizLite_OzEye_getBoxInfoOzEye: + '오즈아이가 읽은 사각형정보%1(중심좌표가 중앙에 가장 가까운 것)%2', + // CodeWizLite_OzEye_writeTextOzEye: '오즈아이 (%1,%2)에 %3출력%4', + // CodeWizLite_OzEye_clearTextOzEye: '오즈아이 텍스트 지우기%1', + CodeWizLite_OzEye_setLightLevel: + '오즈아이 라이트 밝기를 %1 단계로 설정(1~7)%2', + CodeWizLite_OzEye_LightOff: '오즈아이 라이트 끄기%1', + + CodeWizLite_HuskyLens_title: '허스키렌즈', + CodeWizLite_HuskyLens_initHuskyLens: '허스키렌즈 시작설정%1', + CodeWizLite_HuskyLens_setModeOfHuskyLens: + '허스키렌즈 %1알고리즘으로 설정%2', + CodeWizLite_HuskyLens_readHuskyLens: '허스키렌즈 데이터 요청시작%1', + CodeWizLite_HuskyLens_isLearnedHuskyLens: + '허스키렌즈 ID가%1인 데이터를 학습했는가?%2', + CodeWizLite_HuskyLens_getCountLearnedHuskyLens: + '허스키렌즈가 감지한 학습데이터 수%1', + CodeWizLite_HuskyLens_isContainHuskyLens: + '허스키렌즈 ID:%1로 인식한 %2데이터가 있는가?%3', + CodeWizLite_HuskyLens_hasTypeHuskyLens: + '허스키렌즈가 읽은 데이터 타입이%1인가?%2', + CodeWizLite_HuskyLens_getArrowInfoHuskyLens: + '허스키렌즈가 읽은 ID%1인 화살표정보%2%3', + CodeWizLite_HuskyLens_getBoxInfoHuskyLens2: + '허스키렌즈가 읽은 ID%1인 사각형정보%2%3', + CodeWizLite_HuskyLens_getBoxInfoHuskyLens: + '허스키렌즈가 읽은 사각형정보%1(중심좌표가 중앙에 가장 가까운 것)%2', + CodeWizLite_HuskyLens_writeTextHuskyLens: '허스키렌즈 (%1,%2)에 %3출력%4', + CodeWizLite_HuskyLens_clearTextHuskyLens: '허스키렌즈 텍스트 지우기%1', + + CodeWizLite_Servo_title: '서보모터', + CodeWizLite_Servo_setAngle: '서보모터(%1) 각도를 %2(으)로 바꾸기%3', + CodeWizLite_Servo_menuSpeed: '무한회전 서보모터(%1) %2속도로 정하기%3', + CodeWizLite_Servo_customSpeed: + '무한회전 서보모터(%1) %2속도로 정하기(-100~100)%3', + + CodeWizLite_Dc_title: 'DC 모터', + CodeWizLite_Dc_setCarSpeed: + 'WizCar모터에 왼쪽%1, 오른쪽%2 내보내기(-1000~1000)%3', + CodeWizLite_Dc_setValue_Waterpump: '워터펌프(%1)에 %2내보내기(0~1023)%3', + + CodeWizLite_DotMatrix_title: '도트매트릭스', + CodeWizLite_DotMatrix_init: '도트매트릭스 %1개 DIN%2, CS%3, CLK%4로 설정%5', + CodeWizLite_DotMatrix_setBrightness: + '도트매트릭스 %1번 밝기를 %2(으)로 설정%3', + CodeWizLite_DotMatrix_printString: '도트매트릭스 %1번에 문자열%2 출력%3', + CodeWizLite_DotMatrix_setLine: '도트매트릭스 %1번의 %2%3 %4(으)로 만들기%5', + // CodeWizLite_DotMatrix_Show_Custom_Image: + // '도트매트릭스 %1번에 LED %2 켜기 %3', + CodeWizLite_DotMatrix_setDot: '도트매트릭스 %1번의 %2행%3열 %4%5', + CodeWizLite_DotMatrix_clear: '도트매트릭스 %1번 지우기%2', + CodeWizLite_DotMatrix_clearAll: '도트매트릭스 모두 지우기%1', + + CodeWizLite_ColorSensor_title: '컬러센서', + CodeWizLite_ColorSensor_isColor: 'MCON 컬러센서 감지된 색이 %1인가%2', + CodeWizLite_ColorSensor_getColorValue: 'MCON 컬러센서 %1값%2', + + CodeWizLite_DHT_title: '디지털 온습도', + CodeWizLite_DHT_init: '디지털 온습도 pin%1에 설정%2', + CodeWizLite_DHT_getValue: '디지털 온습도 %1값%2', + + CodeWizLite_Joystick_title: '조이스틱', + CodeWizLite_Joystick_setPin: + '조이스틱 설정하기(X축%1, Y축%2, 버튼%3, 범위%4)%5', + CodeWizLite_Joystick_readAxis: '조이스틱 %1의 값%2', + CodeWizLite_Joystick_readButton: '조이스틱 버튼 값%1', + + CodeWizLite_etcReadSensor_title: '기타 입력센서', + CodeWizLite_etcReadSensor_mconRead: 'MCON%1(pin%2)의 측정값%3', + CodeWizLite_etcReadSensor_digitalRead: '%1(pin%2)의 측정값%3', + CodeWizLite_etcReadSensor_InfraredThermometerRead: + '비접촉온도센서 %1에 %2로 읽기%3', + }, + + Helper: { + CodeWizLite_get_sensor: `주변의 소리값을 0~1023 사이 값으로 알려줍니다. + + ▼을 클릭하여 빛, 거리, 홀, 온도를 선택하여 + 주변의 밝기, 거리, 자성, 보드의 온도를 확인할 수 있습니다.`, + CodeWizLite_get_gyroSensor: `선택된 축의 기울기를 -90~90 사이 값으로 알려줍니다. + ▼을 눌러 X축, Y축, Z축을 선택할 수 있습니다.`, + CodeWizLite_isPushedButton: `왼쪽/오른쪽 버튼을 누르면 “참” 으로 판단합니다. + ▼을 눌러 왼쪽, 오른쪽을 선택할 수 있습니다.`, + CodeWizLite_touchPin: `🐻 모양의 터치센서를 손가락으로 터치하면 “참“으로 판단합니다. + ▼을 눌러 🔆,⭕, 🖐, 👊, ❌ 모양의 터치센서를 선택하면 해당 모양의 터치센서의 터치 여부도 확인할 수 있습니다.`, + + CodeWizLite_default_buzzer: `지정된 옥타브의 음을 지정된 음표로 스피커(부저)를 재생합니다.`, + + CodeWizLite_neopixel_init: `코드위즈의 네오 RGB LED 5개의 사용을 설정합니다. + ▼을 눌러 SCON에 연결된 네오픽셀의 개수와 사용을 설정할 수 있습니다.`, + CodeWizLite_neopixel_brightness: `밝기를 0~255 사이 값으로 지정합니다.`, + CodeWizLite_neopixel_setColor_one: `입력한 번호의 LED를 선택한 색으로 켭니다.`, + CodeWizLite_neopixel_setColor_one2: `입력한 번호의 LED를 빨강, 초록, 파랑에 입력된 값의 색으로 켭니다. + 각 값을 0~255 사이 값으로 지정합니다.`, + CodeWizLite_neopixel_off_one: `입력한 번호의 LED를 끕니다.`, + CodeWizLite_neopixel_setColor_all: `모든 LED를 선택한 색으로 켭니다.`, + CodeWizLite_neopixel_setColor_all2: `모든 LED를 빨강, 초록, 파랑에 입력된 값의 색으로 켭니다. + 각 값을 0~255 사이 값으로 지정합니다.`, + CodeWizLite_neopixel_off_all: `모든 LED를 끕니다.`, + CodeWizLite_neopixel_OnPixelRandomColor: `입력한 번호의 LED를 무작위 색으로 켭니다.`, + CodeWizLite_neopixel_fillRandom: `모든 LED를 무작위 색으로 채웁니다.`, + CodeWizLite_neopixel_rotate: `모든 LED를 지정한 방향으로 회전시킵니다. + 방향은 ▼을 눌러 설정합니다.`, + CodeWizLite_neopixel_shift: `모든 LED를 지정한 방향으로 밀어냅니다. + 빈자리는 기존 색으로 채워집니다. + 방향은 ▼을 눌러 설정합니다.`, + CodeWizLite_neopixel_gradationRGB: `지정범위의 LED를 선택한 색의 그라데이션으로 채웁니다. + 왼쪽색부터 오른쪽색까지 RGB색표현의 그라데이션으로 채워집니다. + 범위는 초기화한 LED범위를 벗어날 수 없으며 서로 다른 값이여야 합니다. + LED 번호가 작은 값은 왼쪽에 큰 값은 오른쪽에 위치해야합니다.`, + CodeWizLite_neopixel_gradationHSL: `지정범위의 LED를 선택한 색의 그라데이션으로 채웁니다. + 왼쪽색부터 오른쪽색까지 HSL색표현의 그라데이션으로 채워집니다. + 범위는 초기화한 LED범위를 벗어날 수 없으며 서로 다른 값이여야 합니다. + LED 번호가 작은 값은 왼쪽에 큰 값은 오른쪽에 위치해야합니다.`, + CodeWizLite_neopixel_wheeeeeeel: `녹색, 빨강, 파랑의 세 가지색을 기준으로 섞은 색을 순환시켜 켜주는 블록입니다. + 이 블록을 사용해서 흐르는 듯한 네오픽셀을 표시할 수 있습니다.`, + + CodeWizLite_OLED_clear: `OLED에 표시된 내용을 지웁니다.`, + CodeWizLite_OLED_mirror: `OLED에 표시할 내용의 출력 상태를 설정합니다. + OFF가 기본이며, ON을 선택하면 OLED 배경에 색이 채워지고 내용이 표시됩니다.`, + CodeWizLite_OLED_setSize: `글자 크기를 지정합니다. + 1~10 사이의 범위로 설정할 수 있습니다.`, + CodeWizLite_OLED_setPosition: `글자가 출력될 위치(x좌표, y좌표)를 지정합니다. + X는 0~127, Y는 0~63 사이의 범위로 설정할 수 있습니다.`, + CodeWizLite_OLED_println: `입력한 내용을 OLED에 출력합니다.`, + CodeWizLite_OLED_isCollision: `OLED에 출력된 내용의 줄바꿈을 설정합니다.`, + CodeWizLite_OLED_specialChar: `OLED에 기호를 출력합니다.`, + CodeWizLite_OLED_setFont: `글꼴과 글자 크기를 ▼ 을 눌러 설정합니다.`, + CodeWizLite_OLED_startScroll: `OLED에 입력된 내용을 지정한 화살표방향으로 이동시킵니다. 시작과 종료는 y좌표를 0~7 페이지로 나눈 것으로 각 페이지는 다음과 같은 y 좌표를 가집니다. + + 0 : y좌표 0~7 + 1 : y좌표 8~15 + 2 : y좌표 16~23 + 3 : y좌표 24~31 + 4 : y좌표 32~39 + 5 : y좌표 40~47 + 6 : y좌표 48~55 + 7 : y좌표 56~63`, + CodeWizLite_OLED_stopScroll: `이동을 멈춥니다.`, + CodeWizLite_OLED_drawPoint: `지정된 위치 (x좌표, y좌표)에 점을 찍습니다. + X는 0~127, Y는 0~63 사이의 범위로 설정할 수 있습니다.`, + CodeWizLite_OLED_drawLine1: `시작 위치 (x좌표, y좌표)에서 끝 위치 (x좌표, y좌표)까지 흰색 선을 그립니다.`, + CodeWizLite_OLED_drawLine2: `시작 위치 (x좌표, y좌표)에서 지정된 길이의 흰색 수직선을 그립니다.`, + CodeWizLite_OLED_drawLine3: `시작 위치 (x좌표, y좌표)에서 지정된 길이의 흰색 수평선을 그립니다.`, + CodeWizLite_OLED_drawRect: `시작 위치 (x좌표, y좌표)에서 지정된 가로, 세로 길이의 흰색 선 직사각형을 그립니다. + ▼을 눌러 ‘비움’ 대신 ‘채움‘을 선택하면 직사각형 내부가 채워집니다.`, + CodeWizLite_OLED_drawCircle: `중심(x좌표, y좌표)에서 지정된 반지름을 가지는 흰색 선 원을 그립니다. + ▼을 눌러 ‘비움’ 대신 ‘채움‘을 선택하면 원 내부가 채워집니다.`, + CodeWizLite_OLED_drawPoligon: `점1(x좌표, y좌표), 점2 (x좌표, y좌표), 점3 (x좌표, y좌표)을 연결하여 흰색 선 삼각형을 그립니다. + ▼을 눌러 ‘비움’ 대신 ‘채움‘을 선택하면 원 내부가 채워집니다.`, + CodeWizLite_OLED_printHG: `입력한 내용(한글포함)을 OLED에 출력합니다. + ▼을 눌러 ‘⭕’를 선택하면 아랫줄로 커서를 이동시키고 ‘❌‘를 선택하면 마지막 글자 오른쪽으로 커서를 이동시킵니다.`, + + CodeWizLite_DIGITAL_OUTPUT_digitalWrite: `지정된 핀(터치센서 또는 SCON)에 연결된 센서로 HIGH 또는 LOW 를 내보냅니다. + + <현재 활용 가능한 확장도구> + 진동모터`, + CodeWizLite_DIGITAL_OUTPUT_pwmWrite: `지정된 핀(터치센서 또는 SCON)에 연결된 센서로 입력된 값을 내보냅니다. + + <현재 활용 가능한 확장도구> + 프로펠러`, + + CodeWizLite_OzEye_initOzEye: `오즈아이 시작을 설정합니다.`, + CodeWizLite_OzEye_setModeOfOzEye: `오즈아이를 선택된 알고리즘으로 설정합니다. + + 1.선 인식 + 2.색 인식 + 3.태그 인식 + 4.이미지 인식 + 5.사물 인식 + 6.사물 추적 + 7.선 + 태그`, + CodeWizLite_OzEye_readOzEye: `오즈아이가 인식한 결과를 주기적으로 보내줍니다.`, + CodeWizLite_OzEye_isLearnedOzEye: `입력한 ID 번호 데이터를 학습했다면 ‘참’으로 판단하여 알려줍니다.`, + CodeWizLite_OzEye_isContainOzEye: `입력한 ID 번호의 사각형 데이터가 인식된다면 ‘참’으로 판단하여 알려줍니다. + ▼을 눌러 화살표를 선택하면 화살표 데이터가 인식될 때 ‘참’으로 판단하여 알려줍니다.`, + CodeWizLite_OzEye_getCountLearnedOzEye: `화면에 감지된 학습한 데이터 수를 알려줍니다.`, + CodeWizLite_OzEye_hasTypeOzEye: `읽어온 데이터 타입이 선택한 타입(사각형/화살표)과 같다면 ‘참’으로 판단하여 알려줍니다.`, + CodeWizLite_OzEye_getArrowInfoOzEye: `읽어온 화살표 데이터의 좌표 값을 알려줍니다. 좌표 값은 ‘시작 X좌표‘, ‘시작 Y좌표‘, ‘종료 X좌표‘, ‘종료 Y좌표‘ 중 하나를 선택합니다. + 대상이 없다면 -1을 반환합니다.`, + CodeWizLite_OzEye_getBoxInfoOzEye2: `읽어온 사각형 데이터의 정보를 알려줍니다. 정보는 ‘중심 X좌표‘, ‘중심 Y좌표’, ‘너비‘, ‘높이’ 중 하나를 선택합니다. + 대상이 없다면 -1을 반환합니다.`, + CodeWizLite_OzEye_getBoxInfoOzEye: `읽어온 사각형 데이터의 정보를 알려줍니다. 정보는 ‘ID’, ‘중심 X좌표‘, ‘중심 Y좌표’, ‘너비‘, ‘높이’ 중 하나를 선택합니다. + 대상이 없다면 -1을 반환합니다.`, + // CodeWizLite_OzEye_writeTextOzEye: `오즈아이 화면의 지정된 좌표에 입력된 데이터를 출력합니다.`, + // CodeWizLite_OzEye_clearTextOzEye: `오즈아이 화면에 출력되어 있는 데이터를 지웁니다.`, + CodeWizLite_OzEye_setLightLevel: + '오즈아이의 라이트 밝기를 1~7 단계로 설정합니다.', + CodeWizLite_OzEye_LightOff: '오즈아이 라이트를 끕니다.', + + CodeWizLite_HuskyLens_initHuskyLens: `허스키렌즈 시작을 설정합니다.`, + CodeWizLite_HuskyLens_setModeOfHuskyLens: `허스키렌즈를 선택된 알고리즘으로 설정합니다. + + 1.FACE_RECOGNITION + 2.OBJECT_TRACKING + 3.OBJECT_RECOGNITION + 4.LINE_TRACKING + 5.COLOR_RECOGNITION + 6.TAG_RECOGNITION + 7.OBJECT_CLASSIFICATION`, + CodeWizLite_HuskyLens_readHuskyLens: `허스키렌즈가 인식한 결과를 주기적으로 보내줍니다.`, + CodeWizLite_HuskyLens_isLearnedHuskyLens: `입력한 ID 번호 데이터를 학습했다면 ‘참’으로 판단하여 알려줍니다.`, + CodeWizLite_HuskyLens_isContainHuskyLens: `입력한 ID 번호의 사각형 데이터가 인식된다면 ‘참’으로 판단하여 알려줍니다. + ▼을 눌러 화살표를 선택하면 화살표 데이터가 인식될 때 ‘참’으로 판단하여 알려줍니다.`, + CodeWizLite_HuskyLens_getCountLearnedHuskyLens: `화면에 감지된 학습한 데이터 수를 알려줍니다.`, + CodeWizLite_HuskyLens_hasTypeHuskyLens: `읽어온 데이터 타입이 선택한 타입(사각형/화살표)과 같다면 ‘참’으로 판단하여 알려줍니다.`, + CodeWizLite_HuskyLens_getArrowInfoHuskyLens: `읽어온 화살표 데이터의 좌표 값을 알려줍니다. 좌표 값은 ‘시작 X좌표‘, ‘시작 Y좌표‘, ‘종료 X좌표‘, ‘종료 Y좌표‘ 중 하나를 선택합니다. + 대상이 없다면 -1을 반환합니다.`, + CodeWizLite_HuskyLens_getBoxInfoHuskyLens2: `읽어온 사각형 데이터의 정보를 알려줍니다. 정보는 ‘중심 X좌표‘, ‘중심 Y좌표’, ‘너비‘, ‘높이’ 중 하나를 선택합니다. + 대상이 없다면 -1을 반환합니다.`, + CodeWizLite_HuskyLens_getBoxInfoHuskyLens: `읽어온 사각형 데이터의 정보를 알려줍니다. 정보는 ‘ID’, ‘중심 X좌표‘, ‘중심 Y좌표’, ‘너비‘, ‘높이’ 중 하나를 선택합니다. + 대상이 없다면 -1을 반환합니다.`, + CodeWizLite_HuskyLens_writeTextHuskyLens: `허스키렌즈 화면의 지정된 좌표에 입력된 데이터를 출력합니다.`, + CodeWizLite_HuskyLens_clearTextHuskyLens: `허스키렌즈 화면에 출력되어 있는 데이터를 지웁니다.`, + + CodeWizLite_Servo_setAngle: `선택된 커넥터(MCON/SCON)에 연결된 180도 서보모터의 각도를 입력된 각도로 회전시킵니다.(0~180)`, + CodeWizLite_Servo_menuSpeed: `선택된 커넥터(MCON/SCON)에 무한회전 서보모터를 지정된 속도로 회전시킵니다. + ▼을 눌러 속도를 선택합니다.(빠른/보통/느림/멈춘)`, + CodeWizLite_Servo_customSpeed: `선택된 커넥터(MCON/SCON)에 무한회전 서보모터를 지정된 속도로 회전시킵니다. + + 속도 = 0 : 모터의 회전이 멈춥니다. + 속도 > 0 : 모터가 지정된 속도로 정방향 회전합니다. + 속도 < 0 : 모터가 지정된 속도로 역방향 회전합니다.`, + + CodeWizLite_Dc_setCarSpeed: `WizCar 모터에 입력한 숫자값으로 회전시킵니다. + 각 모터값은 -1000~-180(후진), 180~1000(전진) 사이값입니다. 바닥 상태에 따라 숫자값을 높여가면서 회전을 시켜보세요.`, + CodeWizLite_Dc_setValue_Waterpump: `선택된 워터펌프를 입력한 속도로 회전시킵니다. + ▼을 눌러 회전시킬 모터(MOTOR_L, MOROT_R)를 선택하고 속도는 0~1023 사이 값으로 직접 입력합니다.`, + + CodeWizLite_DotMatrix_init: `도트매트릭스가 연결된 핀을 설정합니다. + + 18, 19번 : SCON + 15, 27번 : 터치센서`, + CodeWizLite_DotMatrix_setBrightness: `입력된 값으로 도트매트릭스의 밝기를 설정합니다.(1~8)`, + CodeWizLite_DotMatrix_printString: `입력된 문자열을 한 글자씩 출력합니다.`, + + // CodeWizLite_DotMatrix_Show_Custom_Image: + // '블록에서 선택한 LED를 선택한 밝기로 켭니다. 한번에 모든 LED를 조작할 수 있습니다.', + + CodeWizLite_DotMatrix_setLine: `지정된 행/열에 위치한 8개 LED의 ON/OFF를 각각 지정해서 제어합니다. + + 1 : ON + 0 : OFF`, + CodeWizLite_DotMatrix_setDot: `입력된 행,열에 위치한 LED의 ON/OFF를 지정합니다. + + 켜기 : ON + 끄기 : OFF`, + CodeWizLite_DotMatrix_clear: `입력된 도트 매트릭스를 지웁니다.(끕니다.)`, + CodeWizLite_DotMatrix_clearAll: `연결된 모든 도트 매트릭스를 지웁니다.(끕니다.)`, + + CodeWizLite_ColorSensor_isColor: `MCON에 연결된 컬러센서에 인식된 색 값이 지정된 색이라면 ‘참’으로 판단하여 알려줍니다. + ▼을 빨강, 초록, 파랑, 검정, 흰색을 선택할 수 있습니다.`, + CodeWizLite_ColorSensor_getColorValue: `MCON에 연결된 컬러센서에 인식된 빨강의 색상 값을 0~255 사이값으로 알려줍니다. + ▼을 눌러 초록, 파랑을 선택할 수 있습니다.`, + + CodeWizLite_DHT_init: `지정한 핀으로 디지털 온습도를 설정합니다.`, + CodeWizLite_DHT_getValue: `앞서 설정한 디지털 온습도에서 선택한 값을 가져옵니다.`, + + CodeWizLite_Joystick_setPin: '지정한 핀으로 조이스틱을 설정합니다.', + CodeWizLite_Joystick_readAxis: + '설정된 조이스틱의 지정한 축의 레버값을 읽어옵니다.', + CodeWizLite_Joystick_readButton: + '설정된 조이스틱의 버튼이 눌렸는지 값을 읽어옵니다.', + + CodeWizLite_etcReadSensor_mconRead: `가변저항/워터센서/토양수분센서의 측정값 + 선택한 센서에 따라서 값이 적절히 매핑되어 반환됩니다.`, + CodeWizLite_etcReadSensor_digitalRead: `버튼/포토인터럽트의 측정값 + 해당핀의 digitalRead값을 가져옵니다. + 버튼의 경우 눌렸을 때 참을 반환하기 위해서 인버스를 취하고, + 포토인터럽트는 읽은 값 그대로 반환됩니다. + `, + CodeWizLite_etcReadSensor_InfraredThermometerRead: `선택된 커넥터(MCON/SCON)에 연결된 비접촉 온도 센서에 인식된 온도를 알려줍니다. + ▼을 눌러 온도 단위를 선택합니다.`, + }, + }, + }; + } + + getBlocks() { + return { + //region codeino 코드위즈 + CodeWizLite_sensor_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_sensor_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_sensor_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_sensor_title', + }, + class: 'CodeWizLite_default_sensor', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_get_sensor: { + // Block UI : %1센서 값 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + fontColor: '#fff', + params: [ + { + type: 'Dropdown', + options: [ + ['소리', 'SOUND'], + ['빛', 'LIGHT'], + ['거리', 'DIST'], + ['홀', 'HALL'], + ['온도', 'tempSensor'], + ], + value: 'SOUND', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + def: { + params: [null], + type: 'CodeWizLite_get_sensor', + }, + paramsKeyMap: { + SENSOR: 0, + }, + isNotFor: ['CodeWizLite'], + class: 'CodeWizLite_default_sensor', + func: function(sprite, script) { + var sensor = script.getField('SENSOR', script); + var hw_sensorData = Entry.CodeWizLite.sensorData; + return hw_sensorData[sensor] ?? 0; + }, + }, + CodeWizLite_get_gyroSensor: { + // Block UI : 자이로 센서 %1값 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + fontColor: '#fff', + params: [ + { + type: 'Dropdown', + options: [ + ['X', 'GYRO_X'], + ['Y', 'GYRO_Y'], + ['Z', 'GYRO_Z'], + ], + value: 'GYRO_X', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + def: { + params: [null], + type: 'CodeWizLite_get_gyroSensor', + }, + paramsKeyMap: { + GYRO_TYPE: 0, + }, + isNotFor: ['CodeWizLite'], + class: 'CodeWizLite_default_sensor', + func: function(sprite, script) { + var sensor = script.getField('GYRO_TYPE', script); + var hw_sensorData = Entry.CodeWizLite.sensorData; + return hw_sensorData[sensor] ?? 0; + }, + }, + CodeWizLite_isPushedButton: { + // Block UI : %1 스위치 버튼 값 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['왼쪽', 'switchButton_26'], + ['오른쪽', 'switchButton_4'], + ], + value: 'switchButton_26', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_isPushedButton', + }, + paramsKeyMap: { + SWITCH: 0, + }, + isNotFor: ['CodeWizLite'], + class: 'CodeWizLite_default_sensor', + func: function(sprite, script) { + var sensor = script.getField('SWITCH', script); + var hw_sensorData = Entry.CodeWizLite.sensorData; + return hw_sensorData[sensor] ?? false; + }, + }, + CodeWizLite_touchPin: { + // Block UI : "터치핀 %1 값", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + fontColor: '#fff', + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['🔆(13)', 'touchPin_13'], + ['⭕(14)', 'touchPin_14'], + ['🖐(15)', 'touchPin_15'], + ['👊(27)', 'touchPin_27'], + ['🐻(32)', 'touchPin_32'], + ['❌(33)', 'touchPin_33'], + ], + value: 'touchPin_32', + fontSize: 14, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_touchPin', + }, + paramsKeyMap: { + SWITCH: 0, + }, + isNotFor: ['CodeWizLite'], + class: 'CodeWizLite_default_sensor', + func: function(sprite, script) { + var sensor = script.getField('SWITCH', script); + var hw_sensorData = Entry.CodeWizLite.sensorData; + return hw_sensorData[sensor] ?? 0; + }, + }, + CodeWizLite_buzzer_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_buzzer_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_buzzer_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_buzzer_title', + }, + class: 'CodeWizLite_buzzer', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_default_buzzer: { + // Block UI : "스피커를 %1옥타브, %2음, %3분음표로 연주하기%4", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1', '1'], + ['2', '2'], + ['3', '3'], + ['4', '4'], + ['5', '5'], + ['6', '6'], + ['7', '7'], + ], + value: '4', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['도', '0'], + ['도#', '1'], + ['레', '2'], + ['미♭', '3'], + ['미', '4'], + ['파', '5'], + ['파#', '6'], + ['솔', '7'], + ['솔#', '8'], + ['라', '9'], + ['시♭', '10'], + ['시', '11'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['2', '2'], + ['4', '4'], + ['8', '8'], + ['16', '16'], + ['32', '32'], + ], + value: '4', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null], + type: 'CodeWizLite_default_buzzer', + }, + paramsKeyMap: { + OCTAVE: 0, + NOTE: 1, + BEAT: 2, + }, + class: 'CodeWizLite_buzzer', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let octave = Number.parseInt(script.getValue('OCTAVE', script)); + let note = Number.parseInt(script.getValue('NOTE', script)); + let beat = Number.parseInt(script.getValue('BEAT', script)); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 1, + params: [octave, note, beat], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + + await Entry.CodeWizLite.checkComplete(1234, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + CodeWizLite_neopixel_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_neopixel_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_neopixel_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_neopixel_title', + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_neopixel_init: { + // Block UI : "네오픽셀 %1에 %2개로 시작설정%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['코드위즈', '23'], + ['18', '18'], + ['19', '19'], + ], + value: '23', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + defaultType: 'number', + value: 5, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_neopixel_init', + }, + paramsKeyMap: { + PIN: 0, + COUNT: 1, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _pin = script.getNumberValue('PIN', script); + let _count = script.getNumberValue('COUNT', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 32, + params: [_pin, _count], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_brightness: { + // Block UI : "네오픽셀 밝기를 %1로 설정(0~255)%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + defaultType: 'number', + value: 22, + }, + + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'CodeWizLite_neopixel_brightness', + }, + paramsKeyMap: { + BRIGHTNESS: 0, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let value = script.getNumberValue('BRIGHTNESS', script); + value = Math.round(value); + if (value < 0) { + value = 0; + } else if (value > 255) { + value = 255; + } + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 2, + params: [value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_setColor_one: { + // Block UI : "네오픽셀 %1번 LED를 <색상표>%2(으)로 켜기%3", + + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Color', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', null, null], + type: 'CodeWizLite_neopixel_setColor_one', + }, + paramsKeyMap: { + NUM: 0, + COLOR: 1, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let num = script.getNumberValue('NUM', script) - 1; + let value = script.getStringField('COLOR', script); + + let colorValue = [ + parseInt(value.substr(1, 2), 16), + parseInt(value.substr(3, 2), 16), + parseInt(value.substr(5, 2), 16), + ]; + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 3, + params: [num, ...colorValue], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_setColor_one2: { + // Block UI : "네오픽셀 %1번 LED를 빨강%2초록%3파랑%4(으)로 켜기%5", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', '255', '255', '255', null], + type: 'CodeWizLite_neopixel_setColor_one2', + }, + paramsKeyMap: { + NUM: 0, + R: 1, + G: 2, + B: 3, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let num = script.getNumberValue('NUM', script) - 1; + let r = script.getNumberValue('R', script); + let g = script.getNumberValue('G', script); + let b = script.getNumberValue('B', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 3, + params: [num, r, g, b], + }, + }; + + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_off_one: { + // Block UI : "네오픽셀 %1번 LED 끄기%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', null], + type: 'CodeWizLite_neopixel_off_one', + }, + paramsKeyMap: { + NUM: 0, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let num = script.getNumberValue('NUM', script) - 1; + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 4, + params: [num], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_setColor_all: { + // Block UI : "네오픽셀 %1(으)로 모두 켜기%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Color', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_neopixel_setColor_all', + }, + paramsKeyMap: { + COLOR: 0, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let value = script.getStringField('COLOR', script); + + let colorValue = [ + parseInt(value.substr(1, 2), 16), + parseInt(value.substr(3, 2), 16), + parseInt(value.substr(5, 2), 16), + ]; + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 5, + params: [...colorValue], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_setColor_all2: { + // Block UI : "네오픽셀 빨강%1초록%2파랑%3(으)로 모두 켜기%4", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['255', '255', '255', null], + type: 'CodeWizLite_neopixel_setColor_all2', + }, + paramsKeyMap: { + R: 0, + G: 1, + B: 2, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let r = script.getNumberValue('R', script); + let g = script.getNumberValue('G', script); + let b = script.getNumberValue('B', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 5, + params: [r, g, b], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_off_all: { + // Block UI : "네오픽셀 모두 끄기%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_neopixel_off_all', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 6, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_OnPixelRandomColor: { + // 랜덤색상 켜기 - 단일 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', null], + type: 'CodeWizLite_neopixel_OnPixelRandomColor', + }, + paramsKeyMap: { + NUM: 0, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let num = script.getNumberValue('NUM', script) - 1; + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 3, + params: [ + num, + Math.floor(Math.random() * 256), + Math.floor(Math.random() * 256), + Math.floor(Math.random() * 256), + ], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_fillRandom: { + // 랜덤색상 켜기 - 전체 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_neopixel_fillRandom', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 43, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_rotate: { + // rotate 네오픽셀 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['역방향', '0'], + ['정방향', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_neopixel_rotate', + }, + paramsKeyMap: { + DIR: 0, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _dir = script.getNumberValue('DIR', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 44, + params: [_dir], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_shift: { + // shift 네오픽셀 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['역방향', '0'], + ['정방향', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_neopixel_shift', + }, + paramsKeyMap: { + DIR: 0, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _dir = script.getNumberValue('DIR', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 45, + params: [_dir], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_gradationRGB: { + // RGB그라데이션 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Color', + }, + { + type: 'Color', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', '8', '#ff0000', '#00ff00'], + type: 'CodeWizLite_neopixel_gradationRGB', + }, + paramsKeyMap: { + START: 0, + END: 1, + S_COLOR: 2, + E_COLOR: 3, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _start = script.getNumberValue('START', script) - 1; + let _end = script.getNumberValue('END', script) - 1; + let _sColor = script.getStringField('S_COLOR', script); + let _eColor = script.getStringField('E_COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 46, + params: [_start, _end, _sColor, _eColor], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_gradationHSL: { + // HSL그라데이션 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Color', + }, + { + type: 'Color', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', '8', '#ff0000', '#611ca1'], + type: 'CodeWizLite_neopixel_gradationHSL', + }, + paramsKeyMap: { + START: 0, + END: 1, + S_COLOR: 2, + E_COLOR: 3, + }, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _start = script.getNumberValue('START', script) - 1; + let _end = script.getNumberValue('END', script) - 1; + let _sColor = script.getStringField('S_COLOR', script); + let _eColor = script.getStringField('E_COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 47, + params: [_start, _end, _sColor, _eColor], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_neopixel_wheeeeeeel: { + // 휠 - 엔트리에선 느려서 활용도가 떨어질 것으로 예상해서 일단 주석 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_neopixel_wheeeeeeel', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_neopixel', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 49, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + // console.log(script.key); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + CodeWizLite_OLED_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_OLED_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_OLED_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_OLED_title', + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_OLED_clear: { + // Block UI : "OLED 지우기%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_OLED_clear', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 7, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_mirror: { + // Block UI : "OLED 반전모드%1 %2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['OFF', '0'], + ['ON', '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OLED_mirror', + }, + paramsKeyMap: { + SWITCH: 0, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _value = script.getNumberValue('SWITCH', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 8, + params: [_value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_setSize: { + // Block UI : "OLED 문자 크기를 %1(으)로 설정%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [3], + type: 'CodeWizLite_OLED_setSize', + }, + paramsKeyMap: { + SIZE: 0, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _value = script.getNumberValue('SIZE', script); + _value = Math.round(_value); + if (_value < 1) { + _value = 1; + } else if (_value > 10) { + _value = 10; + } + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 9, + params: [_value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_setPosition: { + // Block UI : "OLED 커서위치(%1,%2)(으)로 지정%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['0', '0'], + type: 'CodeWizLite_OLED_setPosition', + }, + paramsKeyMap: { + X: 0, + Y: 1, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _x = script.getNumberValue('X', script); + _x = Math.round(_x); + if (_x < 0) { + _x = 0; + } else if (_x > 255) { + _x = 255; + } + + let _y = script.getNumberValue('Y', script); + _y = Math.round(_y); + if (_y < 0) { + _y = 0; + } else if (_y > 255) { + _y = 255; + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 10, + params: [_x, _y], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_println: { + // Block UI : "OLED에 %1 출력%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['Hello, World!!'], + type: 'CodeWizLite_OLED_println', + }, + paramsKeyMap: { + TEXT: 0, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _value = script.getStringValue('TEXT'); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 11, + params: [_value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_isCollision: { + // Block UI : "OLED 문자겹침 모드%1%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['OFF', '0'], + ['ON', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OLED_isCollision', + }, + paramsKeyMap: { + SWITCH: 0, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _value = script.getNumberValue('SWITCH', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 12, + params: [_value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_specialChar: { + // Block UI : "OLED에 기호%1 출력하기%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['♥', '3'], + ['◆', '4'], + ['♣', '5'], + ['♠', '6'], + ['♬', '14'], + ['▲', '30'], + ['▼', '31'], + + ['😧', '1'], + ['😀', '2'], + ['♂', '11'], + ['♀', '12'], + ['↑', '24'], + ['↓', '25'], + ['→', '26'], + ['←', '27'], + ], + value: '14', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OLED_specialChar', + }, + paramsKeyMap: { + CHAR: 0, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _value = script.getNumberValue('CHAR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 13, + params: [_value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_setFont: { + // Block UI : "OLED 폰트%1를 크기%2(으)로 설정%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['Serif', '0'], + ['Sans', '1'], + ['Mono', '2'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['9', '0'], + ['12', '1'], + ['18', '2'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'CodeWizLite_OLED_setFont', + }, + paramsKeyMap: { + FONT: 0, + SIZE: 1, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _value = script.getNumberValue('FONT', script); + let _size = script.getNumberValue('SIZE', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 14, + params: [_value, _size], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_startScroll: { + // Block UI : "OLED 스크롤 시키기 옵션(%1, 범위%2~%3(0~7))%4", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['→', '0'], + ['←', '1'], + ['↗', '2'], + ['↖', '3'], + ], + value: '0', + fontSize: 14, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, '0', '0'], + type: 'CodeWizLite_OLED_startScroll', + }, + paramsKeyMap: { + DIRECTION: 0, + START: 1, + END: 2, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _value = Number.parseInt(script.getNumberValue('DIRECTION', script)); + let _st = Number.parseInt(script.getNumberValue('START', script)); + _st = Math.round(_st); + if (_st < 0) { + _x = 0; + } else if (_st > 7) { + _st = 7; + } + let _ed = script.getNumberValue('END', script); + _ed = Math.round(_ed); + if (_ed < 0) { + _ed = 0; + } else if (_ed > 7) { + _ed = 7; + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 15, + params: [_value, _st, _ed], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_stopScroll: { + // Block UI : "OLED 스크롤 멈추기%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_OLED_stopScroll', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 16, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_drawPoint: { + // Block UI : "OLED에 점찍기 옵션((%1,%2), %3)%4", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['검은색', '0'], + ['흰색', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [63, 31, null], + type: 'CodeWizLite_OLED_drawPoint', + }, + paramsKeyMap: { + X: 0, + Y: 1, + COLOR: 2, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _x = script.getNumberValue('X', script); + _x = Math.round(_x); + if (_x < 0) { + _x = 0; + } else if (_x > 128) { + _x = 128; + } + + let _y = script.getNumberValue('Y', script); + _y = Math.round(_y); + if (_y < 0) { + _y = 0; + } else if (_y > 64) { + _y = 64; + } + + let _color = script.getNumberValue('COLOR', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 17, + params: [_x, _y, _color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_drawLine1: { + // Block UI : "OLED에 선 그리기 옵션((%1,%2)~(%3,%4), %5)%6", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['검은색', '0'], + ['흰색', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['0', '0', '10', '0', null], + type: 'CodeWizLite_OLED_drawLine1', + }, + paramsKeyMap: { + SX: 0, + SY: 1, + EX: 2, + EY: 3, + COLOR: 4, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _sx = script.getNumberValue('SX', script); + _sx = Math.round(_sx); + if (_sx < 0) { + _sx = 0; + } else if (_sx > 128) { + _sx = 128; + } + let _sy = script.getNumberValue('SY', script); + _sy = Math.round(_sy); + if (_sy < 0) { + _sy = 0; + } else if (_sy > 64) { + _sy = 64; + } + let _ex = script.getNumberValue('EX', script); + _ex = Math.round(_ex); + if (_ex < 0) { + _ex = 0; + } else if (_ex > 128) { + _ex = 128; + } + let _ey = script.getNumberValue('EY', script); + _ey = Math.round(_ey); + if (_ey < 0) { + _ey = 0; + } else if (_ey > 64) { + _ey = 64; + } + let _color = script.getNumberValue('COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 18, + params: [_sx, _sy, _ex, _ey, _color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_drawLine2: { + // Block UI : "OLED에 수직 선 그리기 옵션((%1,%2), 길이%3, %4)%5", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['검은색', '0'], + ['흰색', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['0', '0', '10', null], + type: 'CodeWizLite_OLED_drawLine2', + }, + paramsKeyMap: { + SX: 0, + SY: 1, + LEN: 2, + COLOR: 3, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _sx = script.getNumberValue('SX', script); + _sx = Math.round(_sx); + if (_sx < 0) { + _sx = 0; + } else if (_sx > 128) { + _sx = 128; + } + let _sy = script.getNumberValue('SY', script); + _sy = Math.round(_sy); + if (_sy < 0) { + _sy = 0; + } else if (_sy > 64) { + _sy = 64; + } + let _len = script.getNumberValue('LEN', script); + _len = Math.round(_len); + if (_len < 0) { + _len = 0; + } else if (_len > 64) { + _len = 64; + } + let _color = script.getNumberValue('COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 19, + params: [_sx, _sy, _len, _color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_drawLine3: { + // Block UI : "OLED에 수평 선 그리기 옵션((%1,%2), 길이%3, %4)%5", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['검은색', '0'], + ['흰색', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['0', '0', '10', null], + type: 'CodeWizLite_OLED_drawLine3', + }, + paramsKeyMap: { + SX: 0, + SY: 1, + LEN: 2, + COLOR: 3, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _sx = script.getNumberValue('SX', script); + _sx = Math.round(_sx); + if (_sx < 0) { + _sx = 0; + } else if (_sx > 128) { + _sx = 128; + } + let _sy = script.getNumberValue('SY', script); + _sy = Math.round(_sy); + if (_sy < 0) { + _sy = 0; + } else if (_sy > 64) { + _sy = 64; + } + let _len = script.getNumberValue('LEN', script); + _len = Math.round(_len); + if (_len < 0) { + _len = 0; + } else if (_len > 128) { + _len = 128; + } + let _color = script.getNumberValue('COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 20, + params: [_sx, _sy, _len, _color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_drawRect: { + // Block UI : "OLED에 직사각형 그리기 옵션(좌상단점(%1,%2), 가로%3, 세로%4, %5, %6)%7", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['비움', '0'], + ['채움', '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['검은색', '0'], + ['흰색', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['0', '0', '10', '10', null, null], + type: 'CodeWizLite_OLED_drawRect', + }, + paramsKeyMap: { + SX: 0, + SY: 1, + WIDTH: 2, + HEIGHT: 3, + ISFILL: 4, + COLOR: 5, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _sx = script.getNumberValue('SX', script); + _sx = Math.round(_sx); + if (_sx < 0) { + _sx = 0; + } else if (_sx > 128) { + _sx = 128; + } + let _sy = script.getNumberValue('SY', script); + _sy = Math.round(_sy); + if (_sy < 0) { + _sy = 0; + } else if (_sy > 64) { + _sy = 64; + } + let _width = script.getNumberValue('WIDTH', script); + _width = Math.round(_width); + if (_width < 0) { + _width = 0; + } else if (_width > 128) { + _width = 128; + } + let _height = script.getNumberValue('HEIGHT', script); + _height = Math.round(_height); + if (_height < 0) { + _height = 0; + } else if (_height > 64) { + _height = 64; + } + let _isFill = script.getNumberValue('ISFILL', script); + let _color = script.getNumberValue('COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 21, + x: _sx, + y: _sy, + params: [_sx, _sy, _width, _height, _isFill, _color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_drawCircle: { + // Block UI : "OLED에 원 그리기 옵션(중심(%1,%2) 반지름%3, %4, %5)%6", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['비움', '0'], + ['채움', '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['검은색', '0'], + ['흰색', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['30', '30', '10', null, null], + type: 'CodeWizLite_OLED_drawCircle', + }, + paramsKeyMap: { + RX: 0, + RY: 1, + RAD: 2, + ISFILL: 3, + COLOR: 4, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _rx = script.getNumberValue('RX', script); + _rx = Math.round(_rx); + if (_rx < 0) { + _rx = 0; + } else if (_rx > 128) { + _rx = 128; + } + let _ry = script.getNumberValue('RY', script); + _ry = Math.round(_ry); + if (_ry < 0) { + _ry = 0; + } else if (_ry > 64) { + _ry = 64; + } + let _rad = script.getNumberValue('RAD', script); + _rad = Math.round(_rad); + if (_rad < 0) { + _rad = 0; + } else if (_rad > 255) { + _rad = 255; + } + let _isFill = script.getNumberValue('ISFILL', script); + let _color = script.getNumberValue('COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 22, + params: [_rx, _ry, _rad, _isFill, _color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_drawPoligon: { + // Block UI : "OLED에 삼각형 그리기 옵션((%1,%2), (%3,%4), (%5,%6), %7, %8)%9", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['비움', '0'], + ['채움', '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['검은색', '0'], + ['흰색', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['0', '9', '6', '9', '3', '0', null, null], + type: 'CodeWizLite_OLED_drawPoligon', + }, + paramsKeyMap: { + X1: 0, + Y1: 1, + X2: 2, + Y2: 3, + X3: 4, + Y3: 5, + ISFILL: 6, + COLOR: 7, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _x1 = script.getNumberValue('X1', script); + _x1 = Math.round(_x1); + if (_x1 < 0) { + _x1 = 0; + } else if (_x1 > 128) { + _x1 = 128; + } + let _y1 = script.getNumberValue('Y1', script); + _y1 = Math.round(_y1); + if (_y1 < 0) { + _y1 = 0; + } else if (_y1 > 64) { + _y1 = 64; + } + let _x2 = script.getNumberValue('X2', script); + _x2 = Math.round(_x2); + if (_x2 < 0) { + _x2 = 0; + } else if (_x2 > 128) { + _x2 = 128; + } + let _y2 = script.getNumberValue('Y2', script); + _y2 = Math.round(_y2); + if (_y2 < 0) { + _y2 = 0; + } else if (_y2 > 64) { + _y2 = 64; + } + let _x3 = script.getNumberValue('X3', script); + _x3 = Math.round(_x3); + if (_x3 < 0) { + _x3 = 0; + } else if (_x3 > 128) { + _x3 = 128; + } + let _y3 = script.getNumberValue('Y3', script); + _y3 = Math.round(_y3); + if (_y3 < 0) { + _y3 = 0; + } else if (_y3 > 64) { + _y3 = 64; + } + let _isFill = script.getNumberValue('ISFILL', script); + let _color = script.getNumberValue('COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 23, + params: [_x1, _y1, _x2, _y2, _x3, _y3, _isFill, _color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OLED_printHG: { + // OLED 한글 출력 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['❌', '0'], + ['⭕', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['코드위즈 Magic!!', null], + type: 'CodeWizLite_OLED_printHG', + }, + paramsKeyMap: { + TEXT: 0, + isLB: 1, + }, + class: 'CodeWizLite_OLED', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _value = script.getStringValue('TEXT'); + let _isLB = script.getNumberValue('isLB', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 42, + params: [_value, _isLB], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_DIGITAL_OUTPUT_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX( + Lang.template.CodeWizLite_DIGITAL_OUTPUT_title + ), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_DIGITAL_OUTPUT_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_DIGITAL_OUTPUT_title', + }, + class: 'CodeWizLite_DIGITAL_OUTPUT', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_DIGITAL_OUTPUT_digitalWrite: { + // Block UI : "터치센서 디지털 %1(으)로 %2내보내기%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['13', '13'], + ['14', '14'], + ['15', '15'], + ['27', '27'], + ['32', '32'], + ['33', '33'], + ['18', '18'], + ['19', '19'], + ], + value: '13', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['LOW', '0'], + ['HIGH', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'CodeWizLite_DIGITAL_OUTPUT_digitalWrite', + }, + paramsKeyMap: { + PIN: 0, + VALUE: 1, + }, + class: 'CodeWizLite_DIGITAL_OUTPUT', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _pin = script.getNumberValue('PIN', script); + let _val = script.getNumberValue('VALUE', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 25, + params: [_pin, _val], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_DIGITAL_OUTPUT_pwmWrite: { + // Block UI : "터치센서 PWM %1(으)로 %2내보내기(0~1023)%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['13', '13'], + ['14', '14'], + ['15', '15'], + ['27', '27'], + ['32', '32'], + ['33', '33'], + ['18', '18'], + ['19', '19'], + ], + value: '13', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, '0'], + type: 'CodeWizLite_DIGITAL_OUTPUT_pwmWrite', + }, + paramsKeyMap: { + PIN: 0, + VALUE: 1, + }, + class: 'CodeWizLite_DIGITAL_OUTPUT', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _pin = script.getNumberValue('PIN', script); + let _val = script.getNumberValue('VALUE', script); + _val = Math.round(_val); + if (_val < 0) { + _val = 0; + } else if (_val > 1023) { + _val = 1023; + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 26, + params: [_pin, _val], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + /////////오즈아이 시작////////////////////////////////////////////////////////////////////////////////////////////// + + CodeWizLite_OzEye_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_OzEye_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_OzEye_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_OzEye_title', + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + events: {}, + }, + + CodeWizLite_OzEye_initOzEye: { + // Block UI : '오즈아이 시작설정%1', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OzEye_initOzEye', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 52, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + CodeWizLite_OzEye_setModeOfOzEye: { + // Block UI : '오즈아이 %1알고리즘으로 설정%2' + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1.선 인식', '3'], + ['2.색 인식', '4'], + ['3.태그 인식', '5'], + ['4.이미지 인식', '6'], + ['5.사물 인식', '2'], + ['6.사물 추적', '1'], + ['7.선 + 태그', '7'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OzEye_setModeOfOzEye', + }, + paramsKeyMap: { + MODE: 0, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let mode = script.getNumberValue('MODE', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 53, + params: [mode], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OzEye_readOzEye: { + // Block UI : "오즈아이 데이터 요청시작%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_OzEye_readOzEye', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 54, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OzEye_isLearnedOzEye: { + // Block UI : "오즈아이 ID가%1인 데이터를 학습했는가?%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null], + type: 'CodeWizLite_OzEye_isLearnedOzEye', + }, + paramsKeyMap: { + ID: 0, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let learnId = script.getNumberValue('ID', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 15, + params: [learnId], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? false; + //delete Entry.CodeWizLite.sensorData[id]; + + return retVal; + }, + }, + CodeWizLite_OzEye_isContainOzEye: { + // Block UI : "오즈아이 ID:%1로 인식한 %2데이터가 있는가?%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['사각형', '42'], + ['화살표', '43'], + ], + value: '42', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null, null], + type: 'CodeWizLite_OzEye_isContainOzEye', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _learnId = script.getNumberValue('ID', script); + let _type = script.getNumberValue('TYPE', script); + // console.log(this.sensorData); + // console.log(Entry.CodeWizLite.sensorData.HUSKY_READ); + const huskyData = Entry.CodeWizLite.sensorData.HUSKY_READ; + if (!huskyData._list || huskyData._list.length === 0) { + return false; + } + if (huskyData?._type !== _type) { + return false; + } + let _list = Entry.CodeWizLite.sensorData.HUSKY_READ._list; + for (let i = 0; i < _list.length; ++i) { + if (_list[i][0] === _learnId) { + return true; + } + } + return false; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + // let _learnId = script.getNumberValue('ID', script); + // let _type = script.getNumberValue('TYPE', script); + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 2, + // params: [_learnId, _type], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? false; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal; + // }, + }, + CodeWizLite_OzEye_getCountLearnedOzEye: { + // Block UI : "오즈아이가 감지한 학습데이터 수%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OzEye_getCountLearnedOzEye', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + return Entry.CodeWizLite.sensorData.HUSKY_READ?._count ?? 0; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 3, + // params: [], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? 0; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal; + // }, + }, + CodeWizLite_OzEye_hasTypeOzEye: { + // Block UI : "오즈아이가 읽은 데이터 타입이%1인가?%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['사각형', '42'], + ['화살표', '43'], + ], + value: '42', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OzEye_hasTypeOzEye', + }, + paramsKeyMap: { + TYPE: 0, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _type = script.getNumberValue('TYPE', script); + return Entry.CodeWizLite.sensorData.HUSKY_READ?._type === _type; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + // let _type = script.getNumberValue('TYPE', script); + + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 4, + // params: [_type], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? false; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal + // }, + }, + CodeWizLite_OzEye_getArrowInfoOzEye: { + // Block UI : "오즈아이가 읽은 ID%1인 화살표정보%2%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['시작 X좌표', '1'], + ['시작 Y좌표', '2'], + ['종료 X좌표', '3'], + ['종료 Y좌표', '4'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null], + type: 'CodeWizLite_OzEye_getArrowInfoOzEye', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _id = script.getNumberValue('ID', script); + let _arrowType = script.getNumberValue('TYPE', script); + const huskyData = Entry.CodeWizLite.sensorData.HUSKY_READ; + if (!huskyData._list || huskyData._list.length === 0) { + return -1; + } + if (huskyData?._type !== 43) { + return -1; + } + for (let i = 0; i < huskyData._list.length; ++i) { + if (huskyData._list[i][0] === _id) { + return huskyData._list[i][_arrowType]; + } + } + return -1; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + // let _arrowType = script.getNumberValue('TYPE', script); + + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 5, + // params: [_arrowType], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? 0; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal + // }, + }, + CodeWizLite_OzEye_getBoxInfoOzEye2: { + // Block UI : "오즈아이가 읽은 ID%1인 사각형정보%2%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['중심 X좌표', '1'], + ['중심 Y좌표', '2'], + ['너비', '3'], + ['높이', '4'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null], + type: 'CodeWizLite_OzEye_getBoxInfoOzEye2', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _id = script.getNumberValue('ID', script); + let _boxType = script.getNumberValue('TYPE', script); + const huskyData = Entry.CodeWizLite.sensorData.HUSKY_READ; + if (!huskyData._list || huskyData._list.length === 0) { + return -1; + } + if (huskyData?._type !== 42) { + return -1; + } + for (let i = 0; i < huskyData._list.length; ++i) { + if (huskyData._list[i][0] === _id) { + return huskyData._list[i][_boxType]; + } + } + return -1; + }, + }, + CodeWizLite_OzEye_getBoxInfoOzEye: { + // Block UI : "오즈아이가 읽은 사각형정보%1(중심좌표가 중앙에 가장 가까운 것)%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['ID', '0'], + ['중심 X좌표', '1'], + ['중심 Y좌표', '2'], + ['너비', '3'], + ['높이', '4'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OzEye_getBoxInfoOzEye', + }, + paramsKeyMap: { + TYPE: 0, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _boxType = script.getNumberValue('TYPE', script); + const huskyData = Entry.CodeWizLite.sensorData.HUSKY_READ; + if (!huskyData._list || huskyData._list.length === 0) { + return -1; + } + if (huskyData?._type !== 42 || huskyData?._count === 0) { + return -1; + } + let curIdx = 0; + let dist = Entry.CodeWizLite.HUSKY.getDist( + huskyData._list[0][0], + huskyData._list[0][1] + ); + let curDist; + for (let i = 1; i < huskyData._count; ++i) { + curDist = Entry.CodeWizLite.HUSKY.getDist( + huskyData._list[i][0], + huskyData._list[i][1] + ); + if (dist > curDist) { + dist = curDist; + curIdx = i; + } + } + return huskyData._list[curIdx][_boxType]; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + // let _boxType = script.getNumberValue('TYPE', script); + + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 6, + // params: [_boxType], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? 0; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal + // }, + }, + + //오즈아이에 텍스트 출력하기 기능 이후 적용 + /* + CodeWizLite_OzEye_writeTextOzEye: { + // Block UI : "오즈아이 x:%1 y:%2에 %3출력%4", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [0, 0, 'CodeWizLite'], + type: 'CodeWizLite_OzEye_writeTextOzEye', + }, + paramsKeyMap: { + X: 0, + Y: 1, + TEXT: 2, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _x = script.getNumberValue('X', script); + let _y = script.getNumberValue('Y', script); + let _text = script.getStringValue('TEXT'); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 55, + params: [_x, _y, _text], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_OzEye_clearTextOzEye: { + // Block UI : "오즈아이 텍스트 지우기%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_OzEye_clearTextOzEye', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 56, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + */ + + CodeWizLite_OzEye_setLightLevel: { + // Block UI : '오즈아이 라이트 밝기를 %1 단계로 설정(1~7)%2', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1', '1'], + ['2', '2'], + ['3', '3'], + ['4', '4'], + ['5', '5'], + ['6', '6'], + ['7', '7'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OzEye_setLightLevel', + }, + paramsKeyMap: { + Level: 0, + }, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let Level = script.getNumberValue('Level', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 57, + params: [Level], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + CodeWizLite_OzEye_LightOff: { + // Block UI : '오즈아이 라이트 끄기%1', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_OzEye_LightOff', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_OzEye', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 58, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + //////////오즈아이 끝///////////////////////////////////////////////////////////////////////////////////////////// + + CodeWizLite_HuskyLens_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_HuskyLens_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_HuskyLens_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_HuskyLens_title', + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + events: {}, + }, + + CodeWizLite_HuskyLens_initHuskyLens: { + // Block UI : '허스키렌즈 시작설정%1', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_HuskyLens_initHuskyLens', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 27, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_HuskyLens_setModeOfHuskyLens: { + // Block UI : '허스키렌즈 %1알고리즘으로 설정%2' + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['1.FACE_RECOGNITION', '0'], + ['2.OBJECT_TRACKING', '1'], + ['3.OBJECT_RECOGNITION', '2'], + ['4.LINE_TRACKING', '3'], + ['5.COLOR_RECOGNITION', '4'], + ['6.TAG_RECOGNITION', '5'], + ['7.OBJECT_CLASSIFICATION', '6'], + ], + value: '2', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_HuskyLens_setModeOfHuskyLens', + }, + paramsKeyMap: { + MODE: 0, + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let mode = script.getNumberValue('MODE', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 28, + params: [mode], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_HuskyLens_readHuskyLens: { + // Block UI : "허스키렌즈 데이터 요청시작%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_HuskyLens_readHuskyLens', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 29, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_HuskyLens_isLearnedHuskyLens: { + // Block UI : "허스키렌즈 ID가%1인 데이터를 학습했는가?%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null], + type: 'CodeWizLite_HuskyLens_isLearnedHuskyLens', + }, + paramsKeyMap: { + ID: 0, + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let learnId = script.getNumberValue('ID', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 1, + params: [learnId], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? false; + //delete Entry.CodeWizLite.sensorData[id]; + + return retVal; + }, + }, + CodeWizLite_HuskyLens_isContainHuskyLens: { + // Block UI : "허스키렌즈 ID:%1로 인식한 %2데이터가 있는가?%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['사각형', '42'], + ['화살표', '43'], + ], + value: '42', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null, null], + type: 'CodeWizLite_HuskyLens_isContainHuskyLens', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _learnId = script.getNumberValue('ID', script); + let _type = script.getNumberValue('TYPE', script); + // console.log(this.sensorData); + // console.log(Entry.CodeWizLite.sensorData.HUSKY_READ); + const huskyData = Entry.CodeWizLite.sensorData.HUSKY_READ; + if (!huskyData._list || huskyData._list.length === 0) { + return false; + } + if (huskyData?._type !== _type) { + return false; + } + let _list = Entry.CodeWizLite.sensorData.HUSKY_READ._list; + for (let i = 0; i < _list.length; ++i) { + if (_list[i][0] === _learnId) { + return true; + } + } + return false; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + // let _learnId = script.getNumberValue('ID', script); + // let _type = script.getNumberValue('TYPE', script); + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 2, + // params: [_learnId, _type], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? false; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal; + // }, + }, + CodeWizLite_HuskyLens_getCountLearnedHuskyLens: { + // Block UI : "허스키렌즈가 감지한 학습데이터 수%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_HuskyLens_getCountLearnedHuskyLens', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + return Entry.CodeWizLite.sensorData.HUSKY_READ?._count ?? 0; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 3, + // params: [], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? 0; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal; + // }, + }, + CodeWizLite_HuskyLens_hasTypeHuskyLens: { + // Block UI : "허스키렌즈가 읽은 데이터 타입이%1인가?%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['사각형', '42'], + ['화살표', '43'], + ], + value: '42', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_HuskyLens_hasTypeHuskyLens', + }, + paramsKeyMap: { + TYPE: 0, + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _type = script.getNumberValue('TYPE', script); + return Entry.CodeWizLite.sensorData.HUSKY_READ?._type === _type; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + // let _type = script.getNumberValue('TYPE', script); + + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 4, + // params: [_type], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? false; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal + // }, + }, + CodeWizLite_HuskyLens_getArrowInfoHuskyLens: { + // Block UI : "허스키렌즈가 읽은 ID%1인 화살표정보%2%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['시작 X좌표', '1'], + ['시작 Y좌표', '2'], + ['종료 X좌표', '3'], + ['종료 Y좌표', '4'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null], + type: 'CodeWizLite_HuskyLens_getArrowInfoHuskyLens', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _id = script.getNumberValue('ID', script); + let _arrowType = script.getNumberValue('TYPE', script); + const huskyData = Entry.CodeWizLite.sensorData.HUSKY_READ; + if (!huskyData._list || huskyData._list.length === 0) { + return -1; + } + if (huskyData?._type !== 43) { + return -1; + } + for (let i = 0; i < huskyData._list.length; ++i) { + if (huskyData._list[i][0] === _id) { + return huskyData._list[i][_arrowType]; + } + } + return -1; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + // let _arrowType = script.getNumberValue('TYPE', script); + + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 5, + // params: [_arrowType], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? 0; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal + // }, + }, + CodeWizLite_HuskyLens_getBoxInfoHuskyLens2: { + // Block UI : "허스키렌즈가 읽은 ID%1인 사각형정보%2%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['중심 X좌표', '1'], + ['중심 Y좌표', '2'], + ['너비', '3'], + ['높이', '4'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [1, null], + type: 'CodeWizLite_HuskyLens_getBoxInfoHuskyLens2', + }, + paramsKeyMap: { + ID: 0, + TYPE: 1, + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _id = script.getNumberValue('ID', script); + let _boxType = script.getNumberValue('TYPE', script); + const huskyData = Entry.CodeWizLite.sensorData.HUSKY_READ; + if (!huskyData._list || huskyData._list.length === 0) { + return -1; + } + if (huskyData?._type !== 42) { + return -1; + } + for (let i = 0; i < huskyData._list.length; ++i) { + if (huskyData._list[i][0] === _id) { + return huskyData._list[i][_boxType]; + } + } + return -1; + }, + }, + CodeWizLite_HuskyLens_getBoxInfoHuskyLens: { + // Block UI : "허스키렌즈가 읽은 사각형정보%1(중심좌표가 중앙에 가장 가까운 것)%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['ID', '0'], + ['중심 X좌표', '1'], + ['중심 Y좌표', '2'], + ['너비', '3'], + ['높이', '4'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_HuskyLens_getBoxInfoHuskyLens', + }, + paramsKeyMap: { + TYPE: 0, + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + func(sprite, script) { + let _boxType = script.getNumberValue('TYPE', script); + const huskyData = Entry.CodeWizLite.sensorData.HUSKY_READ; + if (!huskyData._list || huskyData._list.length === 0) { + return -1; + } + if (huskyData?._type !== 42 || huskyData?._count === 0) { + return -1; + } + let curIdx = 0; + let dist = Entry.CodeWizLite.HUSKY.getDist( + huskyData._list[0][0], + huskyData._list[0][1] + ); + let curDist; + for (let i = 1; i < huskyData._count; ++i) { + curDist = Entry.CodeWizLite.HUSKY.getDist( + huskyData._list[i][0], + huskyData._list[i][1] + ); + if (dist > curDist) { + dist = curDist; + curIdx = i; + } + } + return huskyData._list[curIdx][_boxType]; + }, + // async func(sprite, script) { + // if (Entry.CodeWizLite.intervalId) { + // await Entry.CodeWizLite.preWait(); + // } + // let _boxType = script.getNumberValue('TYPE', script); + + // const order = { + // type: Entry.CodeWizLite.sensorTypes.READ, + // value: { + // opcode: 6, + // params: [_boxType], + // }, + // }; + // const id = Entry.CodeWizLite.sendOrder(order); + // await Entry.CodeWizLite.checkComplete(1000, id); + + // let retVal= Entry.CodeWizLite.sensorData[id]?.value ?? 0; + // //delete Entry.CodeWizLite.sensorData[id]; + // return retVal + // }, + }, + CodeWizLite_HuskyLens_writeTextHuskyLens: { + // Block UI : "허스키렌즈 x:%1 y:%2에 %3출력%4", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [0, 0, 'CodeWizLite'], + type: 'CodeWizLite_HuskyLens_writeTextHuskyLens', + }, + paramsKeyMap: { + X: 0, + Y: 1, + TEXT: 2, + }, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _x = script.getNumberValue('X', script); + let _y = script.getNumberValue('Y', script); + let _text = script.getStringValue('TEXT'); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 30, + params: [_x, _y, _text], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_HuskyLens_clearTextHuskyLens: { + // Block UI : "허스키렌즈 텍스트 지우기%1", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_HuskyLens_clearTextHuskyLens', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_HuskyLens', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 31, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + CodeWizLite_Servo_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_Servo_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_Servo_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_Servo_title', + }, + class: 'CodeWizLite_Servo', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_Servo_setAngle: { + // Block UI : "서보모터(%1) 각도를 %2로 바꾸기%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['SCON', '18.0'], + ['MCON-18', '18.1'], + ['MCON-19', '19'], + ['MCON-15', '15'], + ['MCON-27', '27'], + ], + value: '18.0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, '0'], + type: 'CodeWizLite_Servo_setAngle', + }, + paramsKeyMap: { + PIN: 0, + VALUE: 1, + }, + class: 'CodeWizLite_Servo', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _pin = Number.parseInt(script.getNumberValue('PIN', script)); + let _value = Number.parseInt(script.getNumberValue('VALUE', script)); + _value = Math.round(_value); + if (_value < 0) { + _value = 0; + } else if (_value > 180) { + _value = 180; + } + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 33, + params: [_pin, _value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_Servo_menuSpeed: { + // Block UI : "무한회전 서보모터(%1) %2속도로 정하기%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['SCON', '18.0'], + ['MCON-18', '18.1'], + ['MCON-19', '19'], + ['MCON-15', '15'], + ['MCON-27', '27'], + ], + value: '18.0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['빠른', '21'], + ['보통', '39'], + ['느린', '58'], + ['멈춘', '76'], + ], + value: '21', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null], + type: 'CodeWizLite_Servo_menuSpeed', + }, + paramsKeyMap: { + PIN: 0, + VALUE: 1, + }, + class: 'CodeWizLite_Servo', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _pin = Number.parseInt(script.getNumberValue('PIN', script)); + let _value = script.getNumberValue('VALUE', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 34, + params: [_pin, _value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_Servo_customSpeed: { + // Block UI : "무한회전 서보모터(%1) %2속도로 정하기(-100~100)%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['SCON', '18.0'], + ['MCON-18', '18.1'], + ['MCON-19', '19'], + ['MCON-15', '15'], + ['MCON-27', '27'], + ], + value: '18.0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, '100'], + type: 'CodeWizLite_Servo_customSpeed', + }, + paramsKeyMap: { + PIN: 0, + VALUE: 1, + }, + class: 'CodeWizLite_Servo', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _pin = Number.parseInt(script.getNumberValue('PIN', script)); + let _value = Number.parseInt(script.getNumberValue('VALUE', script)); + if (_value < -100) { + _value = -100; + } else if (_value > 100) { + _value = 100; + } + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 35, + params: [_pin, _value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + CodeWizLite_Dc_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_Dc_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_Dc_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_Dc_title', + }, + class: 'CodeWizLite_Dc', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_Dc_setCarSpeed: { + // Block UI : 'WizCar 모터에 %1,%2내보내기(-1000~1000)%3', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['600', '600'], + type: 'CodeWizLite_Dc_setCarSpeed', + }, + paramsKeyMap: { + L_VALUE: 0, + R_VALUE: 1, + }, + class: 'CodeWizLite_Dc', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _lValue = Number.parseInt(script.getNumberValue('L_VALUE', script)); + let _rValue = Number.parseInt(script.getNumberValue('R_VALUE', script)); + _lValue = Math.min(Math.max(-1000, _lValue), 1000); + _rValue = Math.min(Math.max(-1000, _rValue), 1000); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 51, + params: [_lValue, _rValue], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_Dc_setValue_Waterpump: { + // 워터펌프 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['MOTOR_L', '0'], + ['MOTOR_R', '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, '1023'], + type: 'CodeWizLite_Dc_setValue_Waterpump', + }, + paramsKeyMap: { + PIN: 0, + VALUE: 1, + }, + class: 'CodeWizLite_Dc', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _pin = script.getNumberValue('PIN', script); + let _value = Number.parseInt(script.getNumberValue('VALUE', script)); + if (_value < 0) { + _value = 0; + } else if (_value > 1023) { + _value = 1023; + } + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 36, + params: [_pin, 1, _value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_DotMatrix_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_DotMatrix_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_DotMatrix_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_DotMatrix_title', + }, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_DotMatrix_init: { + // Block UI : '도트매트릭스 %1개 DIN%2, CS%3, CLK%4에 시작설정%5', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['18', '18'], + ['19', '19'], + ['15', '15'], + ['27', '27'], + ], + value: '18', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['18', '18'], + ['19', '19'], + ['15', '15'], + ['27', '27'], + ], + value: '19', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['18', '18'], + ['19', '19'], + ['15', '15'], + ['27', '27'], + ], + value: '15', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', null, null, null], + type: 'CodeWizLite_DotMatrix_init', + }, + paramsKeyMap: { + COUNT: 0, + PIN1: 1, + PIN2: 2, + PIN3: 3, + }, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _count = Number.parseInt(script.getNumberValue('COUNT', script)); + if (_count <= 0) { + return; + } else if (_count > 8) { + _count = 8; + } + let _pins = [ + script.getNumberValue('PIN1', script), + script.getNumberValue('PIN2', script), + script.getNumberValue('PIN3', script), + ]; + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 24, + params: [_count, ..._pins], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_DotMatrix_setBrightness: { + // Block UI : '도트매트릭스 %1번 밝기를 %2로 설정%3', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', '8'], + type: 'CodeWizLite_DotMatrix_setBrightness', + }, + paramsKeyMap: { + NUM: 0, + BRIGHTNESS: 1, + }, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _num = Number.parseInt(script.getNumberValue('NUM', script)); + if (_num < 1) { + num = 1; + } else if (_num > 8) { + _num = 8; + } + let _brightness = Number.parseInt( + script.getNumberValue('BRIGHTNESS', script) + ); + if (_brightness < 1) { + _brightness = 1; + } else if (_brightness > 15) { + _brightness = 15; + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 37, + params: [_num, _brightness], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_DotMatrix_printString: { + // Block UI : '도트매트릭스 %1번에 문자열%2 출력%3', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', 'HELLO'], + type: 'CodeWizLite_DotMatrix_printString', + }, + paramsKeyMap: { + NUM: 0, + TEXT: 1, + }, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _num = Number.parseInt(script.getNumberValue('NUM', script)); + if (_num < 1) { + num = 1; + } else if (_num > 8) { + _num = 8; + } + let _value = script.getStringValue('TEXT'); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 38, + params: [_num, _value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_DotMatrix_setLine: { + // Block UI : '도트매트릭스 %1번에 %2번%3 %4로 만들기%5', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['행', '1'], + ['열', '0'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', '2', null, '11111111'], + type: 'CodeWizLite_DotMatrix_setLine', + }, + paramsKeyMap: { + NUM: 0, + NUM_LINE: 1, + IS_ROW: 2, + VALUE: 3, + }, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _num = Number.parseInt(script.getNumberValue('NUM', script)); + if (_num < 1) { + num = 1; + } else if (_num > 8) { + _num = 8; + } + let _numLine = Number.parseInt(script.getNumberValue('NUM_LINE', script)); + if (_numLine < 1) { + _numLine = 1; + } else if (_numLine > 8) { + _numLine = 8; + } + let _isRow = script.getNumberValue('IS_ROW', script); + let _value = script.getStringValue('VALUE'); + const _f = (str) => { + str = str.substring(0, 8); + let retVal = ''; + for (let i = 0; i < str.length; ++i) { + if (str[i] === '0' || str[i] === ' ') { + retVal += '0'; + } else { + retVal += '1'; + } + } + return retVal.padStart(8, '0'); + }; + _value = _f(_value); + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 39, + params: [_num, _numLine, _isRow, _value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + /* + CodeWizLite_DotMatrix_Show_Custom_Image: { + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + value: '1', + }, + { + type: 'Led', + value: [ + [0, 0, 0, 0, 0], + [0, 1, 1, 0, 0], + [1, 1, 1, 1, 1], + [1, 1, 1, 1, 1], + [0, 1, 1, 1, 1], + ], + }, + { + type: 'Indicator', + img: 'block_icon/hardwarelite_icon.svg', + size: 12, + }, + ], + events: {}, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + def: { + type: 'CodeWizLite_DotMatrix_Show_Custom_Image', + }, + paramsKeyMap: { + NUM: 0, + VALUE: 1, + }, + async func(sprite, script) { + let _num = Number.parseInt(script.getNumberValue('NUM', script)); + if (_num < 1) { + num = 1; + } else if (_num > 8) { + _num = 8; + } + const value = script.getField('VALUE'); + const processedValue = []; + for (const i in value) { + processedValue[i] = value[i].join(''); + console.log(processedValue[i]); + let _numLine = Number.parseInt(i) + 1; + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 39, + params: [_num, _numLine, 0, processedValue[i]], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + } + return; + }, + }, +*/ + CodeWizLite_DotMatrix_setDot: { + // Block UI : '도트매트릭스 %1번에 %2행%3열 %4%5', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Dropdown', + options: [ + ['켜기', '1'], + ['끄기', '0'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1', '2', '2', null], + type: 'CodeWizLite_DotMatrix_setDot', + }, + paramsKeyMap: { + NUM: 0, + ROW: 1, + COL: 2, + VALUE: 3, + }, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _num = Number.parseInt(script.getNumberValue('NUM', script)); + if (_num < 1) { + num = 1; + } else if (_num > 8) { + _num = 8; + } + let _numRow = Number.parseInt(script.getNumberValue('ROW', script)); + if (_numRow < 1) { + _numRow = 1; + } else if (_numRow > 8) { + _numRow = 8; + } + let _numCol = Number.parseInt(script.getNumberValue('COL', script)); + if (_numCol < 1) { + _numCol = 1; + } else if (_numCol > 8) { + _numCol = 8; + } + let _value = script.getNumberValue('VALUE', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 40, + params: [_num, _numRow, _numCol, _value], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_DotMatrix_clear: { + // Block UI : '도트매트릭스 %1번 지우기%2', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: ['1'], + type: 'CodeWizLite_DotMatrix_clear', + }, + paramsKeyMap: { + NUM: 0, + }, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _num = Number.parseInt(script.getNumberValue('NUM', script)); + if (_num < 1) { + num = 1; + } else if (_num > 8) { + _num = 8; + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 41, + params: [_num - 1], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + CodeWizLite_DotMatrix_clearAll: { + // Block UI : '도트매트릭스 모두 지우기%1', + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [], + type: 'CodeWizLite_DotMatrix_clearAll', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_DotMatrix', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 41, + params: [-1], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + //delete Entry.CodeWizLite.sensorData[id]; + }, + }, + + CodeWizLite_ColorSensor_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_ColorSensor_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_ColorSensor_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_ColorSensor_title', + }, + class: 'CodeWizLite_ColorSensor', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_ColorSensor_isColor: { + // Block UI : "MCON 컬러센서 감지된 색이 %1인가%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['빨강', '0'], + ['초록', '1'], + ['파랑', '2'], + ['검정', '3'], + ['흰색', '4'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_ColorSensor_isColor', + }, + paramsKeyMap: { + COLOR: 0, + }, + class: 'CodeWizLite_ColorSensor', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _color = script.getNumberValue('COLOR', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 8, + params: [_color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? false; + //delete Entry.CodeWizLite.sensorData[id]; + return retVal; + }, + }, + CodeWizLite_ColorSensor_getColorValue: { + // Block UI : "MCON 컬러센서 %1값%2", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['빨강', '0'], + ['초록', '1'], + ['파랑', '2'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_ColorSensor_getColorValue', + }, + paramsKeyMap: { + COLOR: 0, + }, + class: 'CodeWizLite_ColorSensor', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _color = script.getNumberValue('COLOR', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 9, + params: [_color], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? 0; + //delete Entry.CodeWizLite.sensorData[id]; + return retVal; + }, + }, + + CodeWizLite_DHT_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_DHT_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_DHT_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_DHT_title', + }, + class: 'CodeWizLite_DHT', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_DHT_init: { + // 디지털 온습도 설정 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['13', '13'], + ['14', '14'], + ['15', '15'], + ['27', '27'], + ['32', '32'], + ['33', '33'], + ['18', '18'], + ['19', '19'], + ], + value: '18', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_DHT_init', + }, + paramsKeyMap: { + PIN: 0, + }, + class: 'CodeWizLite_DHT', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _pin = script.getNumberValue('PIN', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 48, + params: [_pin], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + }, + }, + CodeWizLite_DHT_getValue: { + // 디지털 온습도 값 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['℃', '0'], + ['℉', '1'], + ['습도', '2'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_DHT_getValue', + }, + paramsKeyMap: { + TYPE: 0, + }, + class: 'CodeWizLite_DHT', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _type = script.getNumberValue('TYPE', script); + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 12, + params: [_type], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? 0.0; + //delete Entry.CodeWizLite.sensorData[id]; + return retVal; + }, + }, + CodeWizLite_Joystick_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: this.getOffsetX(Lang.template.CodeWizLite_Joystick_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_Joystick_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_Joystick_title', + }, + class: 'CodeWizLite_Joystick', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_Joystick_setPin: { + // 조이스틱 설정 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['32', '32'], + ['33', '33'], + ['36', '36'], + ['39', '39'], + ], + value: '36', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['32', '32'], + ['33', '33'], + ['36', '36'], + ['39', '39'], + ], + value: '39', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['13', '13'], + ['14', '14'], + ['15', '15'], + ['27', '27'], + ['18', '18'], + ['19', '19'], + ], + value: '15', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Block', + accept: 'string', + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null, null, null, 12], + type: 'CodeWizLite_Joystick_setPin', + }, + paramsKeyMap: { + PIN_X: 0, + PIN_Y: 1, + PIN_B: 2, + RANGE: 3, + }, + class: 'CodeWizLite_Joystick', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + let _pinX = script.getNumberValue('PIN_X', script); + let _pinY = script.getNumberValue('PIN_Y', script); + let _pinB = script.getNumberValue('PIN_B', script); + let _range = script.getNumberValue('RANGE', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.WRITE, + value: { + opcode: 50, + params: [_pinX, _pinY, _pinB, _range], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + }, + }, + CodeWizLite_Joystick_readAxis: { + // 조이스틱 XY레버값 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['X축', '0'], + ['Y축', '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_Joystick_readAxis', + }, + paramsKeyMap: { + TYPE: 0, + }, + class: 'CodeWizLite_Joystick', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _type = script.getNumberValue('TYPE', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 13, + params: [_type], + }, + }; + + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? 0; + //delete Entry.CodeWizLite.sensorData[id]; + // console.log(_type===0?"X:":"Y:",retVal); + return retVal; + }, + }, + CodeWizLite_Joystick_readButton: { + // 조이스틱 버튼값 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_Joystick_readButton', + }, + paramsKeyMap: {}, + class: 'CodeWizLite_Joystick', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 14, + params: [], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? false; + //delete Entry.CodeWizLite.sensorData[id]; + // console.log("Button:",retVal); + return retVal; + }, + }, + + CodeWizLite_etcReadSensor_title: { + skeleton: 'basic_text', + skeletonOptions: { + box: { + offsetX: + 5 + this.getOffsetX(Lang.template.CodeWizLite_etcReadSensor_title), + offsetY: 5, + }, + }, + color: EntryStatic.colorSet.common.TRANSPARENT, + fontColor: '#333333', + params: [ + { + type: 'Text', + text: Lang.template.CodeWizLite_etcReadSensor_title, + color: '#333333', + align: 'left', + }, + ], + def: { + type: 'CodeWizLite_etcReadSensor_title', + }, + class: 'CodeWizLite_etcReadSensor', + isNotFor: ['CodeWizLite'], + events: {}, + }, + CodeWizLite_etcReadSensor_mconRead: { + // 가변저항, 워터센서, 토양수분센서 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['가변저항', '0'], + ['워터센서', '1'], + ['토양수분센서', '2'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['32', '32'], + ['33', '33'], + ['36', '36'], + ['39', '39'], + ], + value: '36', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_etcReadSensor_mconRead', + }, + paramsKeyMap: { + TYPE: 0, + PIN: 1, + }, + class: 'CodeWizLite_etcReadSensor', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _type = script.getNumberValue('TYPE', script); + let _pin = script.getNumberValue('PIN', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 10, + params: [_type, _pin], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? 0; + //delete Entry.CodeWizLite.sensorData[id]; + return retVal; + }, + }, + CodeWizLite_etcReadSensor_digitalRead: { + // 버튼, 포토인터럽트 + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_boolean_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['버튼', '0'], + ['포토인터럽트', '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['13', '13'], + ['14', '14'], + ['15', '15'], + ['27', '27'], + ['32', '32'], + ['33', '33'], + ['18', '18'], + ['19', '19'], + ], + value: '18', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_etcReadSensor_digitalRead', + }, + paramsKeyMap: { + TYPE: 0, + PIN: 1, + }, + class: 'CodeWizLite_etcReadSensor', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _type = script.getNumberValue('TYPE', script); + let _pin = script.getNumberValue('PIN', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 11, + params: [_type, _pin], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? false; + //delete Entry.CodeWizLite.sensorData[id]; + return retVal; + }, + }, + CodeWizLite_etcReadSensor_InfraredThermometerRead: { + // Block UI : "비접촉온도센서 %1에 %2로 읽기%3", + color: EntryStatic.colorSet.block.default.HARDWARE, + outerLine: EntryStatic.colorSet.block.darken.HARDWARE, + skeleton: 'basic_string_field', + statements: [], + params: [ + { + type: 'Dropdown', + options: [ + ['SCON', '0'], + ['MCON', '1'], + ], + value: '1', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Dropdown', + options: [ + ['℃', '0'], + ['℉', '1'], + ], + value: '0', + fontSize: 11, + bgColor: EntryStatic.colorSet.block.darken.HARDWARE, + arrowColor: EntryStatic.colorSet.arrow.default.HARDWARE, + }, + { + type: 'Indicator', + img: 'block_icon/hardware_icon.svg', + size: 12, + }, + ], + events: {}, + def: { + params: [null], + type: 'CodeWizLite_etcReadSensor_InfraredThermometerRead', + }, + paramsKeyMap: { + IS_M: 0, + IS_F: 1, + }, + class: 'CodeWizLite_etcReadSensor', + isNotFor: ['CodeWizLite'], + async func(sprite, script) { + if (Entry.CodeWizLite.intervalId) { + await Entry.CodeWizLite.preWait(); + } + let _isM = script.getNumberValue('IS_M', script); + let _isF = script.getNumberValue('IS_F', script); + + const order = { + type: Entry.CodeWizLite.sensorTypes.READ, + value: { + opcode: 8, + params: [_isM, _isF], + }, + }; + const id = Entry.CodeWizLite.sendOrder(order); + await Entry.CodeWizLite.checkComplete(1000, id); + + let retVal = Entry.CodeWizLite.sensorData[id]?.value ?? 0; + //delete Entry.CodeWizLite.sensorData[id]; + return retVal; + }, + }, + //endregion CodeWiz 코드위즈 + }; + } + })(); +})(); + +module.exports = Entry.CodeWizLite; diff --git a/src/playground/blocks/hardwareLite/metadata_codewiz_lite.json b/src/playground/blocks/hardwareLite/metadata_codewiz_lite.json new file mode 100644 index 0000000000..a7b70c71dd --- /dev/null +++ b/src/playground/blocks/hardwareLite/metadata_codewiz_lite.json @@ -0,0 +1,9 @@ +{ + "name": "CodeWizLite", + "version": "1.0.0", + "type": "hardware", + "title": "코드위즈", + "description": "Codewiz", + "imageName": "codewizlite.png", + "moduleId": "011201" +}