diff --git a/blocks/sensors/amg8833/AMG8833x.js b/blocks/sensors/amg8833/AMG8833x.js
new file mode 100644
index 0000000..32cc5bc
--- /dev/null
+++ b/blocks/sensors/amg8833/AMG8833x.js
@@ -0,0 +1,55 @@
+'use strict';
+
+const err_msg = 'AMG8833 is already opened. Please close old connection to use new one.';
+const pig = require('@ocogeclub/pigpio');
+
+let pi = -1;
+let i2c_hand = -1;
+exports.init = async (i2c_bus, i2c_addr, win = null) => {
+ if (win !== null) {
+ win.addEventListener('beforeunload', async () => {
+ await exports.stop();
+ });
+ }
+ if (pi >= 0) { throw new Error(err_msg); return; }
+ pi = await pig._pigpio_start('', '');
+ console.log('pi=' + pi);
+ if (i2c_hand >= 0) { throw new Error(err_msg); return; }
+ i2c_hand = await pig._i2c_open(pi, i2c_bus, i2c_addr);
+ console.log('i2c_hand=' + i2c_hand);
+ await pig._i2c_write_byte_data(pi, i2c_hand, 0x00, 0x00); //Normal mode
+ await pig._i2c_write_byte_data(pi, i2c_hand, 0x02, 0x00); //10FPS
+}
+
+exports.read_thermistor = async () => {
+ let temp = await pig._i2c_read_word_data(pi, i2c_hand, 0x0e);
+ return temp * 0.0625;
+}
+
+exports.read_temp_array = async () => {
+ let linedata = [];
+ for (let i = 0; i < 8; i++) {
+ let data = await pig._i2c_read_i2c_block_data(pi, i2c_hand, 0x80 + 0x10 * i, 16);
+ let oneline = [];
+ for (let j = 0; j < 8; j++) {
+ oneline.push(((data[2 * j + 1] & 0x07) * 256 + data[2 * j]) * 0.25);
+ }
+ linedata.push(oneline);
+ }
+ return linedata;
+}
+
+exports.stop = async () => {
+ if (i2c_hand >= 0) {
+ await pig._i2c_close(pi, i2c_hand);
+ i2c_hand = -1;
+ }
+ if (pi >= 0) {
+ await pig._pigpio_stop(pi);
+ pi = -1;
+ }
+}
+
+/*
+* This code was ported from https://www.denshi.club/pc/raspi/5raspberry-pi-zeroiot381i2c-amg8833.html
+*/
diff --git a/blocks/sensors/amg8833/index.js b/blocks/sensors/amg8833/index.js
new file mode 100644
index 0000000..465e75e
--- /dev/null
+++ b/blocks/sensors/amg8833/index.js
@@ -0,0 +1,425 @@
+Blockly.Msg["UGJ_DRAW_GRIDEYEDATA_TITLE"] = "赤外線アレイセンサ画像表示 %1 温度データ %2 温度範囲上限 %3 %4 温度範囲下限 %5 %6";
+Blockly.Msg["UGJ_DRAW_GRIDEYEDATA_TOOLTIP"] = "AMG8833の温度データを、画像としてキャンバスに描画します。「着色」をチェックすると、温度範囲で設定されている色をつけて表示します。";
+
+Blockly.Msg["UGJ_GRIDEYE_INIT_TITLE"] = "赤外線アレイセンサ(アドレス: %1 )を初期化";
+Blockly.Msg["UGJ_GRIDEYE_INIT_TOOLTIP"] = "赤外線アレイセンサ AMG8833 の使用準備をします。";
+Blockly.Msg["UGJ_GRIDEYE_THERMISTOR_TITLE"] = "赤外線アレイセンサ本体温度";
+Blockly.Msg["UGJ_GRIDEYE_THERMISTOR_TOOLTIP"] = "AMG8833に内蔵されたサーミスタ(温度センサ)の値を取得します。";
+Blockly.Msg["UGJ_GRIDEYE_READ_TITLE"] = "赤外線アレイセンサの値";
+Blockly.Msg["UGJ_GRIDEYE_READ_TOOLTIP"] = "AMG8833から読み取った温度データを、8x8の配列で取得します。";
+Blockly.Msg["UGJ_GRIDEYE_STOP_TITLE"] = "赤外線アレイセンサから切断";
+Blockly.Msg["UGJ_GRIDEYE_STOP_TOOLTIP"] = "センサーとの接続を停止します。";
+Blockly.Msg["UGJ_GRIDEYE_CANVAS_CREATE_TITLE"] = "赤外線アレイセンサデータ表示キャンバスを作成";
+Blockly.Msg["UGJ_GRIDEYE_CANVAS_CREATE_TOOLTIP"] = "ディスプレイエリアにAMG8833データ表示用キャンバスを作成します。";
+Blockly.Msg["UGJ_TEACHABLE_MACHINE_TITLE"] = "TensorFlow.jsによる画像分類器の準備";
+Blockly.Msg["UGJ_TEACHABLE_MACHINE_TOOLTIP"] = "TensorFlow.jsにMobileNet, KNN Classifierを読み込んで、画像認識(分類)を行う準備をします。";
+Blockly.Msg["UGJ_GRIDEYE_PREDICT_CLASS_TITLE"] = "赤外線アレイセンサの画像で推論を行う";
+Blockly.Msg["UGJ_GRIDEYE_PREDICT_CLASS_TOOLTIP"] = "キャンバスに表示されたAMG8833の画像を元に画像分類の推論を行います。推論の結果として定義済みのラベルを返します。";
+Blockly.Msg["UGJ_GRIDEYE_ADD_EXAMPLE_TITLE"] = "赤外線アレイセンサの画像にラベル %1 をつけてデータセットへ追加";
+Blockly.Msg["UGJ_GRIDEYE_ADD_EXAMPLE_TOOLTIP"] = "キャンバスに表示されているAMG8833の画像にラベル(クラス名)をつけてデータセットへ追加します。";
+Blockly.Msg["UGJ_TENSORSET_STRINGIFY_TITLE"] = "学習したクラスデータセットを文字列に変換";
+Blockly.Msg["UGJ_TENSORSET_STRINGIFY_TOOLTIP"] = "学習したクラスデータセットを文字列に変換して保存します。";
+Blockly.Msg["UGJ_TENSORSET_PARSE_TITLE"] = "クラスデータ文字列 %1 を画像分類器にセット";
+Blockly.Msg["UGJ_TENSORSET_PARSE_TOOLTIP"] = "JSONテキストをパースして画像分類器に戻します。";
+
+/******************* */
+/** Init Grid-Eye ** */
+/******************* */
+var ugjGridEyeInitDefinition = {
+ "type": "ugj_grideye_init",
+ "message0": "%{BKY_UGJ_GRIDEYE_INIT_TITLE}",
+ "args0": [
+ {
+ "type": "field_dropdown",
+ "name": "addr",
+ "options": [
+ [
+ "0x68",
+ "0x68"
+ ],
+ [
+ "0x69",
+ "0x69"
+ ]
+ ]
+ }
+ ],
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_GRIDEYE_INIT_TOOLTIP}",
+ "helpUrl": "",
+ "style": "sensor_blocks"
+};
+Blockly.Blocks['ugj_grideye_init'] = {
+ init: function () {
+ this.jsonInit(ugjGridEyeInitDefinition);
+ }
+};
+Blockly.JavaScript['ugj_grideye_init'] = function (block) {
+ var dropdown_addr = block.getFieldValue('addr');
+ Blockly.JavaScript.provideFunction_(
+ 'require_gpio', [`const _pi = require('@ocogeclub/` + elutil.gpio_backend + `');`]
+ );
+ let modpath = elutil.path.join(elutil.blocks_sensors_dir, 'amg8833', 'AMG8833x.js');
+ Blockly.JavaScript.provideFunction_(
+ 'require_amg8833', [`const _amg8833 = require('${modpath}');`]
+ );
+ var code = `await _amg8833.init(${elutil.i2c_bus}, ${dropdown_addr}, window);\n`;
+ return code;//
+};
+/********************** */
+/** Grid-Eye 本体温度 ** */
+/********************** */
+var ugjGridEyeThermistorDefinition = {
+ "type": "ugj_grideye_thermistor",
+ "message0": "%{BKY_UGJ_GRIDEYE_THERMISTOR_TITLE}",
+ "output": "Number",
+ "tooltip": "%{BKY_UGJ_GRIDEYE_THERMISTOR_TOOLTIP}",
+ "helpUrl": "",
+ "style": "sensor_blocks"
+};
+Blockly.Blocks['ugj_grideye_thermistor'] = {
+ init: function () {
+ this.jsonInit(ugjGridEyeThermistorDefinition);
+ }
+};
+Blockly.JavaScript['ugj_grideye_thermistor'] = function (block) {
+ var code = `await _amg8833.read_thermistor()`;
+ return [code, Blockly.JavaScript.ORDER_NONE];
+};
+
+/**************************** */
+/** Read Temperature Array ** */
+/**************************** */
+var ugjGridEyeReadDefinition = {
+ "type": "ugj_grideye_read",
+ "message0": "%{BKY_UGJ_GRIDEYE_READ_TITLE}",
+ "inputsInline": true,
+ "output": "Array",
+ "tooltip": "%{BKY_UGJ_GRIDEYE_READ_TOOLTIP}",
+ "helpUrl": "",
+ "style": "sensor_blocks"
+};
+Blockly.Blocks['ugj_grideye_read'] = {
+ init: function () {
+ this.jsonInit(ugjGridEyeReadDefinition);
+ }
+};
+Blockly.JavaScript['ugj_grideye_read'] = function (block) {
+ var code = 'await _amg8833.read_temp_array()';
+ return [code, Blockly.JavaScript.ORDER_ATOMIC];
+};
+/******************* */
+/** Stop Grid-Eye ** */
+/******************* */
+var ugjGridEyeStopDefinition = {
+ "type": "ugj_grideye_stop",
+ "message0": "%{BKY_UGJ_GRIDEYE_STOP_TITLE}",
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_GRIDEYE_STOP_TOOLTIP}",
+ "helpUrl": "",
+ "style": "sensor_blocks"
+};
+Blockly.Blocks['ugj_grideye_stop'] = {
+ init: function () {
+ this.jsonInit(ugjGridEyeStopDefinition);
+ }
+};
+Blockly.JavaScript['ugj_grideye_stop'] = function (block) {
+ var code = 'await _amg8833.stop();\n';
+ return code;
+};
+
+
+/***************************** */
+/** GridEye 表示キャンバス作成 ** */
+/***************************** */
+var ugjGridEyeCanvasCreateDefinition = {
+ "type": "ugj_grideye_canvas_create",
+ "message0": "%{BKY_UGJ_GRIDEYE_CANVAS_CREATE_TITLE}",
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_GRIDEYE_CANVAS_CREATE_TOOLTIP}",
+ "helpUrl": "",
+ "style": "multimedia_blocks"
+};
+Blockly.Blocks['ugj_grideye_canvas_create'] = {
+ init: function () {
+ this.jsonInit(ugjGridEyeCanvasCreateDefinition);
+ }
+};
+Blockly.JavaScript['ugj_grideye_canvas_create'] = function (block) {
+ var code = `let _grideye_canvas = document.createElement('canvas');
+ _grideye_canvas.setAttribute('width', 8);
+ _grideye_canvas.setAttribute('height', 8);
+ _grideye_canvas.className = 'subdisplay';
+ _grideye_canvas.style.width = '160px';
+ _grideye_canvas.style.height = '160px';
+ _grideye_canvas.id = 'subcanvas';
+ document.getElementById('display_area').appendChild(_grideye_canvas);
+ _grideye_ctx = _grideye_canvas.getContext('2d');
+ _grideye_imgData = _grideye_ctx.createImageData(8, 8);
+ `;
+ return code;
+};
+/********************************************** */
+/** Draw IR Array Data to Image Data ** */
+/********************************************** */
+var ugjDrawGrideyedataDefinition = {
+ "type": "ugj_draw_grideyedata",
+ "message0": "%{BKY_UGJ_DRAW_GRIDEYEDATA_TITLE}",
+ "args0": [
+ {
+ "type": "input_dummy"
+ },
+ {
+ "type": "input_value",
+ "name": "amg8833data",
+ "check": "Array",
+ "align": "RIGHT"
+ },
+ {
+ "type": "field_colour",
+ "name": "color_high",
+ "colour": "#ff0000"
+ },
+ {
+ "type": "input_value",
+ "name": "temp_high",
+ "check": "Number",
+ "align": "RIGHT"
+ },
+ {
+ "type": "field_colour",
+ "name": "color_low",
+ "colour": "#3333ff"
+ },
+ {
+ "type": "input_value",
+ "name": "temp_low",
+ "check": "Number",
+ "align": "RIGHT"
+ }
+ ],
+ "inputsInline": false,
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_DRAW_GRIDEYEDATA_TOOLTIP}",
+ "helpUrl": "",
+ "style": "multimedia_blocks"
+};
+Blockly.Blocks['ugj_draw_grideyedata'] = {
+ init: function () {
+ this.jsonInit(ugjDrawGrideyedataDefinition);
+ }
+};
+Blockly.JavaScript['ugj_draw_grideyedata'] = function (block) {
+ var value_amg8833data = Blockly.JavaScript.valueToCode(block, 'amg8833data', Blockly.JavaScript.ORDER_ATOMIC);
+ var colour_color_high = block.getFieldValue('color_high');
+ var value_temp_high = Blockly.JavaScript.valueToCode(block, 'temp_high', Blockly.JavaScript.ORDER_ATOMIC);
+ var colour_color_low = block.getFieldValue('color_low');
+ var value_temp_low = Blockly.JavaScript.valueToCode(block, 'temp_low', Blockly.JavaScript.ORDER_ATOMIC);
+ var functionName = Blockly.JavaScript.provideFunction_(
+ '_mapVal',
+ ['const ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + ' = (val, inMin, inMax, outMin, outMax) => {',
+ `return (val - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;`,
+ '}'
+ ]
+ );
+ // 温度カラー
+ let hr, hg, hb, lr, lg, lb;
+ hr = '0x' + colour_color_high.slice(1, 3);
+ hg = '0x' + colour_color_high.slice(3, 5);
+ hb = '0x' + colour_color_high.slice(5, 7);
+ lr = '0x' + colour_color_low.slice(1, 3);
+ lg = '0x' + colour_color_low.slice(3, 5);
+ lb = '0x' + colour_color_low.slice(5, 7);
+ var code = ` const _color_range = [[${lr}, ${hr}], [${lg}, ${hg}], [${lb}, ${hb}]];
+ let _grideye_data = ${value_amg8833data};//読み取りブロックを入力に直接接続できるようにする
+ for (let raw = 0; raw < _grideye_canvas.height; raw++) {
+ for (let col = 0; col < _grideye_canvas.width; col++) {
+ for (let rgb = 0; rgb < 3; rgb++) {
+ let pixel = ${functionName}(_grideye_data[raw][col], ${value_temp_low}, ${value_temp_high}, _color_range[rgb][0], _color_range[rgb][1]);
+ _grideye_imgData.data[((raw * _grideye_canvas.width * 4) + col * 4) + rgb] = pixel;
+ }
+ _grideye_imgData.data[((raw * _grideye_canvas.width * 4) + col * 4) + 3] = 0xff;
+ }
+ }
+ _grideye_ctx.putImageData(_grideye_imgData, 0, 0);
+
+ `;
+ return code;
+};
+
+/**************************** */
+/** Teachable Machine を開始** */
+/**************************** */
+var ugjTeachableMachineDefinition = {
+ "type": "ugj_teachable_machine",
+ "message0": "%{BKY_UGJ_TEACHABLE_MACHINE_TITLE}",
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_TEACHABLE_MACHINE_TOOLTIP}",
+ "helpUrl": "",
+ "style": "multimedia_blocks"
+};
+Blockly.Blocks['ugj_teachable_machine'] = {
+ init: function () {
+ this.jsonInit(ugjTeachableMachineDefinition);
+ }
+};
+Blockly.JavaScript['ugj_teachable_machine'] = function (block) {
+ Blockly.JavaScript.provideFunction_(
+ 'require_ts', [`const _tf = require('@tensorflow/tfjs');`]
+ // 'require_ts', [`const _tf = require('@tensorflow/tfjs-node');`]
+ );
+ Blockly.JavaScript.provideFunction_(
+ 'require_wasm', [`const _wasm = require('@tensorflow/tfjs-backend-wasm');`]
+ );
+ Blockly.JavaScript.provideFunction_(
+ 'require_mobilenet', [`const _mobilenet = require('@tensorflow-models/mobilenet');`]
+ );
+ Blockly.JavaScript.provideFunction_(
+ 'require_knn', [`const _knnClassifier = require('@tensorflow-models/knn-classifier');`]
+ );
+
+ var code = `await _tf.setBackend('wasm');
+ const _net = await _mobilenet.load({ version: 1, alpha: 0.25 }); // 高速・低精度
+ const _classifier = _knnClassifier.create();
+ `;
+ return code;
+};
+/************************* */
+/** GridEye で推論を行う ** */
+/************************* */
+var ugjGridEyePredictClassDefinition = {
+ "type": "ugj_grideye_predict_class",
+ "message0": "%{BKY_UGJ_GRIDEYE_PREDICT_CLASS_TITLE}",
+ "inputsInline": true,
+ "output": "Number",
+ "tooltip": "%{BKY_UGJ_GRIDEYE_PREDICT_CLASS_TOOLTIP}",
+ "helpUrl": "",
+ "style": "multimedia_blocks"
+};
+Blockly.Blocks['ugj_grideye_predict_class'] = {
+ init: function () {
+ this.jsonInit(ugjGridEyePredictClassDefinition);
+ }
+};
+Blockly.JavaScript['ugj_grideye_predict_class'] = function (block) {
+ var functionName = Blockly.JavaScript.provideFunction_( // left output にするための関数化
+ '_predictClass',
+ [
+ `if (_confidence === undefined) var _confidence;`,
+ `const ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_} = async (img, clsfr, mblnet) => {`,
+ `if (clsfr.getNumClasses() > 0) {`,
+ `const result = await clsfr.predictClass(mblnet.infer(img, 'conv_preds'));`,
+ `_confidence = result.confidences[result.label];`,
+ `return result.label;`,
+ `}`,
+ `else return 0;`,
+ `}`
+ ]
+ );
+ var code = `await ${functionName}(_grideye_canvas, _classifier, _net)`;
+ return [code, Blockly.JavaScript.ORDER_NONE];
+};
+/******************************************** */
+/** ラベルをつけて Example をデータセットに追加 ** */
+/******************************************** */
+var ugjGridEyeAddExampleDefinition = {
+ "type": "ugj_grideye_add_example",
+ "message0": "%{BKY_UGJ_GRIDEYE_ADD_EXAMPLE_TITLE}",
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "class_id",
+ "check": "Number"
+ }
+ ],
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_GRIDEYE_ADD_EXAMPLE_TOOLTIP}",
+ "helpUrl": "",
+ "style": "multimedia_blocks"
+};
+Blockly.Blocks['ugj_grideye_add_example'] = {
+ init: function () {
+ this.jsonInit(ugjGridEyeAddExampleDefinition);
+ }
+};
+Blockly.JavaScript['ugj_grideye_add_example'] = function (block) {
+ var value_class_id = Blockly.JavaScript.valueToCode(block, 'class_id', Blockly.JavaScript.ORDER_ATOMIC);
+ var code = `_classifier.addExample (_net.infer(_grideye_canvas, true), ${value_class_id});`;
+ return code;
+};
+/*************************** */
+/** 学習したクラスを文字列化 ** */
+/*************************** */
+var ugjTensorsetStringifyDefinition = {
+ "type": "ugj_tensorset_stringify",
+ "message0": "%{BKY_UGJ_TENSORSET_STRINGIFY_TITLE}",
+ "output": null,
+ "tooltip": "%{BKY_UGJ_TENSORSET_STRINGIFY_TOOLTIP}",
+ "helpUrl": "",
+ "style": "multimedia_blocks"
+};
+Blockly.Blocks['ugj_tensorset_stringify'] = {
+ init: function () {
+ this.jsonInit(ugjTensorsetStringifyDefinition);
+ }
+};
+Blockly.JavaScript['ugj_tensorset_stringify'] = function (block) {
+ Blockly.JavaScript.provideFunction_(
+ 'require_tensorset', [`const _Tensorset = require('tensorset');`]
+ );
+ var code = `await _Tensorset.stringify(_classifier.getClassifierDataset())`;
+ return [code, Blockly.JavaScript.ORDER_NONE];
+};
+/***************************************** */
+/** jsonをデータセットに戻して分類器にセット ** */
+/***************************************** */
+var ugjTensorsetParseDefinition = {
+ "type": "ugj_tensorset_parse",
+ "message0": "%{BKY_UGJ_TENSORSET_PARSE_TITLE}",
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "class_data_json",
+ "check": "String"
+ }
+ ],
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_TENSORSET_PARSE_TOOLTIP}",
+ "helpUrl": "",
+ "style": "multimedia_blocks"
+};
+Blockly.Blocks['ugj_tensorset_parse'] = {
+ init: function () {
+ this.jsonInit(ugjTensorsetParseDefinition);
+ }
+};
+Blockly.JavaScript['ugj_tensorset_parse'] = function (block) {
+ Blockly.JavaScript.provideFunction_(
+ 'require_tensorset', [`const _Tensorset = require('tensorset');`]
+ );
+ var value_class_data_json = Blockly.JavaScript.valueToCode(block, 'class_data_json', Blockly.JavaScript.ORDER_ATOMIC);
+ var code = `try {
+ let _class_dataset = _Tensorset.parse(${value_class_data_json});
+ _classifier.setClassifierDataset(_class_dataset);
+ } catch (error) {
+ alert('Could not load class dataset.');
+ }
+ `;
+ return code;
+};
+
+
+
diff --git a/blocks/sensors/amg8833/index.json b/blocks/sensors/amg8833/index.json
new file mode 100644
index 0000000..d8842da
--- /dev/null
+++ b/blocks/sensors/amg8833/index.json
@@ -0,0 +1,87 @@
+[
+ {
+ "kind": "label",
+ "text": "赤外線アレイセンサー(サーマルカメラ)AMG8833",
+ "web-line": "4.0",
+ "web-line-width": "200"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_grideye_init",
+ "fields": {
+ "addr": "0x69"
+ }
+ },
+ {
+ "kind": "block",
+ "type": "ugj_grideye_thermistor"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_grideye_read"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_grideye_stop"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_grideye_canvas_create"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_draw_grideyedata",
+ "fields": {
+ "color_high": "#ff0000",
+ "color_low": "#3333ff"
+ },
+ "inputs": {
+ "temp_high": {
+ "shadow": {
+ "type": "math_number",
+ "fields": {
+ "NUM": "28"
+ }
+ }
+ },
+ "temp_low": {
+ "shadow": {
+ "type": "math_number",
+ "fields": {
+ "NUM": "15"
+ }
+ }
+ }
+ }
+ },
+ {
+ "kind": "block",
+ "type": "ugj_teachable_machine"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_grideye_predict_class"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_grideye_add_example",
+ "inputs": {
+ "class_id": {
+ "shadow": {
+ "type": "math_number",
+ "fields": {
+ "NUM": "0"
+ }
+ }
+ }
+ }
+ },
+ {
+ "kind": "block",
+ "type": "ugj_tensorset_stringify"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_tensorset_parse"
+ }
+]
\ No newline at end of file
diff --git a/blocks/sensors/bme280/BME280x.js b/blocks/sensors/bme280/BME280x.js
new file mode 100644
index 0000000..5411eca
--- /dev/null
+++ b/blocks/sensors/bme280/BME280x.js
@@ -0,0 +1,270 @@
+'use strict';
+
+this.pig = null;
+this.pi = null;
+
+this.i2cBusNo = null;
+this.i2cAddress = null;
+this.i2cHand = null;
+
+this.I2C_ADDRESS_B = 0x76;
+this.I2C_ADDRESS_A = 0x77;
+this.CHIP_ID = 0x58;
+
+this.REGISTER_DIG_T1 = 0x88;
+this.REGISTER_DIG_T2 = 0x8A;
+this.REGISTER_DIG_T3 = 0x8C;
+
+this.REGISTER_DIG_P1 = 0x8E;
+this.REGISTER_DIG_P2 = 0x90;
+this.REGISTER_DIG_P3 = 0x92;
+this.REGISTER_DIG_P4 = 0x94;
+this.REGISTER_DIG_P5 = 0x96;
+this.REGISTER_DIG_P6 = 0x98;
+this.REGISTER_DIG_P7 = 0x9A;
+this.REGISTER_DIG_P8 = 0x9C;
+this.REGISTER_DIG_P9 = 0x9E;
+
+this.REGISTER_DIG_H1 = 0xA1;
+this.REGISTER_DIG_H2 = 0xE1;
+this.REGISTER_DIG_H3 = 0xE3;
+this.REGISTER_DIG_H4 = 0xE4;
+this.REGISTER_DIG_H5 = 0xE5;
+this.REGISTER_DIG_H6 = 0xE7;
+
+this.REGISTER_CHIPID = 0xD0;
+this.REGISTER_RESET = 0xE0;
+
+this.REGISTER_CONTROL_HUM = 0xF2;
+this.REGISTER_CONTROL = 0xF4;
+this.REGISTER_PRESSURE_DATA = 0xF7;
+this.REGISTER_TEMP_DATA = 0xFA;
+this.REGISTER_HUMIDITY_DATA = 0xFD;
+
+exports.init = async (options) => {
+ this.pig = require('@ocogeclub/pigpio');
+ this.pi = await this.pig._pigpio_start('', '');
+
+ this.i2cBusNo = (options && options.hasOwnProperty('i2cBusNo')) ? options.i2cBusNo : 1;
+ this.i2cAddress = (options && options.hasOwnProperty('i2cAddress')) ? options.i2cAddress : this.BME280_DEFAULT_I2C_ADDRESS();
+ this.i2cHand = await this.pig._i2c_open(this.pi, this.i2cBusNo, this.i2cAddress);
+
+ let r;
+ r = await this.pig._i2c_write_byte_data(this.pi, this.i2cHand, this.REGISTER_CHIPID, 0);
+ if (r < 0) return r;
+ let chipId = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_CHIPID);
+ if (chipId !== this.CHIP_ID_BME280() &&
+ chipId !== this.CHIP_ID1_BMP280() &&
+ chipId !== this.CHIP_ID2_BMP280() &&
+ chipId !== this.CHIP_ID3_BMP280()) {
+ return `Unexpected BMx280 chip ID: 0x${chipId.toString(16).toUpperCase()}`;
+ }
+ // console.log(`Found BMx280 chip ID 0x${chipId.toString(16).toUpperCase()} on bus i2c-${this.i2cBusNo}, address 0x${this.i2cAddress.toString(16).toUpperCase()}`);
+ await this.loadCalibration(async (err) => {
+ if (err) {
+ return err;
+ }
+ // Humidity 16x oversampling
+ //
+ let r = await this.pig._i2c_write_byte_data(this.pi, this.i2cHand, this.REGISTER_CONTROL_HUM, 0b00000101);
+ if (r < 0) return `Humidity 16x oversampling error: ${r}`;
+ // Temperture/pressure 16x oversampling, normal mode
+ //
+ r = await this.pig._i2c_write_byte_data(this.pi, this.i2cHand, this.REGISTER_CONTROL, 0b10110111);
+ if (r < 0) return `Temperture/pressure 16x oversampling error: ${r}`;
+
+ return 0;
+ });
+}
+
+// reset()
+//
+// Perform a power-on reset procedure. You will need to call init() following a reset()
+//
+exports.reset = async () => {
+ const POWER_ON_RESET_CMD = 0xB6;
+ let r = await this.pig._i2c_write_byte_data(this.pi, this.i2cHand, this.REGISTER_RESET, POWER_ON_RESET_CMD);
+ if (r < 0) return `cannot power-on reset: ${r}`;
+ else return 0;
+}
+
+// cancel()
+//
+// Cancels the sensor and releases resources.
+//
+exports.cancel = async () => {
+ if (this.i2cHand >= 0) {
+ await this.pig._i2c_close(this.pi, this.i2cHand);
+ this.i2cHand = null;
+ await this.pig._pigpio_stop(this.pi);
+ this.pi = null;
+ }
+}
+
+exports.readSensorData = async () => {
+ if (!this.cal) {
+ return 'You must first call bme280.init()';
+ }
+
+ // Grab temperature, humidity, and pressure in a single read
+ //
+ let buffer = await this.pig._i2c_read_i2c_block_data(this.pi, this.i2cHand, this.REGISTER_PRESSURE_DATA, 8);
+ if (!buffer) return `couldn't grab data`;
+ // Temperature (temperature first since we need t_fine for pressure and humidity)
+ //
+ let adc_T = this.uint20(buffer[3], buffer[4], buffer[5]);
+ let tvar1 = ((((adc_T >> 3) - (this.cal.dig_T1 << 1))) * this.cal.dig_T2) >> 11;
+ let tvar2 = (((((adc_T >> 4) - this.cal.dig_T1) * ((adc_T >> 4) - this.cal.dig_T1)) >> 12) * this.cal.dig_T3) >> 14;
+ let t_fine = tvar1 + tvar2;
+
+ let temperature_C = ((t_fine * 5 + 128) >> 8) / 100;
+
+ // Pressure
+ //
+ let adc_P = this.uint20(buffer[0], buffer[1], buffer[2]);
+ let pvar1 = t_fine / 2 - 64000;
+ let pvar2 = pvar1 * pvar1 * this.cal.dig_P6 / 32768;
+ pvar2 = pvar2 + pvar1 * this.cal.dig_P5 * 2;
+ pvar2 = pvar2 / 4 + this.cal.dig_P4 * 65536;
+ pvar1 = (this.cal.dig_P3 * pvar1 * pvar1 / 524288 + this.cal.dig_P2 * pvar1) / 524288;
+ pvar1 = (1 + pvar1 / 32768) * this.cal.dig_P1;
+
+ let pressure_hPa = 0;
+
+ if (pvar1 !== 0) {
+ let p = 1048576 - adc_P;
+ p = ((p - pvar2 / 4096) * 6250) / pvar1;
+ pvar1 = this.cal.dig_P9 * p * p / 2147483648;
+ pvar2 = p * this.cal.dig_P8 / 32768;
+ p = p + (pvar1 + pvar2 + this.cal.dig_P7) / 16;
+
+ pressure_hPa = p / 100;
+ }
+
+ // Humidity (available on the BME280, will be zero on the BMP280 since it has no humidity sensor)
+ //
+ let adc_H = this.uint16(buffer[6], buffer[7]);
+
+ let h = t_fine - 76800;
+ h = (adc_H - (this.cal.dig_H4 * 64 + this.cal.dig_H5 / 16384 * h)) *
+ (this.cal.dig_H2 / 65536 * (1 + this.cal.dig_H6 / 67108864 * h * (1 + this.cal.dig_H3 / 67108864 * h)));
+ h = h * (1 - this.cal.dig_H1 * h / 524288);
+
+ let humidity = (h > 100) ? 100 : (h < 0 ? 0 : h);
+
+ return {
+ temperature_C: temperature_C,
+ humidity: humidity,
+ pressure_hPa: pressure_hPa
+ };
+}
+
+exports.loadCalibration = async (callback) => {
+ let buffer = await this.pig._i2c_read_i2c_block_data(this.pi, this.i2cHand, this.REGISTER_DIG_T1, 24);
+ if (buffer) {
+ let h1 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H1);
+ let h2 = await this.pig._i2c_read_word_data(this.pi, this.i2cHand, this.REGISTER_DIG_H2);
+ let h3 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H3);
+ let h4 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H4);
+ let h5 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H5);
+ let h5_1 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H5 + 1);
+ let h6 = await this.pig._i2c_read_byte_data(this.pi, this.i2cHand, this.REGISTER_DIG_H6);
+
+ this.cal = {
+ dig_T1: this.uint16(buffer[1], buffer[0]),
+ dig_T2: this.int16(buffer[3], buffer[2]),
+ dig_T3: this.int16(buffer[5], buffer[4]),
+
+ dig_P1: this.uint16(buffer[7], buffer[6]),
+ dig_P2: this.int16(buffer[9], buffer[8]),
+ dig_P3: this.int16(buffer[11], buffer[10]),
+ dig_P4: this.int16(buffer[13], buffer[12]),
+ dig_P5: this.int16(buffer[15], buffer[14]),
+ dig_P6: this.int16(buffer[17], buffer[16]),
+ dig_P7: this.int16(buffer[19], buffer[18]),
+ dig_P8: this.int16(buffer[21], buffer[20]),
+ dig_P9: this.int16(buffer[23], buffer[22]),
+
+ dig_H1: h1,
+ dig_H2: h2,
+ dig_H3: h3,
+ dig_H4: (h4 << 4) | (h5 & 0xF),
+ dig_H5: (h5_1 << 4) | (h5 >> 4),
+ dig_H6: h6
+ };
+
+ // console.log('BME280 cal = ' + JSON.stringify(this.cal, null, 2));
+ await callback();
+ }
+}
+
+exports.BME280_DEFAULT_I2C_ADDRESS = () => {
+ return 0x77;
+}
+
+exports.CHIP_ID1_BMP280 = () => {
+ return 0x56;
+}
+
+exports.CHIP_ID2_BMP280 = () => {
+ return 0x57;
+}
+
+exports.CHIP_ID3_BMP280 = () => {
+ return 0x58;
+}
+
+exports.CHIP_ID_BME280 = () => {
+ return 0x60;
+}
+
+exports.int16 = (msb, lsb) => {
+ let val = this.uint16(msb, lsb);
+ return val > 32767 ? (val - 65536) : val;
+}
+
+exports.uint16 = (msb, lsb) => {
+ return msb << 8 | lsb;
+}
+
+exports.uint20 = (msb, lsb, xlsb) => {
+ return ((msb << 8 | lsb) << 8 | xlsb) >> 4;
+}
+
+exports.convertCelciusToFahrenheit = (c) => {
+ return c * 9 / 5 + 32;
+}
+
+exports.convertHectopascalToInchesOfMercury = (hPa) => {
+ return hPa * 0.02952998751;
+}
+
+exports.convertMetersToFeet = (m) => {
+ return m * 3.28084;
+}
+
+exports.calculateHeatIndexCelcius = (temperature_C, humidity) => {
+ return -8.784695 + 1.61139411 * temperature_C + 2.33854900 * humidity +
+ -0.14611605 * temperature_C * humidity + -0.01230809 * Math.pow(temperature_C, 2) +
+ -0.01642482 * Math.pow(humidity, 2) + 0.00221173 * Math.pow(temperature_C, 2) * humidity +
+ 0.00072546 * temperature_C * Math.pow(humidity, 2) +
+ -0.00000358 * Math.pow(temperature_C, 2) * Math.pow(humidity, 2);
+}
+
+exports.calculateDewPointCelcius = (temperature_C, humidity) => {
+ return 243.04 * (Math.log(humidity / 100.0) + ((17.625 * temperature_C) / (243.04 + temperature_C))) /
+ (17.625 - Math.log(humidity / 100.0) - ((17.625 * temperature_C) / (243.04 + temperature_C)));
+}
+
+exports.calculateAltitudeMeters = (pressure_hPa, seaLevelPressure_hPa) => {
+ if (!seaLevelPressure_hPa) {
+ seaLevelPressure_hPa = 1013.25;
+ }
+
+ return (1.0 - Math.pow(pressure_hPa / seaLevelPressure_hPa, (1 / 5.2553))) * 145366.45 * 0.3048;
+}
+
+
+/*
+ * This code was forked from skylarstein's bme280-sensor: https://github.com/skylarstein/bme280-sensor
+ */
\ No newline at end of file
diff --git a/blocks/sensors/bme280/index.js b/blocks/sensors/bme280/index.js
new file mode 100644
index 0000000..d76f568
--- /dev/null
+++ b/blocks/sensors/bme280/index.js
@@ -0,0 +1,56 @@
+/********* */
+/** BME280 */
+/********* */
+Blockly.Blocks['ugj_bme280'] = {
+ init: function () {
+ this.appendDummyInput()
+ .appendField("BME280(アドレス")
+ .appendField(new Blockly.FieldDropdown([["0x76", "0x76"], ["0x77", "0x77"]]), "addr")
+ .appendField(")の計測値を取得");
+ this.setInputsInline(true);
+ this.setPreviousStatement(true, null);
+ this.setNextStatement(true, null);
+ this.setStyle('sensor_blocks');
+ this.setTooltip("環境センサーBME280で、気温(摂氏)、湿度(%)、気圧(hPa)を計測します。計測結果は計測値ブロックで参照します。");
+ this.setHelpUrl("");
+ }
+};
+Blockly.JavaScript['ugj_bme280'] = function (block) {
+ var dropdown_addr = block.getFieldValue('addr');
+ Blockly.JavaScript.provideFunction_(
+ 'require_gpio', [`const _pi = require('@ocogeclub/` + elutil.gpio_backend + `');`]
+ );
+ let modpath = elutil.path.join(elutil.blocks_sensors_dir, 'bme280', 'BME280x.js');
+ Blockly.JavaScript.provideFunction_(
+ 'require_bme280', [`const _bme280 = require('${modpath}');`]
+ );
+ var code = `const options = {
+ i2cBusNo: ${elutil.i2c_bus},
+ i2cAddress: ${dropdown_addr}
+ };
+ await _bme280.init(options);
+ let _thp = await _bme280.readSensorData();
+ let _bmedata = [];
+ _bmedata[0] = Math.round(_thp.temperature_C * 10) / 10;
+ _bmedata[1] = Math.round(_thp.humidity * 10) / 10;
+ _bmedata[2] = Math.round(_thp.pressure_hPa);
+ await _bme280.cancel();
+ `;
+ return code;
+};
+Blockly.Blocks['ugj_bme280_data'] = {
+ init: function () {
+ this.appendDummyInput()
+ .appendField(new Blockly.FieldDropdown([["気温", "0"], ["湿度", "1"], ["気圧", "2"]]), "thp");
+ this.setInputsInline(true);
+ this.setOutput(true, null);
+ this.setStyle('sensor_blocks');
+ this.setTooltip("BME280 の計測値を返します。");
+ this.setHelpUrl("");
+ }
+};
+Blockly.JavaScript['ugj_bme280_data'] = function (block) {
+ var dropdown_thp = block.getFieldValue('thp');
+ var code = `_bmedata[${dropdown_thp}]`;
+ return [code, Blockly.JavaScript.ORDER_ATOMIC];
+};
\ No newline at end of file
diff --git a/blocks/sensors/bme280/index.json b/blocks/sensors/bme280/index.json
new file mode 100644
index 0000000..7a4e319
--- /dev/null
+++ b/blocks/sensors/bme280/index.json
@@ -0,0 +1,22 @@
+[
+ {
+ "kind": "label",
+ "text": "温湿度気圧センサー BME280",
+ "web-line": "4.0",
+ "web-line-width": "200"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_bme280",
+ "fields": {
+ "addr": "0x76"
+ }
+ },
+ {
+ "kind": "block",
+ "type": "ugj_bme280_data",
+ "fields": {
+ "thp": "0"
+ }
+ }
+]
\ No newline at end of file
diff --git a/blocks/sensors/dht11/dht11.py b/blocks/sensors/dht11/dht11.py
new file mode 100644
index 0000000..55ebee9
--- /dev/null
+++ b/blocks/sensors/dht11/dht11.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import time
+import pigpio
+
+
+class DHT11(object):
+ """
+ The DHT11 class is a stripped version of the DHT22 sensor code by joan2937.
+ You can find the initial implementation here:
+ - https://github.com/srounet/pigpio/tree/master/EXAMPLES/Python/DHT22_AM2302_SENSOR
+
+ example code:
+ >>> pi = pigpio.pi()
+ >>> sensor = DHT11(pi, 4) # 4 is the data GPIO pin connected to your sensor
+ >>> for response in sensor:
+ .... print("Temperature: {}".format(response['temperature']))
+ .... print("Humidity: {}".format(response['humidity']))
+ """
+
+ def __init__(self, pi, gpio):
+ """
+ pi (pigpio): an instance of pigpio
+ gpio (int): gpio pin number
+ """
+ self.pi = pi
+ self.gpio = gpio
+ self.high_tick = 0
+ self.bit = 40
+ self.temperature = 0
+ self.humidity = 0
+ self.either_edge_cb = None
+ self.setup()
+
+ def setup(self):
+ """
+ Clears the internal gpio pull-up/down resistor.
+ Kills any watchdogs.
+ """
+ self.pi.set_pull_up_down(self.gpio, pigpio.PUD_OFF)
+ self.pi.set_watchdog(self.gpio, 0)
+ self.register_callbacks()
+
+ def register_callbacks(self):
+ """
+ Monitors RISING_EDGE changes using callback.
+ """
+ self.either_edge_cb = self.pi.callback(
+ self.gpio, pigpio.EITHER_EDGE, self.either_edge_callback
+ )
+
+ def either_edge_callback(self, gpio, level, tick):
+ """
+ Either Edge callbacks, called each time the gpio edge changes.
+ Accumulate the 40 data bits from the dht11 sensor.
+ """
+ level_handlers = {
+ pigpio.FALLING_EDGE: self._edge_FALL,
+ pigpio.RISING_EDGE: self._edge_RISE,
+ pigpio.EITHER_EDGE: self._edge_EITHER,
+ }
+ handler = level_handlers[level]
+ diff = pigpio.tickDiff(self.high_tick, tick)
+ handler(tick, diff)
+
+ def _edge_RISE(self, tick, diff):
+ """
+ Handle Rise signal.
+ """
+ val = 0
+ if diff >= 50:
+ val = 1
+ if diff >= 200: # Bad bit?
+ self.checksum = 256 # Force bad checksum
+
+ if self.bit >= 40: # Message complete
+ self.bit = 40
+ elif self.bit >= 32: # In checksum byte
+ self.checksum = (self.checksum << 1) + val
+ if self.bit == 39:
+ # 40th bit received
+ self.pi.set_watchdog(self.gpio, 0)
+ total = self.humidity + self.temperature
+ # is checksum ok ?
+ if not (total & 255) == self.checksum:
+ raise
+ elif 16 <= self.bit < 24: # in temperature byte
+ self.temperature = (self.temperature << 1) + val
+ elif 0 <= self.bit < 8: # in humidity byte
+ self.humidity = (self.humidity << 1) + val
+ else: # skip header bits
+ pass
+ self.bit += 1
+
+ def _edge_FALL(self, tick, diff):
+ """
+ Handle Fall signal.
+ """
+ self.high_tick = tick
+ if diff <= 250000:
+ return
+ self.bit = -2
+ self.checksum = 0
+ self.temperature = 0
+ self.humidity = 0
+
+ def _edge_EITHER(self, tick, diff):
+ """
+ Handle Either signal.
+ """
+ self.pi.set_watchdog(self.gpio, 0)
+
+ def read(self):
+ """
+ Start reading over DHT11 sensor.
+ """
+ self.pi.write(self.gpio, pigpio.LOW)
+ time.sleep(0.017) # 17 ms
+ self.pi.set_mode(self.gpio, pigpio.INPUT)
+ self.pi.set_watchdog(self.gpio, 200)
+ time.sleep(0.2)
+
+ def close(self):
+ """
+ Stop reading sensor, remove callbacks.
+ """
+ self.pi.set_watchdog(self.gpio, 0)
+ if self.either_edge_cb:
+ self.either_edge_cb.cancel()
+ self.either_edge_cb = None
+
+ def __iter__(self):
+ """
+ Support the iterator protocol.
+ """
+ return self
+
+ def __next__(self):
+ """
+ Call the read method and return temperature and humidity informations.
+ """
+ self.read()
+ response = {"humidity": self.humidity, "temperature": self.temperature}
+ return response
+
+
+if __name__ == "__main__":
+ import sys
+
+ args = sys.argv
+ pin = int(args[1])
+ pi = pigpio.pi()
+ sensor = DHT11(pi, pin)
+ for d in sensor:
+ # print("temperature: {}".format(d["temperature"]))
+ # print("humidity: {}".format(d["humidity"]))
+
+ print(
+ '{"temperature":'
+ + str(d["temperature"])
+ + ',"humidity":'
+ + str(d["humidity"])
+ + "}",
+ flush=True,
+ )
+ break
+ # time.sleep(1)
+ sensor.close()
diff --git a/blocks/sensors/dht11/index.js b/blocks/sensors/dht11/index.js
new file mode 100644
index 0000000..112cf23
--- /dev/null
+++ b/blocks/sensors/dht11/index.js
@@ -0,0 +1,41 @@
+Blockly.Blocks['ugj_dht11'] = {
+ init: function () {
+ this.appendValueInput("pin")
+ .setCheck("Number")
+ .appendField("GPIO");
+ this.appendDummyInput()
+ .appendField("の DHT11 センサーの値を取得");
+ this.setInputsInline(true);
+ this.setPreviousStatement(true, null);
+ this.setNextStatement(true, null);
+ this.setTooltip("");
+ this.setHelpUrl("気温・湿度センサーDHT11で、気温(摂氏)、湿度(%)を計測します。計測値は計測値ブロックで参照します。");
+ this.setStyle('sensor_blocks');
+ }
+};
+Blockly.JavaScript['ugj_dht11'] = function (block) {
+ var value_pin = Blockly.JavaScript.valueToCode(block, 'pin', Blockly.JavaScript.ORDER_ATOMIC);
+ let pypath = elutil.path.join(elutil.blocks_sensors_dir, 'dht11', 'dht11.py');
+ var code = `let _th = require('child_process').spawnSync('python3', ['${pypath}', '${value_pin}']).stdout.toString();
+ let _dhtdata = JSON.parse(_th);`;
+ // let _dht11data[0] =
+ // console.log('t=' + obj.temperature);
+ // console.log('h=' + obj.humidity);
+ return code;
+};
+Blockly.Blocks['ugj_dht11_data'] = {
+ init: function () {
+ this.appendDummyInput()
+ .appendField(new Blockly.FieldDropdown([["気温", "temperature"], ["湿度", "humidity"]]), "th");
+ this.setInputsInline(true);
+ this.setOutput(true, null);
+ this.setStyle('sensor_blocks');
+ this.setTooltip("DHT11 の計測値を返します。");
+ this.setHelpUrl("");
+ }
+};
+Blockly.JavaScript['ugj_dht11_data'] = function (block) {
+ var dropdown_th = block.getFieldValue('th');
+ var code = `_dhtdata.${dropdown_th}`;
+ return [code, Blockly.JavaScript.ORDER_ATOMIC];
+};
\ No newline at end of file
diff --git a/blocks/sensors/dht11/index.json b/blocks/sensors/dht11/index.json
new file mode 100644
index 0000000..7e4b061
--- /dev/null
+++ b/blocks/sensors/dht11/index.json
@@ -0,0 +1,29 @@
+[
+ {
+ "kind": "label",
+ "text": "温湿度センサー DHT11",
+ "web-line": "4.0",
+ "web-line-width": "200"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_dht11",
+ "inputs": {
+ "pin": {
+ "shadow": {
+ "type": "math_number",
+ "fields": {
+ "NUM": "8"
+ }
+ }
+ }
+ }
+ },
+ {
+ "kind": "block",
+ "type": "ugj_dht11_data",
+ "fields": {
+ "th": "temperature"
+ }
+ }
+]
\ No newline at end of file
diff --git a/blocks/sensors/paj7620/PAJ7620x.js b/blocks/sensors/paj7620/PAJ7620x.js
new file mode 100644
index 0000000..78c4cdb
--- /dev/null
+++ b/blocks/sensors/paj7620/PAJ7620x.js
@@ -0,0 +1,471 @@
+"use strict";
+
+const sleep = sec =>
+ new Promise(r => setTimeout(r, sec * 1000));
+
+const GES_REACTION_TIME = .100; // default:0.5 // You can adjust the reaction time according to the actual circumstance.
+const GES_ENTRY_TIME = .050; // default:0.8 // When you want to recognize the Forward/Backward gestures, your gestures' reaction time must less than GES_ENTRY_TIME(0.8s).
+const GES_QUIT_TIME = 1.000;
+
+const BANK0 = 0;
+const BANK1 = 1;
+
+const PAJ7620_ADDR_BASE = 0x00;
+
+//REGISTER BANK SELECT
+const PAJ7620_REGITER_BANK_SEL = (PAJ7620_ADDR_BASE + 0xEF); //W
+
+//DEVICE ID
+// const PAJ7620_ID = 0x73;
+
+//REGISTER BANK 0
+const PAJ7620_ADDR_SUSPEND_CMD = (PAJ7620_ADDR_BASE + 0x3); //W
+const PAJ7620_ADDR_GES_PS_DET_MASK_0 = (PAJ7620_ADDR_BASE + 0x41); //RW
+const PAJ7620_ADDR_GES_PS_DET_MASK_1 = (PAJ7620_ADDR_BASE + 0x42); //RW
+const PAJ7620_ADDR_GES_PS_DET_FLAG_0 = (PAJ7620_ADDR_BASE + 0x43); //R
+const PAJ7620_ADDR_GES_PS_DET_FLAG_1 = (PAJ7620_ADDR_BASE + 0x44); //R
+const PAJ7620_ADDR_STATE_INDICATOR = (PAJ7620_ADDR_BASE + 0x45); //R
+const PAJ7620_ADDR_PS_HIGH_THRESHOLD = (PAJ7620_ADDR_BASE + 0x69); //RW
+const PAJ7620_ADDR_PS_LOW_THRESHOLD = (PAJ7620_ADDR_BASE + 0x6A); //RW
+const PAJ7620_ADDR_PS_APPROACH_STATE = (PAJ7620_ADDR_BASE + 0x6B); //R
+const PAJ7620_ADDR_PS_RAW_DATA = (PAJ7620_ADDR_BASE + 0x6C); //R
+
+//REGISTER BANK 1
+const PAJ7620_ADDR_PS_GAIN = (PAJ7620_ADDR_BASE + 0x44); //RW
+const PAJ7620_ADDR_IDLE_S1_STEP_0 = (PAJ7620_ADDR_BASE + 0x67); //RW
+const PAJ7620_ADDR_IDLE_S1_STEP_1 = (PAJ7620_ADDR_BASE + 0x68); //RW
+const PAJ7620_ADDR_IDLE_S2_STEP_0 = (PAJ7620_ADDR_BASE + 0x69); //RW
+const PAJ7620_ADDR_IDLE_S2_STEP_1 = (PAJ7620_ADDR_BASE + 0x6A); //RW
+const PAJ7620_ADDR_OP_TO_S1_STEP_0 = (PAJ7620_ADDR_BASE + 0x6B); //RW
+const PAJ7620_ADDR_OP_TO_S1_STEP_1 = (PAJ7620_ADDR_BASE + 0x6C); //RW
+const PAJ7620_ADDR_OP_TO_S2_STEP_0 = (PAJ7620_ADDR_BASE + 0x6D); //RW
+const PAJ7620_ADDR_OP_TO_S2_STEP_1 = (PAJ7620_ADDR_BASE + 0x6E); //RW
+const PAJ7620_ADDR_OPERATION_ENABLE = (PAJ7620_ADDR_BASE + 0x72); //RW
+
+//PAJ7620_REGITER_BANK_SEL
+const PAJ7620_BANK0 = 0;
+const PAJ7620_BANK1 = 1;
+
+//PAJ7620_ADDR_SUSPEND_CMD
+const PAJ7620_I2C_WAKEUP = 1;
+const PAJ7620_I2C_SUSPEND = 0;
+
+//PAJ7620_ADDR_OPERATION_ENABLE
+const PAJ7620_ENABLE = 1;
+const PAJ7620_DISABLE = 0;
+
+//ADC, delete
+const REG_ADDR_RESULT = 0x00;
+const REG_ADDR_ALERT = 0x01;
+const REG_ADDR_CONFIG = 0x02;
+const REG_ADDR_LIMITL = 0x03;
+const REG_ADDR_LIMITH = 0x04;
+const REG_ADDR_HYST = 0x05;
+const REG_ADDR_CONVL = 0x06;
+const REG_ADDR_CONVH = 0x07;
+
+const GES_RIGHT_FLAG = 1 << 0;
+const GES_LEFT_FLAG = 1 << 1;
+const GES_UP_FLAG = 1 << 2;
+const GES_DOWN_FLAG = 1 << 3;
+const GES_FORWARD_FLAG = 1 << 4;
+const GES_BACKWARD_FLAG = 1 << 5;
+const GES_CLOCKWISE_FLAG = 1 << 6;
+const GES_COUNT_CLOCKWISE_FLAG = 1 << 7;
+const GES_WAVE_FLAG = 1 << 0;
+
+//Gesture output
+exports.FORWARD = 1;
+exports.BACKWARD = 2;
+exports.RIGHT = 3;
+exports.LEFT = 4;
+exports.UP = 5;
+exports.DOWN = 6;
+exports.CLOCKWISE = 7;
+exports.ANTI_CLOCKWISE = 8;
+exports.WAVE = 9;
+
+//Initial register state
+const initRegisterArray = [
+ [0xEF, 0x00],
+ [0x32, 0x29],
+ [0x33, 0x01],
+ [0x34, 0x00],
+ [0x35, 0x01],
+ [0x36, 0x00],
+ [0x37, 0x07],
+ [0x38, 0x17],
+ [0x39, 0x06],
+ [0x3A, 0x12],
+ [0x3F, 0x00],
+ [0x40, 0x02],
+ [0x41, 0xFF],
+ [0x42, 0x01],
+ [0x46, 0x2D],
+ [0x47, 0x0F],
+ [0x48, 0x3C],
+ [0x49, 0x00],
+ [0x4A, 0x1E],
+ [0x4B, 0x00],
+ [0x4C, 0x20],
+ [0x4D, 0x00],
+ [0x4E, 0x1A],
+ [0x4F, 0x14],
+ [0x50, 0x00],
+ [0x51, 0x10],
+ [0x52, 0x00],
+ [0x5C, 0x02],
+ [0x5D, 0x00],
+ [0x5E, 0x10],
+ [0x5F, 0x3F],
+ [0x60, 0x27],
+ [0x61, 0x28],
+ [0x62, 0x00],
+ [0x63, 0x03],
+ [0x64, 0xF7],
+ [0x65, 0x03],
+ [0x66, 0xD9],
+ [0x67, 0x03],
+ [0x68, 0x01],
+ [0x69, 0xC8],
+ [0x6A, 0x40],
+ [0x6D, 0x04],
+ [0x6E, 0x00],
+ [0x6F, 0x00],
+ [0x70, 0x80],
+ [0x71, 0x00],
+ [0x72, 0x00],
+ [0x73, 0x00],
+ [0x74, 0xF0],
+ [0x75, 0x00],
+ [0x80, 0x42],
+ [0x81, 0x44],
+ [0x82, 0x04],
+ [0x83, 0x20],
+ [0x84, 0x20],
+ [0x85, 0x00],
+ [0x86, 0x10],
+ [0x87, 0x00],
+ [0x88, 0x05],
+ [0x89, 0x18],
+ [0x8A, 0x10],
+ [0x8B, 0x01],
+ [0x8C, 0x37],
+ [0x8D, 0x00],
+ [0x8E, 0xF0],
+ [0x8F, 0x81],
+ [0x90, 0x06],
+ [0x91, 0x06],
+ [0x92, 0x1E],
+ [0x93, 0x0D],
+ [0x94, 0x0A],
+ [0x95, 0x0A],
+ [0x96, 0x0C],
+ [0x97, 0x05],
+ [0x98, 0x0A],
+ [0x99, 0x41],
+ [0x9A, 0x14],
+ [0x9B, 0x0A],
+ [0x9C, 0x3F],
+ [0x9D, 0x33],
+ [0x9E, 0xAE],
+ [0x9F, 0xF9],
+ [0xA0, 0x48],
+ [0xA1, 0x13],
+ [0xA2, 0x10],
+ [0xA3, 0x08],
+ [0xA4, 0x30],
+ [0xA5, 0x19],
+ [0xA6, 0x10],
+ [0xA7, 0x08],
+ [0xA8, 0x24],
+ [0xA9, 0x04],
+ [0xAA, 0x1E],
+ [0xAB, 0x1E],
+ [0xCC, 0x19],
+ [0xCD, 0x0B],
+ [0xCE, 0x13],
+ [0xCF, 0x64],
+ [0xD0, 0x21],
+ [0xD1, 0x0F],
+ [0xD2, 0x88],
+ [0xE0, 0x01],
+ [0xE1, 0x04],
+ [0xE2, 0x41],
+ [0xE3, 0xD6],
+ [0xE4, 0x00],
+ [0xE5, 0x0C],
+ [0xE6, 0x0A],
+ [0xE7, 0x00],
+ [0xE8, 0x00],
+ [0xE9, 0x00],
+ [0xEE, 0x07],
+ [0xEF, 0x01],
+ [0x00, 0x1E],
+ [0x01, 0x1E],
+ [0x02, 0x0F],
+ [0x03, 0x10],
+ [0x04, 0x02],
+ [0x05, 0x00],
+ [0x06, 0xB0],
+ [0x07, 0x04],
+ [0x08, 0x0D],
+ [0x09, 0x0E],
+ [0x0A, 0x9C],
+ [0x0B, 0x04],
+ [0x0C, 0x05],
+ [0x0D, 0x0F],
+ [0x0E, 0x02],
+ [0x0F, 0x12],
+ [0x10, 0x02],
+ [0x11, 0x02],
+ [0x12, 0x00],
+ [0x13, 0x01],
+ [0x14, 0x05],
+ [0x15, 0x07],
+ [0x16, 0x05],
+ [0x17, 0x07],
+ [0x18, 0x01],
+ [0x19, 0x04],
+ [0x1A, 0x05],
+ [0x1B, 0x0C],
+ [0x1C, 0x2A],
+ [0x1D, 0x01],
+ [0x1E, 0x00],
+ [0x21, 0x00],
+ [0x22, 0x00],
+ [0x23, 0x00],
+ [0x25, 0x01],
+ [0x26, 0x00],
+ [0x27, 0x39],
+ [0x28, 0x7F],
+ [0x29, 0x08],
+ [0x30, 0x03],
+ [0x31, 0x00],
+ [0x32, 0x1A],
+ [0x33, 0x1A],
+ [0x34, 0x07],
+ [0x35, 0x07],
+ [0x36, 0x01],
+ [0x37, 0xFF],
+ [0x38, 0x36],
+ [0x39, 0x07],
+ [0x3A, 0x00],
+ [0x3E, 0xFF],
+ [0x3F, 0x00],
+ [0x40, 0x77],
+ [0x41, 0x40],
+ [0x42, 0x00],
+ [0x43, 0x30],
+ [0x44, 0xA0],
+ [0x45, 0x5C],
+ [0x46, 0x00],
+ [0x47, 0x00],
+ [0x48, 0x58],
+ [0x4A, 0x1E],
+ [0x4B, 0x1E],
+ [0x4C, 0x00],
+ [0x4D, 0x00],
+ [0x4E, 0xA0],
+ [0x4F, 0x80],
+ [0x50, 0x00],
+ [0x51, 0x00],
+ [0x52, 0x00],
+ [0x53, 0x00],
+ [0x54, 0x00],
+ [0x57, 0x80],
+ [0x59, 0x10],
+ [0x5A, 0x08],
+ [0x5B, 0x94],
+ [0x5C, 0xE8],
+ [0x5D, 0x08],
+ [0x5E, 0x3D],
+ [0x5F, 0x99],
+ [0x60, 0x45],
+ [0x61, 0x40],
+ [0x63, 0x2D],
+ [0x64, 0x02],
+ [0x65, 0x96],
+ [0x66, 0x00],
+ [0x67, 0x97],
+ [0x68, 0x01],
+ [0x69, 0xCD],
+ [0x6A, 0x01],
+ [0x6B, 0xB0],
+ [0x6C, 0x04],
+ [0x6D, 0x2C],
+ [0x6E, 0x01],
+ [0x6F, 0x32],
+ [0x71, 0x00],
+ [0x72, 0x01],
+ [0x73, 0x35],
+ [0x74, 0x00],
+ [0x75, 0x33],
+ [0x76, 0x31],
+ [0x77, 0x01],
+ [0x7C, 0x84],
+ [0x7D, 0x03],
+ [0x7E, 0x01]
+];
+
+//Enable debug message
+const debug = 1;
+
+const err_msg = 'AMG8833 is already opened. Please close old connection to use new one.';
+let pig = -1;
+let pi = -1;
+let i2c_hand = -1;
+//Initialize the sensors
+exports.init = async (i2c_bus, i2c_addr, win = null) => {
+ if (win !== null) {
+ win.addEventListener('beforeunload', async () => {
+ await exports.stop();
+ });
+ }
+ pig = require('@ocogeclub/pigpio');
+ if (pi >= 0) { throw new Error(err_msg); return; }
+ pi = await pig._pigpio_start('', '');
+ if (i2c_hand >= 0) { throw new Error(err_msg); return; }
+ i2c_hand = await pig._i2c_open(pi, i2c_bus, i2c_addr);
+ if (debug)
+ console.log("pi=" + pi + ", i2c_hand=" + i2c_hand);
+
+ await sleep(.001);
+ await paj7620SelectBank(BANK0);
+ await paj7620SelectBank(BANK0);
+
+ let data0 = (await paj7620ReadReg(0, 1))[0];
+ let data1 = (await paj7620ReadReg(1, 1))[0];
+ if (debug)
+ console.log("data0:" + data0 + ", data1:" + data1);
+ if (data0 != 0x20) //or data1 <> 0x76
+ console.log("Error with sensor");
+ //return 0xff
+ if (data0 == 0x20)
+ console.log("wake-up finish.");
+
+ for (let i = 0; i < initRegisterArray.length; i += 1)
+ await paj7620WriteReg(initRegisterArray[i][0], initRegisterArray[i][1]);
+
+ await paj7620SelectBank(BANK0);
+
+ console.log("Paj7620 initialize register finished.");
+
+}
+
+// Write a byte to a register on the Gesture sensor
+const paj7620WriteReg = async (addr, cmd) =>
+ await pig._i2c_write_word_data(pi, i2c_hand, addr, cmd);
+
+//Select a register bank on the Gesture Sensor
+const paj7620SelectBank = async bank => {
+ if (bank == BANK0)
+ await paj7620WriteReg(PAJ7620_REGITER_BANK_SEL, PAJ7620_BANK0);
+}
+
+//Read a block of bytes of length "qty" starting at address "addr" from the Gesture sensor
+const paj7620ReadReg = async (addr, qty) => {
+ return await pig._i2c_read_i2c_block_data(pi, i2c_hand, addr, qty);
+}
+
+//Return a vlaue from the gestire sensor which can be used in a program
+// 0:nothing
+// 1:Forward
+// 2:Backward
+// 3:Right
+// 4:Left
+// 5:Up
+// 6:Down
+// 7:Clockwise
+// 8:anti-clockwise
+// 9:wave
+exports.return_gesture = async () => {
+
+ let data = (await paj7620ReadReg(0x43, 1))[0];
+ if (data == GES_RIGHT_FLAG) {
+ await sleep(GES_ENTRY_TIME);
+ data = (await paj7620ReadReg(0x43, 1))[0];
+ if (data == GES_FORWARD_FLAG) {
+ return 1;
+ }
+ else if (data == GES_BACKWARD_FLAG) {
+ return 2;
+ }
+ else
+ return 3;
+ }
+
+ else if (data == GES_LEFT_FLAG) {
+ await sleep(GES_ENTRY_TIME);
+ data = (await paj7620ReadReg(0x43, 1))[0];
+ if (data == GES_FORWARD_FLAG) {
+ return 1;
+ }
+ else if (data == GES_BACKWARD_FLAG) {
+ return 2;
+ }
+ else
+ return 4;
+ }
+
+ else if (data == GES_UP_FLAG) {
+ await sleep(GES_ENTRY_TIME);
+ data = (await paj7620ReadReg(0x43, 1))[0];
+ if (data == GES_FORWARD_FLAG) {
+ return 1;
+ }
+ else if (data == GES_BACKWARD_FLAG) {
+ return 2;
+ }
+ else
+ return 5;
+ }
+
+ else if (data == GES_DOWN_FLAG) {
+ await sleep(GES_ENTRY_TIME);
+ data = (await paj7620ReadReg(0x43, 1))[0];
+ if (data == GES_FORWARD_FLAG) {
+ return 1;
+ }
+ else if (data == GES_BACKWARD_FLAG) {
+ return 2;
+ }
+ else
+ return 6;
+ }
+ else if (data == GES_FORWARD_FLAG) {
+ return 1;
+ }
+
+ else if (data == GES_BACKWARD_FLAG) {
+ return 2;
+ }
+
+ else if (data == GES_CLOCKWISE_FLAG)
+ return 7;
+
+ else if (data == GES_COUNT_CLOCKWISE_FLAG)
+ return 8;
+
+ else {
+ let data1 = (await paj7620ReadReg(0x44, 1))[0];
+ if (data1 == GES_WAVE_FLAG)
+ return 9;
+ }
+ return 0;
+}
+
+exports.stop = async () => {
+ if (i2c_hand >= 0) {
+ await pig._i2c_close(pi, i2c_hand);
+ i2c_hand = -1;
+ }
+ if (pi >= 0) {
+ await pig._pigpio_stop(pi);
+ pi = -1;
+ }
+}
+
+/*
+ * This code was ported from "Grove - Gesture Sensor v1.0 Python library and examples": https://github.com/DexterInd/GrovePi/tree/master/Software/Python/grove_gesture_sensor
+ */
\ No newline at end of file
diff --git a/blocks/sensors/paj7620/index.js b/blocks/sensors/paj7620/index.js
new file mode 100644
index 0000000..fc42956
--- /dev/null
+++ b/blocks/sensors/paj7620/index.js
@@ -0,0 +1,89 @@
+/********** */
+/** PAJ7620 */
+/********** */
+Blockly.Msg["UGJ_GESTURE_INIT_TITLE"] = "ジェスチャーセンサー(アドレス: %1 )を初期化";
+Blockly.Msg["UGJ_GESTURE_INIT_TOOLTIP"] = "PAJ7620 ジェスチャーセンサーを使用する準備をします。";
+Blockly.Msg["UGJ_GESTURE_READ_TITLE"] = "ジェスチャーの値";
+Blockly.Msg["UGJ_GESTURE_READ_TOOLTIP"] = "センサーから現在のジェスチャーの値(0〜9)を読み込みます";
+Blockly.Msg["UGJ_GESTURE_STOP_TITLE"] = "ジェスチャーセンサーから切断";
+Blockly.Msg["UGJ_GESTURE_STOP_TOOLTIP"] = "センサーとの接続を停止します。";
+
+var ugjGestureInitDefinition = {
+ "type": "ugj_gesture_init",
+ "message0": "%{BKY_UGJ_GESTURE_INIT_TITLE}",
+ "args0": [
+ {
+ "type": "input_value",
+ "name": "i2c_addr",
+ "check": "Number"
+ }
+ ],
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_GESTURE_INIT_TOOLTIP}",
+ "helpUrl": "",
+ "style": "sensor_blocks"
+};
+Blockly.Blocks['ugj_gesture_init'] = {
+ init: function () {
+ this.jsonInit(ugjGestureInitDefinition);
+ }
+};
+Blockly.JavaScript['ugj_gesture_init'] = function (block) {
+ var value_i2c_addr = Blockly.JavaScript.valueToCode(block, 'i2c_addr', Blockly.JavaScript.ORDER_ATOMIC);
+ Blockly.JavaScript.provideFunction_(
+ 'require_gpio', [`const _pi = require('@ocogeclub/` + elutil.gpio_backend + `');`]
+ );
+ let modpath = elutil.path.join(elutil.blocks_sensors_dir, 'paj7620', 'PAJ7620x.js');
+ Blockly.JavaScript.provideFunction_(
+ 'require_paj7620', [`const _paj7620 = require('${modpath}');`]
+ );
+ var code = `await _paj7620.init(${elutil.i2c_bus}, ${value_i2c_addr}, window);
+ `;
+ return code;
+};
+
+/****************** */
+/** Gesture Read ** */
+/****************** */
+var ugjGestureReadDefinition = {
+ "type": "ugj_gesture_read",
+ "message0": "%{BKY_UGJ_GESTURE_READ_TITLE}",
+ "inputsInline": true,
+ "output": "Number",
+ "tooltip": "%{BKY_UGJ_GESTURE_READ_TOOLTIP}",
+ "helpUrl": "https://ocoge.club/sensors/paj7620.html",
+ "style": "sensor_blocks"
+};
+Blockly.Blocks['ugj_gesture_read'] = {
+ init: function () {
+ this.jsonInit(ugjGestureReadDefinition);
+ }
+};
+Blockly.JavaScript['ugj_gesture_read'] = function (block) {
+ var code = 'await _paj7620.return_gesture()';
+ return [code, Blockly.JavaScript.ORDER_ATOMIC];
+};
+/****************** */
+/** Gesture Stop ** */
+/****************** */
+var ugjGestureStopDefinition = {
+ "type": "ugj_gesture_stop",
+ "message0": "%{BKY_UGJ_GESTURE_STOP_TITLE}",
+ "inputsInline": true,
+ "previousStatement": null,
+ "nextStatement": null,
+ "tooltip": "%{BKY_UGJ_GESTURE_STOP_TOOLTIP}",
+ "helpUrl": "",
+ "style": "sensor_blocks"
+};
+Blockly.Blocks['ugj_gesture_stop'] = {
+ init: function () {
+ this.jsonInit(ugjGestureStopDefinition);
+ }
+};
+Blockly.JavaScript['ugj_gesture_stop'] = function (block) {
+ var code = 'await _paj7620.stop();\n';
+ return code;
+};
diff --git a/blocks/sensors/paj7620/index.json b/blocks/sensors/paj7620/index.json
new file mode 100644
index 0000000..fdf9602
--- /dev/null
+++ b/blocks/sensors/paj7620/index.json
@@ -0,0 +1,37 @@
+[
+ {
+ "kind": "label",
+ "text": "ジェスチャーセンサー PAJ7620",
+ "web-line": "4.0",
+ "web-line-width": "200"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_gesture_init",
+ "inputs": {
+ "i2c_addr": {
+ "shadow": {
+ "type": "ugj_hextodec",
+ "inputs": {
+ "hex": {
+ "shadow": {
+ "type": "text",
+ "fields": {
+ "TEXT": "73"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "kind": "block",
+ "type": "ugj_gesture_read"
+ },
+ {
+ "kind": "block",
+ "type": "ugj_gesture_stop"
+ }
+]
\ No newline at end of file
diff --git a/index.js b/index.js
index 9231916..4467728 100644
--- a/index.js
+++ b/index.js
@@ -372,14 +372,55 @@ const ugj_createCode = (args) => {
}
// ブロックスクリプト実行
+// var is_running = false;
+// var worker;
+// const ugj_runCode = async () => {
+// const {
+// Worker,
+// isMainThread,
+// setEnvironmentData,
+// getEnvironmentData,
+// } = require('worker_threads');
+// const stop_icon = ` 停止`;
+// const run_icon = ` 実行`;
+// document.activeElement.blur(); //実行ボタンからフォーカスを外す:エンターキー押下が悪さをするため
+
+// let btnel = document.getElementById('runbtn');
+// if (is_running) {
+// worker.terminate();
+// } else {
+// if (isMainThread) {
+// btnel.innerHTML = stop_icon;
+// let code = ugj_createCode({});
+// setEnvironmentData('code', code);
+// worker = new Worker(__filename);
+// // worker.on('exit', (excode) => {
+// // btnel.innerHTML = run_icon;
+// // });
+// // } else {
+// // let AsyncFunction = Object.getPrototypeOf(async function () { }).constructor;
+// // let ocogeFunc = new AsyncFunction(getEnvironmentData('code'));
+// // await ocogeFunc().catch(e => { console.error(e); });
+// }
+// }
+
+// is_running = !is_running;
+// if (is_running) btnel.innerHTML = stop_icon;
+// else btnel.innerHTML = run_icon;
+
+
+// }
const ugj_runCode = async () => {
document.activeElement.blur(); //実行ボタンからフォーカスを外す:エンターキー押下が悪さをするため
+ let btnel = document.getElementById('runbtn');
+ btnel.disabled = true;
// let code = ugj_createCode({ 'async': true });
// await eval(code).catch(e => { alert(e); });
let AsyncFunction = Object.getPrototypeOf(async function () { }).constructor
let ocogeFunc = new AsyncFunction(ugj_createCode({}));
await ocogeFunc().catch(e => { window.alert(e); });
console.log('Code Execution done.');
+ btnel.disabled = false;
}
// コードをダイアログで表示・保存
@@ -413,7 +454,7 @@ const ugj_showCode = () => {
// document... と ugj_... と elutil... をコメントアウト(ブラウザ関連部分の追放という意味では不完全なので注意)
// あと正規表現もいい加減
if (chkbox_cli.checked && ext == 'js')
- code = code.replace(/const appendDiv[^#]*\/\/#/gm, 'const blackboardWrite = text => console.log(text);').replace('window.alert', 'console.log').replace(/ugj_fukidashi(.*), \d+(\);)/gm, 'console.log$1$2').replace(/(^(?=.*document.)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*ugj_)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*elutil.)[^;]*;)/gm, '/* $1 */');
+ code = code.replace(/const appendDiv[^#]*\/\/#/gm, 'const blackboardWrite = text => console.log(text);').replace('window.alert', 'console.log').replace(/_fukidashi(.*), \d+(\);)/gm, 'console.log$1$2').replace(/(^(?=.*document.)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*ugj_)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*elutil.)[^;]*;)/gm, '/* $1 */');
if (elutil.saveFile(code, ext) === false) {
window.alert('保存できませんでした。');
}
@@ -439,7 +480,7 @@ const ugj_showCode = () => {
// フキダシ
let ugj_fdTimeoutID = null;
let ugj_fdRecentBox = null;
-const ugj_fukidashi = (text, sec) => {
+const _fukidashi = (text, sec) => {
// Canvas Context
const context = document.getElementById('canvas').getContext('2d');
// 吹き出しを消去する関数
@@ -628,34 +669,10 @@ window.onload = () => {
// 背景canvas
ugj_canvasBgImg(elutil.getMascotFilePath(), -1, -1);
}
-window.onbeforeunload = () => {
+window.addEventListener('beforeunload', () => {
+ // window.onbeforeunload = () => {
ugj_saveWorkspace();
elutil.savePrefsToLS();
- elutil.killAllChildren();
elutil.cleanupGPIO();
-}
-
-// センサーブロック
-// ブロックデータ格納ディレクトリのリスト
-const allDirents = elutil.fs.readdirSync(elutil.blocks_sensors_dir, { withFileTypes: true });
-const blocks_list = allDirents.filter(dirent => dirent.isDirectory()).map(({ name }) => name);
-// センサーカテゴリのインスタンス
-var category_sensors = workspace.getToolbox().getToolboxItemById('category_sensors');
-var flyout_contents = []; // フライアウトのjsonのリスト
-for (const sensor_dir of blocks_list) { //ディレクトリ巡り
- if (sensor_dir.charAt(0) == '.') continue; //隠しディレクトリをスキップ
- // フライアウトのjsonを取得してパース、リストに追加
- let fname = elutil.path.join(elutil.blocks_sensors_dir, sensor_dir, 'index.json');
- let json_text = elutil.fs.readFileSync(fname);
- let obj = JSON.parse(json_text);
- flyout_contents = flyout_contents.concat(obj);
- // ブロック定義のスクリプト要素をbody要素の最後に追加
- fname = elutil.path.join(elutil.blocks_sensors_dir, sensor_dir, 'index.js');
- let script = document.createElement('script');
- script.type = 'text/javascript';
- script.src = fname;
- document.body.appendChild(script);
-}
-// センサーカテゴリのフライアウトをアップデート
-category_sensors.updateFlyoutContents(flyout_contents);
-
+ // }
+});
diff --git a/index_elutil.js b/index_elutil.js
index 2e1bdd7..57227c4 100644
--- a/index_elutil.js
+++ b/index_elutil.js
@@ -10,7 +10,7 @@ const ugj_const = {
library_dirname: 'lib',
document_root: 'Documents',
executable_path: '.ocogeclub/apps/',
- blocks_sensors_dir: '.ocogeclub/sensors/',
+ blocks_sensors_dir: 'blocks/sensors/',
localStorage_fname: 'ocoge.json',
error_ja_all: 'エラーが発生しました。\n『おこげ倶楽部』までお問い合わせください。',
pig: 'pigpio',
@@ -35,7 +35,9 @@ class elUtil {
this.doc_root = this.path.join(process.env["HOME"], ugj_const.document_root);
this.doc_current = this.path.join(process.env["HOME"], ugj_const.document_root);
this.executable_path = this.path.join(process.env["HOME"], ugj_const.executable_path);
- this.blocks_sensors_dir = this.path.join(process.env["HOME"], ugj_const.blocks_sensors_dir);
+ // this.blocks_sensors_dir = this.path.join(process.env["HOME"], ugj_const.blocks_sensors_dir);
+ const EventEmitter = require('events');
+ this.ugjEmitter = new EventEmitter();
}
// static init = async () => {
// return new elUtil(await elUtil.get_app_path());
@@ -45,6 +47,43 @@ class elUtil {
this.app_path = await this.ipcRenderer.invoke('get_app_path');
this.mascotFilePath = this.path.join(this.app_path, ugj_const.mascot_dirname, ugj_const.mascot_defname);
this.library_path = this.path.join(this.app_path, ugj_const.library_dirname);
+ this.blocks_sensors_dir = this.path.join(this.app_path, ugj_const.blocks_sensors_dir);
+ this.loadSensorblocks();
+ }
+
+ // センサーブロックのロード
+ loadSensorblocks() {
+ // ディレクトリの有無
+ if (!this.fs.existsSync(this.blocks_sensors_dir)) return;
+ // ブロックデータ格納ディレクトリのリスト
+ const allDirents = this.fs.readdirSync(this.blocks_sensors_dir, { withFileTypes: true });
+ const blocks_list = allDirents.filter(dirent => dirent.isDirectory()).map(({ name }) => name);
+ // センサーカテゴリのインスタンス
+ let category_sensors = workspace.getToolbox().getToolboxItemById('category_sensors');
+ let flyout_contents = []; // フライアウトのjsonのリスト
+ for (let sensor_dir of blocks_list) { //ディレクトリ巡り
+ if (sensor_dir.charAt(0) == '.') continue; //隠しディレクトリをスキップ
+ // フライアウトのjsonを取得してパース、リストに追加
+ let fname = this.path.join(this.blocks_sensors_dir, sensor_dir, 'index.json');
+ let json_text = this.fs.readFileSync(fname);
+ let obj = JSON.parse(json_text);
+ flyout_contents = flyout_contents.concat(obj);
+ // ブロック定義のスクリプト要素をbody要素の最後に追加
+ fname = this.path.join(this.blocks_sensors_dir, sensor_dir, 'index.js');
+ let script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = fname;
+ document.body.appendChild(script);
+ }
+ let lastline = [{
+ "kind": "label",
+ "text": " ",
+ "web-line": "4.0",
+ "web-line-width": "200"
+ }];
+ flyout_contents = flyout_contents.concat(lastline);
+ // センサーカテゴリのフライアウトをアップデート
+ category_sensors.updateFlyoutContents(flyout_contents);
}
@@ -200,24 +239,10 @@ class elUtil {
}
}
- // 子プロセス関連
- // 新しい子プロセスを作成し、配列に保存
- addChild(child) {
- this.children.push(child);
- }
- // 全ての子プロセスを殺し、配列をクリア
- killAllChildren() {
- this.children.forEach(function (child) {
- child.kill();
- });
- this.children = [];
- }
-
// GPIO 関連:リロードでGPIOをロックしたままハンドルを失うのを防ぐ
cleanupGPIO() {
+ // this.ugjEmitter.emit('device_stop');//デバイス停止イベント
require('@ocogeclub/' + this.gpio_backend).close_all_handle();
- // require('@ocogeclub/paj7620').stop();
- // require('@ocogeclub/amg8833').stop();
}
// 設定(保存ファイルパスと未保存フラグ)をローカルストレージに保存
@@ -318,6 +343,11 @@ class brUtil {
setWsChanged() { ; }
killAllChildren() { ; }
cleanupGPIO() { ; }
+ path = {
+ join: function (a = '', b = '', c = '', d = '', e = '') {
+ return a + b + c + d + e;
+ }
+ }
}
// Electron 動作 / ブラウザ動作自動判別
@@ -339,11 +369,11 @@ if (!is_el) {
var require = module_name => {
let block;
switch (module_name) {
- case '@tensorflow/tfjs-node':
+ case '@tensorflow/tfjs':
block = 'TensorFlow';
break;
- case '@vladmandic/face-api':
- block = 'Face-API';
+ case '@tensorflow-models/blazeface':
+ block = '顔認識';
break;
case 'axios':
block = 'URLを取得';
@@ -354,15 +384,6 @@ if (!is_el) {
case '@ocogeclub/pigpio':
block = 'GPIO';
break;
- case '@ocogeclub/bme280':
- block = 'BME280';
- break;
- case '@ocogeclub/amg8833':
- block = '赤外線アレイセンサ';
- break;
- case '@ocogeclub/paj7620':
- block = 'ジェスチャーセンサー';
- break;
case 'fs':
block = 'ファイル';
break;
diff --git a/package-lock.json b/package-lock.json
index 05419b2..57dd4dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,22 +1,21 @@
{
"name": "ocoge",
- "version": "0.1.5",
+ "version": "0.1.6",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ocoge",
- "version": "0.1.5",
+ "version": "0.1.6",
"license": "ISC",
"dependencies": {
- "@ocogeclub/amg8833": "file:local_modules/@ocogeclub/amg8833",
"@ocogeclub/pigpio": "file:local_modules/@ocogeclub/pigpio",
"@tensorflow-models/blazeface": "^0.0.7",
"@tensorflow-models/knn-classifier": "^1.2.2",
"@tensorflow-models/mobilenet": "^2.1.0",
"@tensorflow/tfjs": "^3.13.0",
"@tensorflow/tfjs-backend-wasm": "^3.13.0",
- "axios": "^0.25.0",
+ "axios": "^0.26.0",
"electron-squirrel-startup": "^1.0.0",
"nodemailer": "^6.7.2",
"tensorset": "^1.2.9"
@@ -27,12 +26,13 @@
"@electron-forge/maker-rpm": "^6.0.0-beta.63",
"@electron-forge/maker-squirrel": "6.0.0-beta.33",
"@electron-forge/maker-zip": "^6.0.0-beta.63",
- "electron": "^17.0.0",
+ "electron": "^17.1.0",
"electron-rebuild": "^3.2.7"
}
},
"local_modules/@ocogeclub/amg8833": {
"version": "0.0.1",
+ "extraneous": true,
"license": "MIT",
"dependencies": {
"@ocogeclub/pigpio": "file:../pigpio"
@@ -1420,10 +1420,6 @@
"node": ">=10"
}
},
- "node_modules/@ocogeclub/amg8833": {
- "resolved": "local_modules/@ocogeclub/amg8833",
- "link": true
- },
"node_modules/@ocogeclub/pigpio": {
"resolved": "local_modules/@ocogeclub/pigpio",
"link": true
@@ -1959,11 +1955,11 @@
"dev": true
},
"node_modules/axios": {
- "version": "0.25.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
- "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
+ "version": "0.26.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
+ "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
"dependencies": {
- "follow-redirects": "^1.14.7"
+ "follow-redirects": "^1.14.8"
}
},
"node_modules/balanced-match": {
@@ -2829,9 +2825,9 @@
}
},
"node_modules/electron": {
- "version": "17.0.0",
- "resolved": "https://registry.npmjs.org/electron/-/electron-17.0.0.tgz",
- "integrity": "sha512-3UXcBQMwbMWdPvGHaSdPMluHrd+/bc+K143MyvE5zVZ+S1XCHt4sau7dj6svJHns5llN0YG/c6h/vRfadIp8Zg==",
+ "version": "17.1.0",
+ "resolved": "https://registry.npmjs.org/electron/-/electron-17.1.0.tgz",
+ "integrity": "sha512-X/qdldmQ8lA15NmeraubWCTtMeTO8K9Ser0wtSCgOXVh53Sr1Ea0VQQ7Q9LuGgWRVz4qtr40cntuEdM8icdmTw==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -3708,6 +3704,7 @@
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+ "dev": true,
"optional": true,
"dependencies": {
"iconv-lite": "^0.6.2"
@@ -3717,6 +3714,7 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dev": true,
"optional": true,
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -6896,7 +6894,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "devOptional": true
+ "dev": true
},
"node_modules/seedrandom": {
"version": "2.4.3",
@@ -9169,12 +9167,6 @@
}
}
},
- "@ocogeclub/amg8833": {
- "version": "file:local_modules/@ocogeclub/amg8833",
- "requires": {
- "@ocogeclub/pigpio": "file:../pigpio"
- }
- },
"@ocogeclub/pigpio": {
"version": "file:local_modules/@ocogeclub/pigpio",
"requires": {
@@ -9207,20 +9199,17 @@
"@tensorflow-models/blazeface": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/@tensorflow-models/blazeface/-/blazeface-0.0.7.tgz",
- "integrity": "sha512-+hInPkvHJoubfiXlmNuF3SCucZvU6W1PMC25IV99NSAftJUpKvLokfF93iX8UkOFQCXkPFbnLKacGfGlbjgvMw==",
- "requires": {}
+ "integrity": "sha512-+hInPkvHJoubfiXlmNuF3SCucZvU6W1PMC25IV99NSAftJUpKvLokfF93iX8UkOFQCXkPFbnLKacGfGlbjgvMw=="
},
"@tensorflow-models/knn-classifier": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@tensorflow-models/knn-classifier/-/knn-classifier-1.2.2.tgz",
- "integrity": "sha512-QRnkCf7ErOxSRtvJ6yCwhlLREPcBJGaXRanF46f0iY6ii3Sybjb6Ux0qnNPTrHZChD0izPa3Z4GQEgSAykiHkQ==",
- "requires": {}
+ "integrity": "sha512-QRnkCf7ErOxSRtvJ6yCwhlLREPcBJGaXRanF46f0iY6ii3Sybjb6Ux0qnNPTrHZChD0izPa3Z4GQEgSAykiHkQ=="
},
"@tensorflow-models/mobilenet": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@tensorflow-models/mobilenet/-/mobilenet-2.1.0.tgz",
- "integrity": "sha512-JjqT9ijHDFA2FEpUGWg7H2lQ0GrMuE2VmiCRBYmUew6b4JKht8LXDjG5HxZh95YH6c/25sZWTpGeHbquloH+hw==",
- "requires": {}
+ "integrity": "sha512-JjqT9ijHDFA2FEpUGWg7H2lQ0GrMuE2VmiCRBYmUew6b4JKht8LXDjG5HxZh95YH6c/25sZWTpGeHbquloH+hw=="
},
"@tensorflow/tfjs": {
"version": "3.13.0",
@@ -9274,8 +9263,7 @@
"@tensorflow/tfjs-converter": {
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-3.13.0.tgz",
- "integrity": "sha512-H2VpDTv9Ve0HBt7ttzz46DmnsPaiT0B+yJjVH3NebGZbgY9C8boBgJIsdyqfiqEWBS3WxF8h4rh58Hv5XXMgaQ==",
- "requires": {}
+ "integrity": "sha512-H2VpDTv9Ve0HBt7ttzz46DmnsPaiT0B+yJjVH3NebGZbgY9C8boBgJIsdyqfiqEWBS3WxF8h4rh58Hv5XXMgaQ=="
},
"@tensorflow/tfjs-core": {
"version": "3.13.0",
@@ -9303,8 +9291,7 @@
"@tensorflow/tfjs-layers": {
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-3.13.0.tgz",
- "integrity": "sha512-kTWJ/+9fbNCMDA9iQjDMYHmWivsiWz8CKNSOZdeCW7tiBwF1EiREBVQXMk1JI11ngQa8f+rYSLs7rkhp3SYl5Q==",
- "requires": {}
+ "integrity": "sha512-kTWJ/+9fbNCMDA9iQjDMYHmWivsiWz8CKNSOZdeCW7tiBwF1EiREBVQXMk1JI11ngQa8f+rYSLs7rkhp3SYl5Q=="
},
"@tootallnate/once": {
"version": "1.1.2",
@@ -9618,11 +9605,11 @@
"dev": true
},
"axios": {
- "version": "0.25.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
- "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
+ "version": "0.26.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
+ "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
"requires": {
- "follow-redirects": "^1.14.7"
+ "follow-redirects": "^1.14.8"
}
},
"balanced-match": {
@@ -10273,9 +10260,9 @@
}
},
"electron": {
- "version": "17.0.0",
- "resolved": "https://registry.npmjs.org/electron/-/electron-17.0.0.tgz",
- "integrity": "sha512-3UXcBQMwbMWdPvGHaSdPMluHrd+/bc+K143MyvE5zVZ+S1XCHt4sau7dj6svJHns5llN0YG/c6h/vRfadIp8Zg==",
+ "version": "17.1.0",
+ "resolved": "https://registry.npmjs.org/electron/-/electron-17.1.0.tgz",
+ "integrity": "sha512-X/qdldmQ8lA15NmeraubWCTtMeTO8K9Ser0wtSCgOXVh53Sr1Ea0VQQ7Q9LuGgWRVz4qtr40cntuEdM8icdmTw==",
"dev": true,
"requires": {
"@electron/get": "^1.13.0",
@@ -10948,6 +10935,7 @@
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+ "dev": true,
"optional": true,
"requires": {
"iconv-lite": "^0.6.2"
@@ -10957,6 +10945,7 @@
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dev": true,
"optional": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -13432,7 +13421,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "devOptional": true
+ "dev": true
},
"seedrandom": {
"version": "2.4.3",
@@ -13883,8 +13872,7 @@
"@tensorflow/tfjs-converter": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-converter/-/tfjs-converter-2.8.6.tgz",
- "integrity": "sha512-Uv4YC66qjVC9UwBxz0IeLZ8KS2CReh63WlGRtHcSwDEYiwsa7cvp9H6lFSSPT7kiJmrK6JtHeJGIVcTuNnSt9w==",
- "requires": {}
+ "integrity": "sha512-Uv4YC66qjVC9UwBxz0IeLZ8KS2CReh63WlGRtHcSwDEYiwsa7cvp9H6lFSSPT7kiJmrK6JtHeJGIVcTuNnSt9w=="
},
"@tensorflow/tfjs-core": {
"version": "2.8.6",
@@ -13910,8 +13898,7 @@
"@tensorflow/tfjs-layers": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-2.8.6.tgz",
- "integrity": "sha512-fdZ0i/R2dIKmy8OB5tBAsm5IbAHfJpI6AlbjxpgoU3aWj1HCdDo+pMji928MkDJhP01ISgFTgw/7PseGNaUflw==",
- "requires": {}
+ "integrity": "sha512-fdZ0i/R2dIKmy8OB5tBAsm5IbAHfJpI6AlbjxpgoU3aWj1HCdDo+pMji928MkDJhP01ISgFTgw/7PseGNaUflw=="
},
"@types/webgl2": {
"version": "0.0.5",
diff --git a/package.json b/package.json
index e5ebcfd..1f22d11 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ocoge",
- "version": "0.1.5",
+ "version": "0.1.6",
"description": "ブロックベースビジュアルプログラム開発・実行環境",
"main": "main.js",
"scripts": {
@@ -27,18 +27,17 @@
"@electron-forge/maker-rpm": "^6.0.0-beta.63",
"@electron-forge/maker-squirrel": "6.0.0-beta.33",
"@electron-forge/maker-zip": "^6.0.0-beta.63",
- "electron": "^17.0.0",
+ "electron": "^17.1.0",
"electron-rebuild": "^3.2.7"
},
"dependencies": {
- "@ocogeclub/amg8833": "file:local_modules/@ocogeclub/amg8833",
"@ocogeclub/pigpio": "file:local_modules/@ocogeclub/pigpio",
"@tensorflow-models/blazeface": "^0.0.7",
"@tensorflow-models/knn-classifier": "^1.2.2",
"@tensorflow-models/mobilenet": "^2.1.0",
"@tensorflow/tfjs": "^3.13.0",
"@tensorflow/tfjs-backend-wasm": "^3.13.0",
- "axios": "^0.25.0",
+ "axios": "^0.26.0",
"electron-squirrel-startup": "^1.0.0",
"nodemailer": "^6.7.2",
"tensorset": "^1.2.9"
diff --git a/ugj_blocks.js b/ugj_blocks.js
index 7594fa3..166cbf6 100644
--- a/ugj_blocks.js
+++ b/ugj_blocks.js
@@ -1174,7 +1174,7 @@ Blockly.JavaScript['ugj_canvas_say'] = function (block) {
var value_say = Blockly.JavaScript.valueToCode(block, 'say', Blockly.JavaScript.ORDER_ATOMIC);
var value_sec = Blockly.JavaScript.valueToCode(block, 'sec', Blockly.JavaScript.ORDER_ATOMIC);
var code = [
- `ugj_fukidashi(String(${value_say}), ${value_sec});`,
+ `_fukidashi(String(${value_say}), ${value_sec});`,
''
].join('\n');
return code;
@@ -1431,294 +1431,6 @@ Blockly.JavaScript['ugj_canvas_drawrect'] = function (block) {
return code;
};
-/***************************** */
-/** GridEye 表示キャンバス作成 ** */
-/***************************** */
-var ugjGridEyeCanvasCreateDefinition = {
- "type": "ugj_grideye_canvas_create",
- "message0": "%{BKY_UGJ_GRIDEYE_CANVAS_CREATE_TITLE}",
- "inputsInline": true,
- "previousStatement": null,
- "nextStatement": null,
- "tooltip": "%{BKY_UGJ_GRIDEYE_CANVAS_CREATE_TOOLTIP}",
- "helpUrl": "",
- "style": "multimedia_blocks"
-};
-Blockly.Blocks['ugj_grideye_canvas_create'] = {
- init: function () {
- this.jsonInit(ugjGridEyeCanvasCreateDefinition);
- }
-};
-Blockly.JavaScript['ugj_grideye_canvas_create'] = function (block) {
- var code = `let _grideye_canvas = document.createElement('canvas');
-_grideye_canvas.setAttribute('width', 8);
-_grideye_canvas.setAttribute('height', 8);
-_grideye_canvas.className = 'subdisplay';
-_grideye_canvas.style.width = '160px';
-_grideye_canvas.style.height = '160px';
-_grideye_canvas.id = 'subcanvas';
-document.getElementById('display_area').appendChild(_grideye_canvas);
-_grideye_ctx = _grideye_canvas.getContext('2d');
-_grideye_imgData = _grideye_ctx.createImageData(8, 8);
-`;
- return code;
-};
-/********************************************** */
-/** Draw IR Array Data to Image Data ** */
-/********************************************** */
-var ugjDrawGrideyedataDefinition = {
- "type": "ugj_draw_grideyedata",
- "message0": "%{BKY_UGJ_DRAW_GRIDEYEDATA_TITLE}",
- "args0": [
- {
- "type": "input_dummy"
- },
- {
- "type": "input_value",
- "name": "amg8833data",
- "check": "Array",
- "align": "RIGHT"
- },
- {
- "type": "field_colour",
- "name": "color_high",
- "colour": "#ff0000"
- },
- {
- "type": "input_value",
- "name": "temp_high",
- "check": "Number",
- "align": "RIGHT"
- },
- {
- "type": "field_colour",
- "name": "color_low",
- "colour": "#3333ff"
- },
- {
- "type": "input_value",
- "name": "temp_low",
- "check": "Number",
- "align": "RIGHT"
- }
- ],
- "inputsInline": false,
- "previousStatement": null,
- "nextStatement": null,
- "tooltip": "%{BKY_UGJ_DRAW_GRIDEYEDATA_TOOLTIP}",
- "helpUrl": "",
- "style": "multimedia_blocks"
-};
-Blockly.Blocks['ugj_draw_grideyedata'] = {
- init: function () {
- this.jsonInit(ugjDrawGrideyedataDefinition);
- }
-};
-Blockly.JavaScript['ugj_draw_grideyedata'] = function (block) {
- var value_amg8833data = Blockly.JavaScript.valueToCode(block, 'amg8833data', Blockly.JavaScript.ORDER_ATOMIC);
- var colour_color_high = block.getFieldValue('color_high');
- var value_temp_high = Blockly.JavaScript.valueToCode(block, 'temp_high', Blockly.JavaScript.ORDER_ATOMIC);
- var colour_color_low = block.getFieldValue('color_low');
- var value_temp_low = Blockly.JavaScript.valueToCode(block, 'temp_low', Blockly.JavaScript.ORDER_ATOMIC);
- var functionName = Blockly.JavaScript.provideFunction_(
- '_mapVal',
- ['const ' + Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_ + ' = (val, inMin, inMax, outMin, outMax) => {',
- `return (val - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;`,
- '}'
- ]
- );
- // 温度カラー
- let hr, hg, hb, lr, lg, lb;
- hr = '0x' + colour_color_high.slice(1, 3);
- hg = '0x' + colour_color_high.slice(3, 5);
- hb = '0x' + colour_color_high.slice(5, 7);
- lr = '0x' + colour_color_low.slice(1, 3);
- lg = '0x' + colour_color_low.slice(3, 5);
- lb = '0x' + colour_color_low.slice(5, 7);
- var code = ` const _color_range = [[${lr}, ${hr}], [${lg}, ${hg}], [${lb}, ${hb}]];
- let _grideye_data = ${value_amg8833data};//読み取りブロックを入力に直接接続できるようにする
- for (let raw = 0; raw < _grideye_canvas.height; raw++) {
- for (let col = 0; col < _grideye_canvas.width; col++) {
- for (let rgb = 0; rgb < 3; rgb++) {
- let pixel = ${functionName}(_grideye_data[raw][col], ${value_temp_low}, ${value_temp_high}, _color_range[rgb][0], _color_range[rgb][1]);
- _grideye_imgData.data[((raw * _grideye_canvas.width * 4) + col * 4) + rgb] = pixel;
- }
- _grideye_imgData.data[((raw * _grideye_canvas.width * 4) + col * 4) + 3] = 0xff;
- }
- }
- _grideye_ctx.putImageData(_grideye_imgData, 0, 0);
-
-`;
- return code;
-};
-
-/**************************** */
-/** Teachable Machine を開始** */
-/**************************** */
-var ugjTeachableMachineDefinition = {
- "type": "ugj_teachable_machine",
- "message0": "%{BKY_UGJ_TEACHABLE_MACHINE_TITLE}",
- "inputsInline": true,
- "previousStatement": null,
- "nextStatement": null,
- "tooltip": "%{BKY_UGJ_TEACHABLE_MACHINE_TOOLTIP}",
- "helpUrl": "",
- "style": "multimedia_blocks"
-};
-Blockly.Blocks['ugj_teachable_machine'] = {
- init: function () {
- this.jsonInit(ugjTeachableMachineDefinition);
- }
-};
-Blockly.JavaScript['ugj_teachable_machine'] = function (block) {
- Blockly.JavaScript.provideFunction_(
- 'require_ts', [`const _tf = require('@tensorflow/tfjs');`]
- // 'require_ts', [`const _tf = require('@tensorflow/tfjs-node');`]
- );
- Blockly.JavaScript.provideFunction_(
- 'require_wasm', [`const _wasm = require('@tensorflow/tfjs-backend-wasm');`]
- );
- Blockly.JavaScript.provideFunction_(
- 'require_mobilenet', [`const _mobilenet = require('@tensorflow-models/mobilenet');`]
- );
- Blockly.JavaScript.provideFunction_(
- 'require_knn', [`const _knnClassifier = require('@tensorflow-models/knn-classifier');`]
- );
-
- var code = `await _tf.setBackend('wasm');
- const _net = await _mobilenet.load({ version: 1, alpha: 0.25 }); // 高速・低精度
- const _classifier = _knnClassifier.create();
- `;
- return code;
-};
-/************************* */
-/** GridEye で推論を行う ** */
-/************************* */
-var ugjGridEyePredictClassDefinition = {
- "type": "ugj_grideye_predict_class",
- "message0": "%{BKY_UGJ_GRIDEYE_PREDICT_CLASS_TITLE}",
- "inputsInline": true,
- "output": "Number",
- "tooltip": "%{BKY_UGJ_GRIDEYE_PREDICT_CLASS_TOOLTIP}",
- "helpUrl": "",
- "style": "multimedia_blocks"
-};
-Blockly.Blocks['ugj_grideye_predict_class'] = {
- init: function () {
- this.jsonInit(ugjGridEyePredictClassDefinition);
- }
-};
-Blockly.JavaScript['ugj_grideye_predict_class'] = function (block) {
- var functionName = Blockly.JavaScript.provideFunction_( // left output にするための関数化
- '_predictClass',
- [
- `if (_confidence === undefined) var _confidence;`,
- `const ${Blockly.JavaScript.FUNCTION_NAME_PLACEHOLDER_} = async (img, clsfr, mblnet) => {`,
- `if (clsfr.getNumClasses() > 0) {`,
- `const result = await clsfr.predictClass(mblnet.infer(img, 'conv_preds'));`,
- `_confidence = result.confidences[result.label];`,
- `return result.label;`,
- `}`,
- `else return 0;`,
- `}`
- ]
- );
- var code = `await ${functionName}(_grideye_canvas, _classifier, _net)`;
- return [code, Blockly.JavaScript.ORDER_NONE];
-};
-/******************************************** */
-/** ラベルをつけて Example をデータセットに追加 ** */
-/******************************************** */
-var ugjGridEyeAddExampleDefinition = {
- "type": "ugj_grideye_add_example",
- "message0": "%{BKY_UGJ_GRIDEYE_ADD_EXAMPLE_TITLE}",
- "args0": [
- {
- "type": "input_value",
- "name": "class_id",
- "check": "Number"
- }
- ],
- "inputsInline": true,
- "previousStatement": null,
- "nextStatement": null,
- "tooltip": "%{BKY_UGJ_GRIDEYE_ADD_EXAMPLE_TOOLTIP}",
- "helpUrl": "",
- "style": "multimedia_blocks"
-};
-Blockly.Blocks['ugj_grideye_add_example'] = {
- init: function () {
- this.jsonInit(ugjGridEyeAddExampleDefinition);
- }
-};
-Blockly.JavaScript['ugj_grideye_add_example'] = function (block) {
- var value_class_id = Blockly.JavaScript.valueToCode(block, 'class_id', Blockly.JavaScript.ORDER_ATOMIC);
- var code = `_classifier.addExample (_net.infer(_grideye_canvas, true), ${value_class_id});`;
- return code;
-};
-/*************************** */
-/** 学習したクラスを文字列化 ** */
-/*************************** */
-var ugjTensorsetStringifyDefinition = {
- "type": "ugj_tensorset_stringify",
- "message0": "%{BKY_UGJ_TENSORSET_STRINGIFY_TITLE}",
- "output": null,
- "tooltip": "%{BKY_UGJ_TENSORSET_STRINGIFY_TOOLTIP}",
- "helpUrl": "",
- "style": "multimedia_blocks"
-};
-Blockly.Blocks['ugj_tensorset_stringify'] = {
- init: function () {
- this.jsonInit(ugjTensorsetStringifyDefinition);
- }
-};
-Blockly.JavaScript['ugj_tensorset_stringify'] = function (block) {
- Blockly.JavaScript.provideFunction_(
- 'require_tensorset', [`const _Tensorset = require('tensorset');`]
- );
- var code = `await _Tensorset.stringify(_classifier.getClassifierDataset())`;
- return [code, Blockly.JavaScript.ORDER_NONE];
-};
-/***************************************** */
-/** jsonをデータセットに戻して分類器にセット ** */
-/***************************************** */
-var ugjTensorsetParseDefinition = {
- "type": "ugj_tensorset_parse",
- "message0": "%{BKY_UGJ_TENSORSET_PARSE_TITLE}",
- "args0": [
- {
- "type": "input_value",
- "name": "class_data_json",
- "check": "String"
- }
- ],
- "previousStatement": null,
- "nextStatement": null,
- "tooltip": "%{BKY_UGJ_TENSORSET_PARSE_TOOLTIP}",
- "helpUrl": "",
- "style": "multimedia_blocks"
-};
-Blockly.Blocks['ugj_tensorset_parse'] = {
- init: function () {
- this.jsonInit(ugjTensorsetParseDefinition);
- }
-};
-Blockly.JavaScript['ugj_tensorset_parse'] = function (block) {
- Blockly.JavaScript.provideFunction_(
- 'require_tensorset', [`const _Tensorset = require('tensorset');`]
- );
- var value_class_data_json = Blockly.JavaScript.valueToCode(block, 'class_data_json', Blockly.JavaScript.ORDER_ATOMIC);
- var code = `try {
- let _class_dataset = _Tensorset.parse(${value_class_data_json});
- _classifier.setClassifierDataset(_class_dataset);
- } catch (error) {
- alert('Could not load class dataset.');
- }
-`;
- return code;
-};
-
-
/****************************** */
/** KeyUpDown Event Listener ** */
/****************************** */
@@ -2415,7 +2127,7 @@ Blockly.JavaScript['ugj_event_answer'] = function (block) {
// var variable_answer = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('answer'), Blockly.Variables.NAME_TYPE);
var statements_do = Blockly.JavaScript.statementToCode(block, 'do');
var code = [
- `ugj_fukidashi(${value_question}, 0);`,
+ `_fukidashi(${value_question}, 0);`,
`_inputForm = document.getElementById('inputForm');`,
`_inputBox = document.getElementById('inputBox');`,
"_inputForm.style.display = 'inline-block'",
@@ -2493,18 +2205,16 @@ Blockly.Blocks['ugj_spawn'] = {
Blockly.JavaScript['ugj_spawn'] = function (block) {
var value_childprocess = Blockly.JavaScript.valueToCode(block, 'childprocess', Blockly.JavaScript.ORDER_NONE);
var value_data = Blockly.JavaScript.valueToCode(block, 'data', Blockly.JavaScript.ORDER_ATOMIC);
- // var variable_data = Blockly.JavaScript.nameDB_.getName(block.getFieldValue('data'), Blockly.Variables.NAME_TYPE);
var statements_do = Blockly.JavaScript.statementToCode(block, 'do');
+
var code = [
`let _child = require('child_process').spawn(${value_childprocess});`,
- `elutil.addChild(_child);`,
"_child.stderr.on('data', _data => { console.error(_data.toString()) })",
"_child.stdout.on('data', async _data => {",
`${value_data} = _data.toString();`,
statements_do,
"})",
- "_child.on('close', (_code, _signal) => { if (_code !== 0) { console.error(`process exited with code ${_code}, signal ${_signal}`)}",
- "})",
+ `window.addEventListener( 'beforeunload', function() { _child.kill() }, false );`,
''
].join("\n");
return code;