chao 2 months ago
parent
commit
71da41ef6e

+ 38 - 14
package-lock.json

@@ -45,6 +45,7 @@
         "antd": "^5.6.4",
         "axios": "^1.8.4",
         "blockly": "^10.3.0",
+        "caniuse-lite": "^1.0.30001731",
         "comlink": "^4.4.1",
         "i18next": "^25.0.1",
         "immer": "^10.0.2",
@@ -62,7 +63,8 @@
         "redux": "^4.2.1",
         "typescript": "^4.9.5",
         "web-vitals": "^2.1.4",
-        "xterm": "^5.2.1",
+        "xterm": "^5.3.0",
+        "xterm-addon-attach": "^0.9.0",
         "xterm-addon-fit": "^0.7.0",
         "xterm-addon-search": "^0.12.0",
         "xterm-addon-webgl": "^0.15.0"
@@ -7039,6 +7041,7 @@
       "version": "10.3.0",
       "resolved": "https://registry.npmjs.org/blockly/-/blockly-10.3.0.tgz",
       "integrity": "sha512-+95241EVK5o80F3b/iDP61+LfwKwueqscRyh/JfGKPRA4Tlcg8nngu1DdMhOyVCy8Z58AyXuFJ+96+QlCFx5MQ==",
+      "license": "Apache-2.0",
       "dependencies": {
         "jsdom": "22.1.0"
       }
@@ -7524,9 +7527,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001514",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001514.tgz",
-      "integrity": "sha512-ENcIpYBmwAAOm/V2cXgM7rZUrKKaqisZl4ZAI520FIkqGXUxJjmaIssbRW5HVVR5tyV6ygTLIm15aU8LUmQSaQ==",
+      "version": "1.0.30001731",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
+      "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==",
       "funding": [
         {
           "type": "opencollective",
@@ -7540,7 +7543,8 @@
           "type": "github",
           "url": "https://github.com/sponsors/ai"
         }
-      ]
+      ],
+      "license": "CC-BY-4.0"
     },
     "node_modules/case-sensitive-paths-webpack-plugin": {
       "version": "2.4.0",
@@ -23047,14 +23051,28 @@
       "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
     },
     "node_modules/xterm": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.2.1.tgz",
-      "integrity": "sha512-cs5Y1fFevgcdoh2hJROMVIWwoBHD80P1fIP79gopLHJIE4kTzzblanoivxTiQ4+92YM9IxS36H1q0MxIJXQBcA=="
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz",
+      "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==",
+      "deprecated": "This package is now deprecated. Move to @xterm/xterm instead.",
+      "license": "MIT"
+    },
+    "node_modules/xterm-addon-attach": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/xterm-addon-attach/-/xterm-addon-attach-0.9.0.tgz",
+      "integrity": "sha512-NykWWOsobVZPPK3P9eFkItrnBK9Lw0f94uey5zhqIVB1bhswdVBfl+uziEzSOhe2h0rT9wD0wOeAYsdSXeavPw==",
+      "deprecated": "This package is now deprecated. Move to @xterm/addon-attach instead.",
+      "license": "MIT",
+      "peerDependencies": {
+        "xterm": "^5.0.0"
+      }
     },
     "node_modules/xterm-addon-fit": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.7.0.tgz",
       "integrity": "sha512-tQgHGoHqRTgeROPnvmtEJywLKoC/V9eNs4bLLz7iyJr1aW/QFzRwfd3MGiJ6odJd9xEfxcW36/xRU47JkD5NKQ==",
+      "deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.",
+      "license": "MIT",
       "peerDependencies": {
         "xterm": "^5.0.0"
       }
@@ -28071,9 +28089,9 @@
       }
     },
     "caniuse-lite": {
-      "version": "1.0.30001514",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001514.tgz",
-      "integrity": "sha512-ENcIpYBmwAAOm/V2cXgM7rZUrKKaqisZl4ZAI520FIkqGXUxJjmaIssbRW5HVVR5tyV6ygTLIm15aU8LUmQSaQ=="
+      "version": "1.0.30001731",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
+      "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg=="
     },
     "case-sensitive-paths-webpack-plugin": {
       "version": "2.4.0",
@@ -38889,9 +38907,15 @@
       "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
     },
     "xterm": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.2.1.tgz",
-      "integrity": "sha512-cs5Y1fFevgcdoh2hJROMVIWwoBHD80P1fIP79gopLHJIE4kTzzblanoivxTiQ4+92YM9IxS36H1q0MxIJXQBcA=="
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz",
+      "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg=="
+    },
+    "xterm-addon-attach": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/xterm-addon-attach/-/xterm-addon-attach-0.9.0.tgz",
+      "integrity": "sha512-NykWWOsobVZPPK3P9eFkItrnBK9Lw0f94uey5zhqIVB1bhswdVBfl+uziEzSOhe2h0rT9wD0wOeAYsdSXeavPw==",
+      "requires": {}
     },
     "xterm-addon-fit": {
       "version": "0.7.0",

+ 4 - 1
package.json

@@ -6,6 +6,7 @@
   },
   "version": "0.1.0",
   "private": true,
+  "proxy": "http://192.168.0.176:8888",
   "dependencies": {
     "@ant-design/icons": "^6.0.0",
     "@blockly/field-date": "^9.0.7",
@@ -44,6 +45,7 @@
     "antd": "^5.6.4",
     "axios": "^1.8.4",
     "blockly": "^10.3.0",
+    "caniuse-lite": "^1.0.30001731",
     "comlink": "^4.4.1",
     "i18next": "^25.0.1",
     "immer": "^10.0.2",
@@ -61,7 +63,8 @@
     "redux": "^4.2.1",
     "typescript": "^4.9.5",
     "web-vitals": "^2.1.4",
-    "xterm": "^5.2.1",
+    "xterm": "^5.3.0",
+    "xterm-addon-attach": "^0.9.0",
     "xterm-addon-fit": "^0.7.0",
     "xterm-addon-search": "^0.12.0",
     "xterm-addon-webgl": "^0.15.0"

+ 40 - 1
src/Blockly/BlocklyComponent.css

@@ -3,12 +3,17 @@
   width: 100%;
 }
 
+.blocklyTreeIconOpen,
+.blocklyTreeIconClosed {
+  opacity: 0;
+}
 
 .blocklyTreeRow {
   height: 40px;
   line-height: 40px;
   padding: 0px 16px 0px 0px;
   text-align: left;
+  margin-bottom: 1px;
 }
 
 .blocklyToolboxDiv {
@@ -22,6 +27,40 @@
   padding: 0px 0px 0px 0px !important;
   background: rgba(236, 241, 247, 0.8) !important;
 }
-.blocklyScrollbarHorizontal, .blocklyScrollbarVertical{
+
+.blocklyScrollbarHorizontal,
+.blocklyScrollbarVertical {
   left: 0px !important;
+}
+
+.blocklyToolboxContents>div:nth-child(15) {
+  margin-top: 10px;
+}
+
+.blocklyToolboxContents>div:nth-child(15)>div:nth-child(1) {
+  background-color: rgb(49, 99, 237);
+  color: white;
+}
+
+.blocklyToolboxContents>div:nth-child(16)>div:nth-child(1) {
+  background-color: #2fc67b;
+  color: white;
+}
+
+.blocklyToolboxContents>div:nth-child(17)>div:nth-child(1) {
+  background-color: #ee783a;
+  color: white;
+}
+
+.blocklyToolboxContents>div:nth-child(18)>div:nth-child(1) {
+  background-color: #7e3cca;
+  color: white;
+}
+
+.blocklyToolboxContents>div:nth-child(n+16) {
+  margin-top: 3px;
+}
+
+.blocklyToolboxContents {
+  margin-top: -1px;
 }

+ 802 - 4
src/Blockly/blocklyXml.js

@@ -658,11 +658,809 @@ export default `<xml  style="height: 100%">
             </value>
           </block>
         </category>
-        <category id="catMainBoard" name="Main Board" colour="#3163ed">
-          <category id="time" name="Basics" colour="#d42b03">
+        <category id="catBasicFunctions" name="基础功能" colour="#3163ed">
+          <category id="catBasic" name="Basics" colour="#d42b03">
+            <label id="basis_button" text="Basis button" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_v831_button_read_pressed"></block>
+            <block type="ai_v831_button_read_released"></block>
+            <label id="catFASTLED" text="灯光" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_v831_led_light_up"></block>
+            <block type="ai_v831_led_light_off"></block>
+            <label id="rgb_light" text="RGB灯光" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_v831_rgb_light_up">
+              <value name="rgb_value">'
+                <block type="ai_lcd_rgb_value_input">'
+                  <value name="rgb_value_r">'
+                    <shadow type="math_number">'
+                      <field name="NUM">0</field>'
+                    </shadow>'
+                  </value>'
+                  <value name="rgb_value_g">'
+                    <shadow type="math_number">'
+                      <field name="NUM">0</field>'
+                    </shadow>'
+                  </value>'
+                  <value name="rgb_value_b">'
+                    <shadow type="math_number">'
+                      <field name="NUM">0</field>'
+                    </shadow>'
+                  </value>'
+                </block>'
+              </value>'
+            </block>
+            <block type="ai_v831_rgb_light_off"></block>
+          </category>
+          <category id="catSensors" name="传感器" colour="#5fcd8e">
+            <label id="basis_light" text="光照传感器" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="esp32_main_controller_get_light"></block>
+            <label id="basis_environmental" text="温湿度传感器" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="esp32_main_controller_get_environmental_value"></block>
+            <label id="" text="QMI8658" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="esp32_main_controller_motion_acceleration"></block>
+            <block type="esp32_main_controller_motion_rotation_measurement"></block>
+            <block type="esp32_main_controller_motion_tilt_angle"></block>
           </category>
-          <category id="catBasics" name="Basics" colour="#d42b03">
+          <category id="catPower" name="动力" colour="#386dc8">
+            <label id="catServo" text="舵机" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="extension_servo_setup_on_ai"></block>
+            <block type="extension_servo_write_on_ai">
+              <value name="degree">
+                <shadow type="math_number">
+                  <field name="NUM">90</field>
+                </shadow>
+              </value>
+            </block>
+
+            <label id="catMOTOR" text="电机" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_motor_setup"></block>
+            <block type="ai_motor_run">
+              <value name="speed">
+                <shadow type="math_number">
+                  <field name="NUM">150</field>
+                </shadow>
+              </value>
+            </block>
+          </category>
+          <category id="catAIScreen" name="Screen" colour="#5cb2d6">
+            <label id="catBasicFunctions" text="Basis function" web-class="myLabelStyle" style="font-size:20px;"></label><label id="catLCD" text="LCD" web-class="myLabelStyle" style="font-size:20px;"></label>
+            
+            <block type="ai_lcd_font">
+              <value name="save_path">
+                    <shadow type="text">
+                        <field name="TEXT">/root/preset/fonts/CascadiaCodePL-Italic.ttf</field>
+                    </shadow>
+              </value>
+            </block>
+            <label id="basis_carvas_draw" text="Basis carvas drawing" web-class="myLabelStyle" style="font-size:20px;"></label>
+            
+            <block type="ai_lcd_fill_screen_with_rgb">
+              <value name="rgb_value">
+                <block type="ai_lcd_rgb_value_input">
+                  <value name="rgb_value_r">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="rgb_value_g">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                  </shadow>
+                  </value>
+                  <value name="rgb_value_b">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+            </block>
+            <block type="ai_lcd_textcarvas">
+              <value name="POSA">
+                <block type="lcd_set_position">
+                  <value name="POSX">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="POSY">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+              <value name="CONTENT">
+                <shadow type="text">
+                  <field name="TEXT"></field>
+                </shadow>
+              </value>
+              <value name="COLOR">
+                <block type="lcd_set_color">
+                </block>
+              </value>
+              <value name="Scale">
+                <shadow type="math_number">
+                  <field name="NUM">1</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="ai_lcd_linecarvas">
+              <value name="POSA">
+                <block type="lcd_set_position">
+                  <value name="POSX">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="POSY">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+              <value name="POSB">
+                <block type="lcd_set_position">
+                  <value name="POSX">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="POSY">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+              <value name="COLOR">
+                <block type="lcd_set_color"></block>
+              </value>
+              <value name="Scale">
+                <shadow type="math_number">
+                  <field name="NUM">1</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="ai_lcd_draw_rectangle">
+              <value name="POSA">
+                <block type="lcd_set_position">
+                  <value name="POSX">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="POSY">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+              <value name="POSB">
+                <block type="lcd_set_width_height">
+              <value name="WIDTH">
+                <shadow type="math_number">
+                  <field name="NUM">320</field>
+                </shadow>
+              </value>
+              <value name="HEIGHT">
+                <shadow type="math_number">
+                  <field name="NUM">240</field>
+                </shadow>
+              </value>
+                </block>
+              </value>
+              <value name="COLOR">
+                <block type="lcd_set_color"></block>
+              </value>
+              <value name="Scale">
+                <shadow type="math_number">
+                  <field name="NUM">1</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="ai_lcd_drawcirclecarvas">
+              <value name="POSA">
+                <block type="lcd_set_position">
+                  <value name="POSX">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="POSY">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+              <value name="Scale">
+                <shadow type="math_number">
+                  <field name="NUM">2</field>
+                </shadow>
+              </value>
+              <value name="COLOR">
+                <block type="lcd_set_color">
+                </block>
+              </value>
+              <value name="Scale_0">
+                <shadow type="math_number">
+                  <field name="NUM">1</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="ai_lcd_draw_image_on_canvas">
+              <value name="image_path">
+                   <block type="v831_img_open">
+                       <value name="save_path">
+                           <shadow type="text">
+                               <field name="TEXT">/root/user/img/saved.jpg</field>
+                           </shadow>
+                       </value>
+                   </block>
+              </value>
+              <value name="scale_y">
+                <block type="lcd_set_position">
+                  <value name="POSX">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="POSY">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+            </block>
+            <block type="ai_lcd_showcarvas_set_display"></block>
+            <block type="ai_lcd_clearcanvas"></block>
+          </category>
+          <category id="catCamera" name="摄像头" colour="#60c1bb">
+            <block type="ai_camera_windows"></block>
+            <block type="ai_camera_image_property_change"></block>
+            <block type="ai_camera_snapshot"></block>
+            <block type="v831_camera_graph_transmission"></block>
+          </category>
+          <category id="catMicrophone" name="Camera" colour="#5fcd8e">
+            <label id="catMicrophone" text="麦克风" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_mphone_record_init"></block>
+            <block type="ai_mphone_record_setting">' +
+              <value name="PATH">
+                <shadow type="text">
+                  <field name="TEXT">/root/user/audio/record.wav</field>
+                </shadow>
+              </value>
+              <value name="record_time">
+                <shadow type="math_number">
+                  <field name="NUM">4</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="ai_mphone_Record_audio_start"></block>
+            <block type="ai_mphone_Record_audio_sound_loudness_analysis"></block>
+            <block type="mphone_audio_spectrum_init"></block>
+            <block type="ai_mphone_read_sound_sensitivity">
+          </category>
+          <category id="catSpeaker" name="扬声器" colour="#603ea0">
+            <block type="ai_speaker_play_wav">
+              <value name="PATH">
+                <shadow type="text">
+                  <field name="TEXT">/root/user/audio/record.wav</field>
+                </shadow>
+              </value>  
+            </block>
+            <block type="set_volume">
+              <value name="VOLUME">
+                <shadow type="math_number">
+                  <field name="NUM">50</field>
+                </shadow>
+              </value>
+            </block>
+          </category>
+          <category id="catSystem" name="系统功能" colour="#22398e">
+            <block type="system_poweroff"></block>
+            <block type="system_reboot"></block>
+            <block type="system_get_cpu_temperature"></block>
+            <block type="system_set_thread1">
+              <block type="procedures_callNothirdreturn">
+                <mutation name="system_set_thread1"></mutation>
+                <value name="ARG0">
+                  <block type="math_number">
+                    <field name="NUM">1000</field>
+                  </block>
+                </value>
+              </block>
+            </block>
+            <block type="system_start_thread"></block>
+          </category>
+        </category>
+        <category id="ExtendedFunction" name="媒体处理" colour="#2fc67b">
+          <category id="catImage" name="图像处理" colour="#f2a247">
+            <label id="basis_function" text="Basis function" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="image_save">
+              <value name="save_path">
+                <shadow type="text">
+                  <field name="TEXT">/root/user/img/saved.jpg</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="image_open">
+              <value name="save_path">
+                <shadow type="text">
+                  <field name="TEXT">/root/user/img/saved.jpg</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="image_rotating">
+              <value name="route">
+                <shadow type="math_number">
+                  <field name="NUM">90</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="image_crop">
+              <value name="xy">
+                <block type="ai_lcd_XY_vision">
+                  <value name="A">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="B">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+              <value name="wh">
+                <block type="ai_lcd_WH_vision">
+                  <value name="A">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="B">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+            </block>
+            <block type="image_resize">
+              <value name="wh">
+                <block type="ai_lcd_WH_vision">
+                  <value name="A">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="B">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+            </block>
+            <block type="image_find_blobs">
+              <value name="color">
+                <block type="ai_vision_get_threshold_default"></block>
+              </value>
+              <value name="xy">
+                <block type="ai_lcd_XY_vision">
+                  <value name="A">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="B">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+              <value name="wh">
+                <block type="ai_lcd_WH_vision">
+                  <value name="A">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="B">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+            </block>
+            <block type="ai_vision_get_blobs"></block>
+            <block type="image_find_lines">
+              <value name="color">
+                <block type="ai_vision_get_threshold_default"></block>
+              </value>
+              <value name="xy">
+                <block type="ai_lcd_XY_vision">
+                  <value name="A">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="B">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+              <value name="wh">
+                <block type="ai_lcd_WH_vision">
+                  <value name="A">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                  <value name="B">
+                    <shadow type="math_number">
+                      <field name="NUM">0</field>
+                    </shadow>
+                  </value>
+                </block>
+              </value>
+            </block>
+            <block type="image_get_lines_result"></block>
+            <block type="ai_lane_tracking_setup">
+              <value name="color">
+                <block type="ai_vision_get_threshold_default"></block>
+              </value>
+              <value name="lsize">
+                <block type="ai_canvas_area_tuple">
+                  <value name="xy">
+                    <block type="ai_lcd_XY_vision">
+                      <value name="A">
+                        <shadow type="math_number">
+                          <field name="NUM">0</field>
+                        </shadow>
+                      </value>
+                      <value name="B">
+                        <shadow type="math_number">
+                          <field name="NUM">140</field>
+                        </shadow>
+                      </value>
+                    </block>
+                  </value>
+                  <value name="wh">
+                    <block type="ai_lcd_WH_vision">
+                      <value name="A">
+                        <shadow type="math_number">
+                          <field name="NUM">100</field>
+                        </shadow>
+                      </value>
+                      <value name="B">
+                        <shadow type="math_number">
+                          <field name="NUM">240</field>
+                        </shadow>
+                      </value>
+                    </block>
+                  </value>
+                </block>
+              </value>
+              <value name="rsize">
+                <block type="ai_canvas_area_tuple">
+                  <value name="xy">
+                    <block type="ai_lcd_XY_vision">
+                      <value name="A">
+                        <shadow type="math_number">
+                          <field name="NUM">220</field>
+                        </shadow>
+                      </value>
+                      <value name="B">
+                        <shadow type="math_number">
+                          <field name="NUM">140</field>
+                        </shadow>
+                      </value>
+                    </block>
+                  </value>
+                  <value name="wh">
+                    <block type="ai_lcd_WH_vision">
+                      <value name="A">
+                        <shadow type="math_number">
+                          <field name="NUM">320</field>
+                        </shadow>
+                      </value>
+                      <value name="B">
+                        <shadow type="math_number">
+                          <field name="NUM">240</field>
+                        </shadow>
+                      </value>
+                    </block>
+                  </value>
+                </block>
+              </value>
+              <value name="axis">
+                <block type="math_number"><field name="NUM">112</field></block>
+              </value>
+            </block>
+            <block type="image_find_qrcodes"></block>
+            <block type="image_get_qrcodes_result"></block>
+            <block type="image_find_barcodes"></block>
+            <block type="image_get_barcodes_result"></block>
+            <block type="image_find_apriltag"></block>
+            <block type="image_get_apriltag_result"></block>
+          </category>
+          <category id="catVideo" name="视频处理" colour="#4d9994">
+            <block type="record_video">
+              <value name="time">
+                <shadow type="math_number">
+                  <field name="NUM">4</field>
+                </shadow>
+              </value>
+              <value name="save_path">
+                <shadow type="text">
+                  <field name="TEXT">/root/user/img/saved.jpg</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="play_video">
+              <value name="video_path">
+                <shadow type="text">
+                  <field name="TEXT">/root/user/video/video.mp4</field>
+                </shadow>
+              </value>
+            </block>
+          </category>
+        </category>
+        <category id="AI" name="人工智能" colour="#ee783a">
+          <category id="AI" name="人工智能" colour="#ee783a">
+            <label id="Object_classification" text="物体分类" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_object_classification"></block>
+            <block type="ai_get_object_classification_result"></block>
+            <label id="Object_detection" text="物体检测" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_object_detection"></block>
+            <block type="ai_get_object_detection_is_result"></block>
+            <block type="ai_get_object_detection_result"></block>
+            <label id="face_and_keypoint detection" text="人脸及关键点检测" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_face_and_keypoint_detection"></block>
+            <block type="ai_get_face_and_keypoint_detection_result"></block>
+            <label id="facial_Keypoint_detection" text="人脸多关键点检测" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_facial_Keypoint_detection"></block>
+            <block type="ai_get_facial_Keypoint_detection_result"></block>
+            <label id="face_recognition" text="人脸识别" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_face_recognition"></block>
+            <block type="ai_get_face_recognition_result"></block>
+            <label id="Facial_expression_recognition" text="人脸表情识别" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_facial_expression_recognition"></block>
+            <block type="ai_get_facial_expression_recognition_result"></block>
+            <label id="Human_keypoint_detection" text="人体关键点检测" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_human_keypoint_detection"></block>
+            <block type="ai_get_human_keypoint_detection_result"></block>
+            <label id="Self_learning_classifier" text="自学习分类器" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_self_learning_classifier_init">
+              <value name="class_input">
+                <block type="lists_create_with">
+                  <value name="ADD0">
+                    <block type="text"><field name="TEXT">Object 1 Name</field></block>
+                  </value>
+                  <value name="ADD1"> 
+                    <block type="text"><field name="TEXT">Object 2 Name</field></block>
+                  </value>
+                  <value name="ADD2"> 
+                    <block type="text"><field name="TEXT">Object 3 Name</field></block>
+                  </value>
+                </block>
+              </value>
+            </block>
+            <block type="ai_set_self_learning_classifier_add_train_data"></block>
+            <block type="ai_set_self_learning_classifier_save_model"></block>
+            <block type="ai_set_self_learning_classifier_load_model"></block>
+            <block type="ai_set_self_learning_classifier_result"></block>
+            <label id="Object_trajectory_tracking_and_counting" text="物体轨迹跟踪和计数" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_object_trajectory_tracking_and_counting"></block>
+            <block type="ai_set_object_trajectory_tracking_and_counting_result"></block>
+            <label id="OCR_text_recognition" text="OCR文字识别" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_ocr_text_recognition"></block>
+            <block type="ai_get_ocr_text_recognition_result"></block>
+            <label id="gesture_recognition" text="手势识别" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_gesture_recognition"></block>
+            <block type="ai_set_gesture_recognition_result"></block>
+            <label id="pose_recognition" text="姿态识别" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_pose_recognition"></block>
+            <block type="ai_set_pose_recognition_result"></block>
+            <label id="Real_time_speech_recognition" text="语音实时识别" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_real_time_speech_recognition"></block>
+            <block type="ai_get_real_time_speech_recognition_result"></block>
+            <label id="Keyword_recognition" text="关键词识别" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_keyword_recognition"></block>
+            <block type="ai_get_keyword_recognition_result"></block>
+          </category>
+          <category id="AIGC" name="AIGC" colour="#0000FF"> 
+            <block type="Initialize_the_AIGC_large_model"></block>
+            <block type="ai_set_aigc_image_generation">
+              <value name="generation">
+                <shadow type="text">
+                  <field name="TEXT">abc</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="ai_get_aigc_image_generation_result"></block>
+            <label id="ai_agent" text="智能体" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="ai_set_ai_agent">
+              <value name="NAME">
+                <shadow type="text">
+                  <field name="TEXT">ENTER_YOUR_EVENT_API_KEY</field>
+                </shadow>
+              </value>
+              <value name="NAME1">
+                <shadow type="text">
+                  <field name="TEXT">Problem</field>
+                </shadow>
+              </value>
+            </block>
+          </category>
+        </category>
+        <category id="catIOT" name="物联网" colour="#7e3cca"> 
+          <category id="catIOT_WIFI" name="WIFI" colour="#7e3cca"> 
+            <block type="wifi_connect"></block>
+            <block type="wifi_disconnect"></block>
+            <block type="wifi_is_connected"></block>
+            <block type="wifi_get_ip"></block>
+            <block type="network_time"></block>
+          </category>
+          <category id="catNetworkCommunication" name="网络通信" colour="#3062c1"> 
+            <label id="Get_weather" text="获取天气信息" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="set_network_weather"></block>
+            <block type="get_network_weather"></block>
+            <label id="IFTTT" text="IFTTT" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="esp32_main_controller_ifttt_send_data">
+              <value name="ifttt_data_1">
+                <shadow type="math_number">
+                  <field name="NUM">0</field>
+                </shadow>
+              </value>
+              <value name="ifttt_data_2">
+                <shadow type="math_number">
+                  <field name="NUM">0</field>
+                </shadow>
+              </value>
+              <value name="ifttt_data_3">
+                <shadow type="math_number">
+                  <field name="NUM">0</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="esp32_main_controller_ifttt_touched"></block>
+            <label id="basis_service_thingspeak" text="Basis service thingspeak" web-class="myLabelStyle" style="font-size:20px;"></label>' +
+            <block type="iot_service_thingspeak">
+              <value name="ADD0">
+                <shadow type="math_number">
+                  <field name="NUM">0</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="iot_service_thingspeak_read"></block>
+            <block type="iot_service_thingspeak_read_total"></block>
+            <block type="iot_service_thingspeak_read_specific">
+              <value name="entry">
+                <shadow type="math_number">
+                  <field name="NUM">1</field>
+                </shadow>
+              </value>
+              <value name="field">
+                <shadow type="math_number">
+                  <field name="NUM">1</field>
+                </shadow>
+              </value>
+            </block>
+            <label id="send_email_label" text="发送邮件" web-class="myLabelStyle" style="font-size:20px;"></label>' +
+            <block type="cocopi_email_send">
+              <value name="email">
+                <shadow type="text">
+                  <field name="TEXT">jidechao@cocorobo.cc</field>
+                </shadow>
+              </value>
+              <value name="email_content">
+                <shadow type="text">
+                  <field name="TEXT">content</field>
+                </shadow>
+              </value>
+            </block>
+            <label id="Flask Web" text="Flask Web" web-class="myLabelStyle" style="font-size:20px;"></label>
+            <block type="websocket_server_set_request"></block>
+            <block type="network_http_get">
+              <value name="http_get_url">
+                <shadow type="text">
+                  <field name="TEXT">HTTP://ENTER_AN_URL</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="network_http_post">
+              <value name="http_post_url">
+                <shadow type="text">
+                  <field name="TEXT">HTTP://ENTER_AN_URL</field>
+                </shadow>
+              </value>
+              <value name="data">
+                <block type="dict_create_with_items_insert"></block>
+              </value>
+            </block>
+            <block type="CocoRobo_get"></block>
+          </category>
+          <category id="WebSocket" name="WebSocket" colour="#5C81A6">
+            <block type="websocket_server_init"></block>
+            <block type="websocket_server_send">
+              <value name="data">
+                <shadow type="text">
+                  <field name="TEXT">abc</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="websocket_server_receive"></block>
+            <block type="websocket_client_init"></block>
+            <block type="websocket_client_send">
+              <value name="data">
+                <shadow type="text">
+                  <field name="TEXT">abc</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="websocket_client_receive"></block>
+            <block type="websocket_client_close"></block>
+          </category>
+          <category id="MQTT" name="MQTT" colour="#e8795b">
+            <block type="MQTT_connected"></block>
+            <block type="MQTT_is_connected"></block>
+            <block type="mqtt_subscribe">
+              <value name="content">
+                <shadow type="text">
+                  <field name="TEXT">hello</field>
+                </shadow>
+              </value>
+              <value name="topic">
+                <shadow type="text">
+                  <field name="TEXT">abc</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="mqtt_received">
+              <value name="topic">
+                <shadow type="text">
+                  <field name="TEXT">abc</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="mqtt_accept_data"></block>
+          </category>
+          <category name="Socket" text="Socket 通信" colour="#5C8EFF" >
+            <block type="socket_TCP_server_init"></block>
+            <block type="socket_TCP_server_send">
+              <value name="data">
+                <shadow type="text">
+                  <field name="TEXT">abc</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="socket_TCP_server_receive"></block>
+            <block type="socket_TCP_client_init"></block>
+            <block type="socket_TCP_client_send">
+              <value name="data">
+                <shadow type="text">
+                  <field name="TEXT">abc</field>
+                </shadow>
+              </value>
+            </block>
+            <block type="socket_TCP_client_receive"></block>
+            <block type="socket_TCP_client_close"></block>
           </category>
         </category>
 </xml>`;
-
+{/* 
+  <label id="Self_learning_detector" text="自学习检测器" web-class="myLabelStyle" style="font-size:20px;"></label>
+  <block type="ai_set_self_learning_detector_add_train_data"></block>
+            
+*/}

+ 1035 - 0
src/Blockly/blocks/Iot.js

@@ -0,0 +1,1035 @@
+import * as Blockly from 'blockly';
+import { pythonGenerator } from 'blockly/python';
+
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) };
+
+const wifiColor = '#7e3cca';
+Blockly.Blocks['wifi_connect'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("WIFI连接")
+            .appendField(new Blockly.FieldTextInput("wifi_name"), "wifi_name")
+            .appendField("密码")
+            .appendField(new Blockly.FieldTextInput("wifi_password"), "wifi_password");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(wifiColor);
+        this.setTooltip("WiFi连接");
+    }
+}
+Blockly.Python['wifi_connect'] = function (block) {
+    var wifi_name = block.getFieldValue('wifi_name');
+    var wifi_password = block.getFieldValue('wifi_password');
+    var code = `wifi.connect("${wifi_name}", "${wifi_password}")`;
+    return code;
+};
+
+Blockly.Blocks['wifi_disconnect'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("WIFI断开连接");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(wifiColor);
+        this.setTooltip("WiFi断开连接");
+    }
+}
+Blockly.Python['wifi_disconnect'] = function (block) {
+    var code = `wifi.disconnect()`;
+    return code;
+};
+
+Blockly.Blocks['wifi_is_connected'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("WIFI是否连接");
+        this.setOutput(true, null);
+        this.setColour(wifiColor);
+        this.setTooltip("WIFI是否连接");
+    }
+}
+Blockly.Python['wifi_is_connected'] = function (block) {
+    var code = `wifi.status()`;
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['wifi_get_ip'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("获取WIFI IP");
+        this.setOutput(true, null);
+        this.setColour(wifiColor);
+        this.setTooltip("获取WIFI IP");
+    }
+}
+Blockly.Python['wifi_get_ip'] = function (block) {
+    var code = `wifi.get_ip()`;
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['network_time'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("获取网络时间");
+        this.setNextStatement(true, null);
+        this.setPreviousStatement(true, null);
+        this.setColour(wifiColor);
+        this.setTooltip("获取网络时间");
+    }
+}
+
+const networkColor = '#3062c1';
+Blockly.Blocks['set_network_weather'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.set_weather_city)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.beijing, "101010100"],
+                [Blockly.Msg.shanghai, "101020100"],
+                [Blockly.Msg.guangzhou, "101280101"],
+                [Blockly.Msg.shenzhen, "101280601"],
+                [Blockly.Msg.HongKong, "101320101"],
+            ]), "get_city")
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.set_weather_city);
+    }
+}
+Blockly.Python['set_network_weather'] = function (block) {
+    var city = block.getFieldValue('get_city');
+    Blockly.Python.definitions_["import_requests"] = `import requests`;
+    Blockly.Python.definitions_["hefengGetWeather"] = `def hefengGetWeather(city,lang):
+  getWeatherUrl = f"https://devapi.qweather.com/v7/weather/now?location={city}&key=d8d1d01bac3246ee8c34640681c1c9b6&lang={lang}"
+  weatherResult = ""
+  try:
+    responseResult = requests.get(getWeatherUrl)
+    if responseResult.status_code == 200:
+      weatherResult = responseResult.json()
+  except:
+    pass
+  return weatherResult
+`
+    let lang = localStorage.getItem("lang") == 2 ? "zh-hans" : localStorage.getItem("lang") == 0 ? "en" : "zh-hant"
+    var code = `getWeatherResult = hefengGetWeather("${city}","${lang}")`;
+    return code;
+};
+
+Blockly.Blocks['get_network_weather'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ESP32_ENV_GET_TEXT)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.weather_resulet, "result"],
+                [Blockly.Msg.image_process_temperature, "temp"],
+                [Blockly.Msg.weather_condition, "text"],
+                [Blockly.Msg.windDir, "windDir"],
+                [Blockly.Msg.windScale, "windScale"],
+                [Blockly.Msg.windSpeed, "windSpeed"],
+                [Blockly.Msg.image_process_humidity, "humidity"],
+            ]), "get_weather")
+        this.setOutput(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.get_weather_city);
+    }
+}
+Blockly.Python['get_network_weather'] = function (block) {
+    var weather = block.getFieldValue('get_weather');
+    var code = "";
+    if (weather == "result") {
+        code = `getWeatherResult`
+    } else {
+        code = `getWeatherResult["now"]["${weather}"]`
+    }
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['esp32_main_controller_ifttt_send_data'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_ifttt_send_title);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_ifttt_send_webhook)
+            .appendField(new Blockly.FieldTextInput("ENTER_YOUR_API_KEY"), "ifttt_api_key");
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_ifttt_send_eventname)
+            .appendField(new Blockly.FieldTextInput("ENTER_YOUR_EVENT_NAME"), "ifttt_event");
+        this.appendValueInput("ifttt_data_1")
+            .setCheck(null)
+            .appendField(Blockly.Msg.iotservice_ifttt_send_1);
+        this.appendValueInput("ifttt_data_2")
+            .setCheck(null)
+            .appendField(Blockly.Msg.iotservice_ifttt_send_2);
+        this.appendValueInput("ifttt_data_3")
+            .setCheck(null)
+            .appendField(Blockly.Msg.iotservice_ifttt_send_3);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.Esp32_Main_Controller_Ifttt_Send_Data_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['esp32_main_controller_ifttt_send_data'] = function (block) {
+    var text_ifttt_api_key = block.getFieldValue('ifttt_api_key');
+    var text_ifttt_event = block.getFieldValue('ifttt_event');
+    var value_ifttt_data_1 = Blockly.Python.valueToCode(block, 'ifttt_data_1', Blockly.Python.ORDER_ATOMIC);
+    var value_ifttt_data_2 = Blockly.Python.valueToCode(block, 'ifttt_data_2', Blockly.Python.ORDER_ATOMIC);
+    var value_ifttt_data_3 = Blockly.Python.valueToCode(block, 'ifttt_data_3', Blockly.Python.ORDER_ATOMIC);
+    // TODO: Assemble Python into code variable.
+
+    Blockly.Python.definitions_['v831_import_requests'] = `import requests`
+    Blockly.Python.definitions_['v831_import_json'] = `import json`;
+
+    var code = '' +
+        '_IFTTT_POST_API_KEY = "' + text_ifttt_api_key + '"\n' +
+        '_IFTTT_POST_EVENT_NAME = "' + text_ifttt_event + '"\n' +
+        '_IFTTT_POST_ENDPOINT = "http://maker.ifttt.com/trigger/"+ _IFTTT_POST_EVENT_NAME + "/with/key/" + _IFTTT_POST_API_KEY\n' +
+        '_IFTTT_POST_DATA = \'{"value1":"\'+ str(' + value_ifttt_data_1 + ') +\'","value2":"\'+ str(' + value_ifttt_data_2 + ') +\'","value3":"\'+ str(' + value_ifttt_data_3 + ') +\'"}\'\n' +
+        '_IFTTT_POST_REQUEST = requests.post(_IFTTT_POST_ENDPOINT, data = _IFTTT_POST_DATA , headers = { "Content-type": "application/json" }, timeout=60)\n' +
+        '\n';
+    return code;
+};
+
+
+
+Blockly.Blocks['esp32_main_controller_ifttt_touched'] = {
+    init: function () {
+        // this.appendDummyInput()
+        //     .appendField(new Blockly.FieldImage("blockly/media/ifttt_webhook.png", 110, 60, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_ifttt_trigger_title);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_ifttt_trigger_webhook)
+            .appendField(new Blockly.FieldTextInput("ENTER_YOUR_API_KEY"), "key");
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_ifttt_trigger_eventname)
+            .appendField(new Blockly.FieldTextInput("ENTER_YOUR_EVENT_NAME"), "timename");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.Esp32_Main_Controller_Ifttt_Touched_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['esp32_main_controller_ifttt_touched'] = function (block) {
+    var text_ifttt_api_key = block.getFieldValue('key');
+    var text_timename = block.getFieldValue('timename');
+    Blockly.Python.definitions_['v831_import_requests'] = `import requests`
+    Blockly.Python.definitions_['v831_import_json'] = `import json`;
+    var code = '_IFTTT_TRIGGER_EVENT_NAME = "' + text_timename + '"\n'
+    code += '_IFTTT_TRIGGER_API_KEY = "' + text_ifttt_api_key + '"\n'
+    code += '_IFTTT_TRIGGER_ENDPOINT = "https://maker.ifttt.com/trigger/" + _IFTTT_TRIGGER_EVENT_NAME + "/with/key/" + _IFTTT_TRIGGER_API_KEY\n'
+    var code = '_IFTTT_GET_REQUEST = requests.get(_IFTTT_TRIGGER_ENDPOINT, timeout=60)\n'
+    return code;
+};
+Blockly.Blocks['iot_service_thingspeak'] = {
+    init: function () {
+        // this.appendDummyInput()
+        //     .appendField(new Blockly.FieldImage("blockly/media/thingspeak.png", 170, 45, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeak_send_title);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeak_send_api)
+            .appendField(new Blockly.FieldTextInput("ENTER_YOUR_CHANNEL_WRITE_API_KEY"), "t_api");
+        this.itemCount_ = 1;
+        this.updateShape_();
+        this.setMutator(new Blockly.icons.MutatorIcon(['iot_service_thingspeak_create_with_item'], this));
+        this.setColour(networkColor);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setTooltip(Blockly.Msg.Iot_Service_Thingspeak_TOOLTIP);
+        this.setHelpUrl("");
+    },
+    mutationToDom: function () {
+        var container = document.createElement('mutation');
+        container.setAttribute('items', this.itemCount_);
+        return container;
+    },
+    domToMutation: function (xmlElement) {
+        this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
+        this.updateShape_();
+    },
+    decompose: function (workspace) {
+        var containerBlock = workspace.newBlock('iot_service_thingspeak_create_with_container');
+        containerBlock.initSvg();
+        var connection = containerBlock.getInput('STACK').connection;
+        for (var i = 0; i < this.itemCount_; i++) {
+            var itemBlock = workspace.newBlock('iot_service_thingspeak_create_with_item');
+            itemBlock.initSvg();
+            connection.connect(itemBlock.previousConnection);
+            connection = itemBlock.nextConnection;
+        }
+        return containerBlock;
+    },
+    compose: function (containerBlock) {
+        var itemBlock = containerBlock.getInputTargetBlock('STACK');
+        // Count number of inputs.
+        var connections = [];
+        while (itemBlock) {
+            connections.push(itemBlock.valueConnection_);
+            itemBlock = itemBlock.nextConnection &&
+                itemBlock.nextConnection.targetBlock();
+        }
+        // Disconnect any children that don't belong.
+        for (var i = 0; i < this.itemCount_; i++) {
+            var connection = this.getInput('ADD' + i).connection.targetConnection;
+            if (connection && connections.indexOf(connection) == -1) {
+                connection.disconnect();
+            }
+        }
+        this.itemCount_ = connections.length;
+        this.updateShape_();
+        // Reconnect any child blocks.
+        for (var i = 0; i < this.itemCount_; i++) {
+            Blockly.icons.MutatorIcon.reconnect(connections[i], this, 'ADD' + i);
+        }
+    },
+    saveConnections: function (containerBlock) {
+        var itemBlock = containerBlock.getInputTargetBlock('STACK');
+        var i = 0;
+        while (itemBlock) {
+            var input = this.getInput('ADD' + i);
+            itemBlock.valueConnection_ = input && input.connection.targetConnection;
+            i++;
+            itemBlock = itemBlock.nextConnection &&
+                itemBlock.nextConnection.targetBlock();
+        }
+    },
+    updateShape_: function () {
+        for (var i = 0; i < this.itemCount_; i++) {
+            if (!this.getInput('ADD' + i)) {
+                var input = this.appendValueInput('ADD' + i);
+                input.appendField("Field " + (i + 1) + ":");
+                //input.appendField(new Blockly.FieldLabelSerializable("field" + (i + 1)), 'FIELD' + i);
+                // input.appendField(new Blockly.FieldTextInput("field" + (i + 1)), 'FIELD' + i)
+            }
+        }
+        while (this.getInput('ADD' + i)) {
+            this.removeInput('ADD' + i);
+            i++;
+        }
+    },
+};
+
+Blockly.Blocks['iot_service_thingspeak_create_with_container'] = {
+    init: function () {
+        this.setColour(networkColor);
+        this.appendDummyInput()
+            .appendField("Items");
+        this.appendStatementInput('STACK');
+        this.setTooltip('');
+        this.contextMenu = false;
+    }
+};
+
+Blockly.Blocks['iot_service_thingspeak_create_with_item'] = {
+    init: function () {
+        this.setColour(networkColor);
+        this.appendDummyInput()
+            .appendField("Field");
+        this.setPreviousStatement(true);
+        this.setNextStatement(true);
+        this.setTooltip('');
+        this.contextMenu = false;
+    }
+};
+
+Blockly.Python['iot_service_thingspeak'] = function (block) {
+    var first_input = Blockly.Python.valueToCode(block, 'first_input', Blockly.Python.ORDER_ATOMIC);
+    var api = block.getFieldValue('t_api');
+
+    // Blockly.Python.addVariable('_THINGSPEAK_REQUEST', '', true);
+    Blockly.Python.definitions_['v831_import_requests'] = `import requests`
+    Blockly.Python.definitions_['v831_import_json'] = `import json`;
+
+
+    // var key = Blockly.Arduino.valueToCode(block, 'KEY', Blockly.Arduino.ORDER_ATOMIC).replace(/\"/g, '') || "";
+
+    var item_field = '',
+        item_value = '';
+    var thingspeak_url = "http://api.thingspeak.com/update?api_key=" + api;
+    for (var n = 0; n < this.itemCount_; n++) {
+        item_field = "field" + (n + 1);
+        item_value = Blockly.Python.valueToCode(this, 'ADD' + n,
+            Blockly.Python.ORDER_NONE) || '';
+        thingspeak_url += '&' + item_field + '=\"+str(' + item_value + ')+\"';
+    }
+    var code = '' +
+        '_THINGSPEAK_ENDPOINT = "' + thingspeak_url + '"\n' +
+        '_THINGSPEAK_REQUEST = requests.get(_THINGSPEAK_ENDPOINT,timeout=60)\n' +
+        '';
+
+    return code;
+};
+
+Blockly.Blocks['iot_service_thingspeak_read'] = {
+    init: function () {
+        // this.appendDummyInput()
+        //     .appendField(new Blockly.FieldImage("blockly/media/thingspeak.png", 170, 45, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeak_query_title);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeak_query_api)
+            .appendField(new Blockly.FieldTextInput("ENTER_YOUR_CHANNEL_READ_API_KEY"), "api_key");
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeak_channel_id)
+            .appendField(new Blockly.FieldTextInput("ENTER_YOUR_CHANNEL_ID"), "id");
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.Iot_Service_Thingspeak_Read_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+
+Blockly.Python['iot_service_thingspeak_read'] = function (block) {
+    var text_api_key = block.getFieldValue('api_key');
+    var text_id = block.getFieldValue('id');
+    Blockly.Python.definitions_['v831_import_requests'] = `import requests`
+    Blockly.Python.definitions_['v831_import_json'] = `import json`;
+
+    Blockly.Python.addVariable('_THINGSPEAK_READ_REQUEST', '', true);
+    // TODO: Assemble Python into code variable.
+    var code = '_THINGSPEAK_READ_REQUEST = requests.get("https://api.thingspeak.com/channels/" + "' + text_id + '" + "/feeds.json?api_key=" + "' + text_api_key + '",timeout=60)\n';
+    return code;
+};
+
+
+Blockly.Blocks['iot_service_thingspeak_read_total'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeak_read_total);
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.Iot_Service_Thingspeak_Read_Total_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['iot_service_thingspeak_read_total'] = function (block) {
+    // TODO: Assemble Python into code variable.
+    var code = '_THINGSPEAK_READ_REQUEST.json()[\'channel\'][\'last_entry_id\']';
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+
+Blockly.Blocks['iot_service_thingspeak_read_specific'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeak_get_title);
+        this.appendValueInput("entry")
+            .setCheck(null);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeaK_get_field);
+        this.appendValueInput("field")
+            .setCheck(null);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.iotservice_thingspeaK_get_value);
+        this.setInputsInline(true);
+        this.setOutput(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.Iot_Service_Thingspeak_Read_Specific_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['iot_service_thingspeak_read_specific'] = function (block) {
+    var value_entry = Blockly.Python.valueToCode(block, 'entry', Blockly.Python.ORDER_ATOMIC);
+    var value_field = Blockly.Python.valueToCode(block, 'field', Blockly.Python.ORDER_ATOMIC);
+    // TODO: Assemble Python into code variable.
+    var code = '_THINGSPEAK_READ_REQUEST.json()[\'feeds\'][' + value_entry + '][\'field' + value_field + '\']';
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+
+// 发送邮件
+
+Blockly.Blocks['cocopi_email_send'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.send_email_title);
+        this.appendValueInput("email")
+            .setCheck(null)
+            .appendField(Blockly.Msg.send_email_to);
+        this.appendValueInput("email_content")
+            .setCheck(null)
+            .appendField(Blockly.Msg.send_email_content);
+        this.setOutput(true);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.send_email_title_title);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['cocopi_email_send'] = function (block) {
+    var Email = Blockly.Python.valueToCode(block, 'email', Blockly.Python.ORDER_ATOMIC);
+    var EmailContent = Blockly.Python.valueToCode(block, 'email_content', Blockly.Python.ORDER_ATOMIC);
+
+    Blockly.Python.definitions_['import_requests'] = `import requests`
+    Blockly.Python.definitions_['import_json'] = `import json`;
+    // TODO: Assemble Python into code variable.
+    Blockly.Python.definitions_['send_email'] = `def send_email(email,content):
+    params = {
+        "email": email,
+        "content": content,
+        "subject":"训练平台",
+        "content_type":'plain'
+    }
+    emailURL = "https://traininguser-api.cocorobo.cn/sendEmail"
+    try:
+        r = requests.post(emailURL,json=params)
+        print(json.loads(r.text))
+        if json.loads(r.text)["FunctionResponse"] == "发送成功":
+            return True
+        else:
+            return False
+    except Exception as e:
+        print(e)
+        return False
+    `
+    var code = `send_email(${Email},${EmailContent})`;
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+
+// socket 
+const socketColor = '#5C8EFF';
+Blockly.Blocks['socket_TCP_server_init'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("TCP服务端初始化");
+        this.setNextStatement(true, null);
+        this.setColour(socketColor);
+        this.setTooltip("TCP服务端初始化");
+        this.setPreviousStatement(true, null);
+    }
+};
+Blockly.Python['socket_TCP_server_init'] = function (block) {
+    Blockly.Python.definitions_['import_socket'] = `import socket`;
+    Blockly.Python.definitions_['socket_TCP_server_init'] = `def socket_TCP_server_init():
+    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    s.bind(('', 8888))
+    s.listen(5)
+    return s
+    `;
+    var code = `socket_TCP_server_init()`;
+    return code;
+};
+
+Blockly.Blocks['socket_TCP_server_send'] = {
+    init: function () {
+        this.appendValueInput("data").setCheck(null).appendField("服务端发送数据");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(socketColor);
+        this.setTooltip("服务端发送数据");
+    }
+}
+Blockly.Python['socket_TCP_server_send'] = function (block) {
+    // var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
+    Blockly.Python.definitions_['socket_TCP_server_send'] = `def socket_TCP_server_send(s,data):
+    s.send(data.encode())
+    `;
+    let code = `socket_TCP_server_send(s)`;
+    return code;
+}
+Blockly.Blocks['socket_TCP_server_receive'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("服务端接收数据");
+        this.setOutput(true, null);
+        this.setColour(socketColor);
+        this.setTooltip("服务端接收数据");
+    }
+}
+Blockly.Python['socket_TCP_server_receive'] = function (block) {
+    Blockly.Python.definitions_['socket_TCP_server_receive'] = `def socket_TCP_server_receive(s):
+    data = s.recv(1024)
+    return data.decode()
+    `;
+    var code = `socket_TCP_server_receive(s)`;
+    return code;
+}
+
+Blockly.Blocks['socket_TCP_client_init'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("客户端初始化");
+        this.setPreviousStatement(true, null);
+        this.setColour(socketColor);
+        this.setTooltip("客户端初始化");
+    }
+}
+Blockly.Python['socket_TCP_client_init'] = function (block) {
+    Blockly.Python.definitions_['import_socket'] = `import socket`;
+    Blockly.Python.definitions_['socket_TCP_client_init'] = `def socket_TCP_client_init():
+    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    s.connect(('192.168.1.100', 888))`
+    let code = `socket_TCP_client_init()`;
+    return code
+}
+
+Blockly.Blocks['socket_TCP_client_send'] = {
+    init: function () {
+        this.appendValueInput("data").setCheck(null).appendField("客户端发送数据");
+        this.setNextStatement(true, null);
+        this.setPreviousStatement(true, null);
+        this.setColour(socketColor);
+        this.setTooltip("客户端发送数据");
+    }
+}
+Blockly.Python['socket_TCP_client_send'] = function (block) {
+    // var value_data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
+    Blockly.Python.definitions_['socket_TCP_client_send'] = `def socket_TCP_client_send(s,data):
+    s.send(data.encode())
+    `;
+    let code = `socket_TCP_client_send(s)`;
+    return code;
+}
+
+Blockly.Blocks['socket_TCP_client_receive'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("客户端接收数据");
+        this.setOutput(true, null);
+        this.setColour(socketColor);
+        this.setTooltip("客户端接收数据");
+    }
+}
+Blockly.Python['socket_TCP_client_receive'] = function (block) {
+    Blockly.Python.definitions_['socket_TCP_client_receive'] = `def socket_TCP_client_receive(s):
+    data = s.recv(1024)
+    return data.decode()
+    `;
+    var code = `socket_TCP_client_receive(s)`;
+    return code;
+}
+
+Blockly.Blocks['socket_TCP_client_close'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("客户端关闭连接");
+        this.setPreviousStatement(true, null);
+        this.setColour(socketColor);
+        this.setTooltip("客户端关闭连接");
+    }
+}
+Blockly.Python['socket_TCP_client_close'] = function (block) {
+    Blockly.Python.definitions_['socket_TCP_client_close'] = `def socket_TCP_client_close(s):
+    s.close()
+    `;
+    var code = `socket_TCP_client_close(s)`;
+    return code;
+}
+
+
+// MQTT
+const mqttColor = '#e8795b';
+Blockly.Blocks['MQTT_connected'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("MQTT连接");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(mqttColor);
+        this.setTooltip("MQTT连接");
+    }
+};
+Blockly.Python['MQTT_connected'] = function (block) {
+    Blockly.Python.definitions_['import_paho'] = `import paho.mqtt.client as mqtt`;
+    Blockly.Python.definitions_['mqtt_connect'] = `def mqtt_connect():
+    client = mqtt.Client()
+    client.connect("mqtt.eclipse.org", 1883, 60)
+    return client   
+`;
+    var code = `mqtt_connect()`;
+    return code;
+};
+
+Blockly.Blocks['MQTT_is_connected'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("MQTT是否连接");
+        this.setOutput(true, null);
+        this.setColour(mqttColor);
+        this.setTooltip("MQTT是否连接");
+        this.setHelpUrl("");
+    }
+}
+Blockly.Python['MQTT_is_connected'] = function (block) {
+    Blockly.Python.definitions_['MQTT_is_connected'] = `def MQTT_is_connected(client):
+    return client.is_connected()
+`;
+    var code = `MQTT_is_connected(client)`;
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['mqtt_subscribe'] = {
+    init: function () {
+        this.appendValueInput("content")
+            .setCheck(null).appendField("发送");
+        this.appendValueInput("topic")
+            .setCheck(null).appendField("内容到主题");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(mqttColor);
+        this.setTooltip("MQTT订阅主题");
+        this.setInputsInline(true);
+    }
+}
+Blockly.Python['mqtt_subscribe'] = function (block) {
+    var topic = Blockly.Python.valueToCode(block, 'topic', Blockly.Python.ORDER_ATOMIC);
+    Blockly.Python.definitions_['mqtt_subscribe'] = `def mqtt_subscribe(client, topic):
+    client.subscribe(topic)
+`;
+    var code = `mqtt_subscribe(client, ${topic})`;
+    return code;
+};
+
+Blockly.Blocks['mqtt_received'] = { 
+    init: function () { 
+        this.appendValueInput("topic").setCheck(null).appendField("当从主题")
+        this.appendDummyInput().appendField("收到消息时");
+        this.appendStatementInput("exec")
+            .setCheck(null)
+            .appendField(Blockly.Msg.wifi_web_http_server_route_setting_do);
+        this.setColour(mqttColor);
+        this.setTooltip("当从主题收到消息时");
+        this.setHelpUrl("");
+        this.setNextStatement(true, null);
+        this.setPreviousStatement(true, null);
+    }
+};
+Blockly.Python['mqtt_received'] = function (block) {
+    var path = block.getFieldValue('path');
+    var statements_exec = Blockly.Python.statementToCode(block, 'exec');
+    Blockly.Python.definitions_['mqtt_on_message'] = `def on_message(client, userdata, msg):
+    topic = msg.topic
+    message = msg.payload.decode()
+    print("Received message: " + message + " from topic: " + topic)
+`;
+    let code = ``;
+    return code;
+}
+
+Blockly.Blocks['mqtt_accept_data'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("接收MQTT数据");
+        this.setOutput(true, null);
+        this.setColour(mqttColor);
+        this.setTooltip("接收MQTT数据");
+    }
+}
+Blockly.Python['mqtt_accept_data'] = function (block) {
+    Blockly.Python.definitions_['mqtt_accept_data'] = `def mqtt_accept_data(client
+):
+    client.loop_start()
+    return client`;
+    var code = `mqtt_accept_data(client)`;
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+// WebSocket
+const websocketColor = '#5C81A6';
+Blockly.Blocks['websocket_server_init'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("websocket服务端初始化");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(websocketColor);
+        this.setTooltip("websocket服务端初始化");
+    }
+};
+Blockly.Python['websocket_server_init'] = function (block) {
+    Blockly.Python.definitions_['import_websocket'] = `import websocket`;
+    Blockly.Python.definitions_['websocket_server_init'] = `def websocket_server_init():
+    ws = websocket.WebSocketServer('192.168.1.100', 8080)
+    return ws`;
+    var code = `websocket_server_init()`;
+    return code;
+
+}
+
+Blockly.Blocks['websocket_server_receive'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("websocket服务端接收数据");
+        this.setOutput(true, null);
+        this.setColour(websocketColor);
+        this.setTooltip("websocket服务端接收数据");
+    }
+}
+Blockly.Python['websocket_server_receive'] = function (block) {
+    Blockly.Python.definitions_['websocket_server_receive'] = `def websocket_server_receive(ws):
+    data = ws.recv()
+    return data`;
+    var code = `websocket_server_receive(ws)`;
+    return [code, Blockly.Python.ORDER_NONE];
+}
+
+Blockly.Blocks['websocket_server_send'] = {
+    init: function () {
+        this.appendValueInput("data").setCheck(null).appendField("websocket服务端发送数据");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(websocketColor);
+        this.setTooltip("websocket服务端发送数据");
+    }
+}
+Blockly.Python['websocket_server_send'] = function (block) {
+    var data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
+    Blockly.Python.definitions_['websocket_server_send'] = `def websocket_server_send(ws, data):
+    ws.send(data)`;
+    var code = `websocket_server_send(ws, ${data})`;
+    return code;
+}
+
+Blockly.Blocks['websocket_client_init'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("websocket客户端初始化");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(websocketColor);
+        this.setTooltip("websocket客户端初始化");
+    }
+}
+Blockly.Python['websocket_client_init'] = function (block) {
+    Blockly.Python.definitions_['import_websocket'] = `import websocket`;
+    Blockly.Python.definitions_['websocket_client_init'] = `def websocket_client_init():
+    ws = websocket.WebSocket()
+    ws.connect('ws://192.168.1.100:8080')
+    return ws`;
+    var code = `websocket_client_init()`;
+    return code;
+}
+
+Blockly.Blocks['websocket_client_receive'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("websocket客户端接收数据");
+        this.setOutput(true, null);
+        this.setColour(websocketColor);
+        this.setTooltip("websocket客户端接收数据");
+    }
+}
+Blockly.Python['websocket_client_receive'] = function (block) {
+    Blockly.Python.definitions_['websocket_client_receive'] = `def websocket_client_receive(ws):
+    data = ws.recv()
+    return data`;
+    var code = `websocket_client_receive(ws)`;
+    return [code, Blockly.Python.ORDER_NONE];
+}
+
+Blockly.Blocks['websocket_client_send'] = {
+    init: function () {
+        this.appendValueInput("data").setCheck(null).appendField("websocket客户端发送数据");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(websocketColor);
+        this.setTooltip("websocket客户端发送数据");
+    }
+}
+Blockly.Python['websocket_client_send'] = function (block) {
+    var data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
+    Blockly.Python.definitions_['websocket_client_send'] = `def websocket_client_send(ws, data):
+    ws.send(data)`;
+    var code = `websocket_client_send(ws, ${data})`;
+    return code;
+}
+
+Blockly.Blocks['websocket_client_close'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("websocket客户端关闭");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(websocketColor);
+        this.setTooltip("websocket客户端关闭");
+    }
+}
+Blockly.Python['websocket_client_close'] = function (block) {
+    Blockly.Python.definitions_['websocket_client_close'] = `def websocket_client_close(ws):
+    ws.close()`;
+    var code = `websocket_client_close(ws)`;
+    return code;
+}
+
+// Flask Web
+Blockly.Blocks['websocket_server_set_request'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.wifi_web_http_server_route_setting_title);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.wifi_web_http_server_route_setting_path)
+            .appendField(new Blockly.FieldTextInput("/"), "path")
+            .appendField(Blockly.Msg.wifi_web_http_server_route_setting_being_requested);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.wifi_web_http_server_route_setting_property)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.wifi_web_http_server_route_setting_get, "get"],
+                [Blockly.Msg.wifi_web_http_server_route_setting_post, "post"]
+            ]), "response_type");
+        this.appendStatementInput("exec")
+            .setCheck(null)
+            .appendField(Blockly.Msg.wifi_web_http_server_route_setting_do);
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(networkColor);
+        // this.setTooltip("");
+        this.setHelpUrl("");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('response_type');
+            var TOOLTIPS = {
+                'get': Blockly.Msg.Esp32_Network_Http_Server_Route_TOOLTIP.replace('%1', Blockly.Msg.wifi_web_http_server_route_setting_get),
+                'post': Blockly.Msg.Esp32_Network_Http_Server_Route_TOOLTIP.replace('%1', Blockly.Msg.wifi_web_http_server_route_setting_post)
+            };
+            return TOOLTIPS[mode];
+        });
+    }
+}
+Blockly.Python['websocket_server_set_request'] = function () {
+    var dropdown_response_type = block.getFieldValue('response_type');
+    var text_path = block.getFieldValue('path');
+    var statements_exec = Blockly.Python.statementToCode(block, 'exec');
+    var code = ``;
+    return code;
+}
+
+Blockly.Blocks['network_http_get'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.internet_http_get_title);
+        this.appendValueInput("http_get_url")
+            .setCheck(null)
+            .appendField(Blockly.Msg.internet_http_get_url);
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.Esp32_Network_Http_Get_TOOLTIP);
+        this.setHelpUrl("");
+    }
+}
+
+Blockly.Python['network_http_get'] = function (block) {
+    var url = Blockly.Python.valueToCode(block, 'http_get_url', Blockly.Python.ORDER_ATOMIC);
+    Blockly.Python.definitions_['v831_import_requests'] = `import requests`
+    Blockly.Python.definitions_['v831_import_json'] = `import json`;
+    Blockly.Python.definitions_['v831_import_SEND_HTTP'] = `_SEND_HTTP_GET_ENDPOINT = ${url}`;
+    // TODO: Assemble Python into code variable.
+
+    var code = '_SEND_HTTP_REQUEST = requests.get(_SEND_HTTP_GET_ENDPOINT)\n';
+    return code;
+};
+
+Blockly.Blocks['network_http_post'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(new Blockly.FieldImage("blockly/media/http_header_post.png", 180, 50, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.internet_http_post_title);
+        this.appendValueInput("http_post_url")
+            .setCheck(null)
+            .appendField(Blockly.Msg.internet_http_post_url);
+        this.appendValueInput("data")
+            .setCheck(null)
+            .appendField(Blockly.Msg.internet_http_post_json);
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(networkColor);
+        this.setTooltip(Blockly.Msg.Esp32_Network_Http_Post_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+
+Blockly.Python['network_http_post'] = function (block) {
+    var url = Blockly.Python.valueToCode(block, 'http_post_url', Blockly.Python.ORDER_ATOMIC);
+    var data = Blockly.Python.valueToCode(block, 'data', Blockly.Python.ORDER_ATOMIC);
+
+    Blockly.Python.addVariable('_SEND_HTTP_POST_ENDPOINT', '', true);
+    Blockly.Python.addVariable('_SEND_HTTP_REQUEST', '', true);
+    Blockly.Python.definitions_['831_import_requests'] = `import requests`
+    Blockly.Python.definitions_['831_import_json'] = `import json`
+    Blockly.Python.definitions_['import_urequests'] = '' +
+        '_SEND_HTTP_POST_ENDPOINT = ' + url + '\n' +
+        '';
+    // TODO: Assemble Python into code variable.
+
+    // var code = '' +
+    //     '_SEND_HTTP_POST_DATA = \'' + data + '\'\n' +
+    //     '_SEND_HTTP_REQUEST = requests.post(_SEND_HTTP_POST_ENDPOINT, data = _SEND_HTTP_POST_DATA , headers = { "Content-type": "application/json" })\n' +
+    //     '';
+    var code = `_SEND_HTTP_POST_DATA = ${data}
+_SEND_HTTP_REQUEST = requests.post(_SEND_HTTP_POST_ENDPOINT, json = _SEND_HTTP_POST_DATA , headers = { "Content-type": "application/json" })
+`
+    return code;
+};
+
+Blockly.Blocks['CocoRobo_get'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.internet_response_http_content_title)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.internet_response_text, "text"],
+                [Blockly.Msg.internet_response_content, "content"],
+                [Blockly.Msg.internet_response_status, "state"],
+                [Blockly.Msg.internet_response_json, "json"],
+                [Blockly.Msg.internet_response_encode, "code"],
+                [Blockly.Msg.internet_response_reason, "reason"]
+            ]), "op");
+        this.setOutput(true, null);
+        this.setColour(networkColor);
+        // this.setTooltip(Blockly.Msg.CocoRobo_get_TOOLTIP);
+        this.setHelpUrl("");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('op');
+            var TOOLTIPS = {
+                'text': Blockly.Msg.CocoRobo_get_TOOLTIP.replace('%1', Blockly.Msg.internet_response_text),
+                'content': Blockly.Msg.CocoRobo_get_TOOLTIP.replace('%1', Blockly.Msg.internet_response_content),
+                'state': Blockly.Msg.CocoRobo_get_TOOLTIP.replace('%1', Blockly.Msg.internet_response_status),
+                'json': Blockly.Msg.CocoRobo_get_TOOLTIP.replace('%1', Blockly.Msg.internet_response_json),
+                'code': Blockly.Msg.CocoRobo_get_TOOLTIP.replace('%1', Blockly.Msg.internet_response_encode),
+                'reason': Blockly.Msg.CocoRobo_get_TOOLTIP.replace('%1', Blockly.Msg.internet_response_reason)
+            };
+            return TOOLTIPS[mode];
+        });
+    }
+};
+
+Blockly.Python['CocoRobo_get'] = function (block) {
+    var op = block.getFieldValue('op');
+    var code = '_SEND_HTTP_REQUEST.text';
+    if (op == "text") {
+        code = '_SEND_HTTP_REQUEST.text';
+    } else if (op == "content") {
+        code = '_SEND_HTTP_REQUEST.content';
+    } else if (op == "state") {
+        code = '_SEND_HTTP_REQUEST.status_code';
+    } else if (op == "json") {
+        code = '_SEND_HTTP_REQUEST.json()';
+    } else if (op == "code") {
+        code = '_SEND_HTTP_REQUEST.encoding';
+    } else if (op == "reason") {
+        code = '_SEND_HTTP_REQUEST.reason';
+    }
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
+};
+
+
+export default Blockly;

+ 665 - 0
src/Blockly/blocks/MediaProcessing.js

@@ -0,0 +1,665 @@
+
+import * as Blockly from 'blockly';
+import { pythonGenerator } from 'blockly/python';
+
+
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) };
+const color =  "#f0983e";
+
+Blockly.Blocks['ai_canvas_area_tuple'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_vision_canvas_area_tuple);
+        this.appendValueInput("xy")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_find_blobs_start_coord);
+        this.appendValueInput("wh")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_find_blobs_size);
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour("#f0983e");
+        this.setTooltip(Blockly.Msg.ai_vision_canvas_area_tuple);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_canvas_area_tuple'] = function (block) {
+    var value_coordinate = Blockly.Python.valueToCode(block, 'xy', Blockly.Python.ORDER_ATOMIC);
+    var value_size = Blockly.Python.valueToCode(block, 'wh', Blockly.Python.ORDER_ATOMIC);
+    // TODO: Assemble Python into code variable.
+    var code = value_coordinate + ',' + value_size;
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_NONE];
+};
+Blockly.Blocks['image_save'] = {
+    init: function () {
+        this.appendValueInput("save_path")
+            .setCheck(null)
+            .appendField(Blockly.Msg.save_img_path_to)
+        this.setOutput(false, null);
+        this.setColour(color);
+        this.setTooltip(Blockly.Msg.save_img_path_to);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['image_save'] = function (block) {
+    var save_path_location = Blockly.Python.valueToCode(block, 'save_path', Blockly.Python.ORDER_ATOMIC);
+
+    var code = 'canvas.save(' + save_path_location + ')';
+    return code;
+};
+
+Blockly.Blocks["image_open"] = {
+    init: function () {
+        this.appendValueInput("save_path")
+            .setCheck(null)
+            .appendField(Blockly.Msg.read_img_path_to);
+        this.setOutput(true, null);
+        this.setColour(color);
+        this.setTooltip(Blockly.Msg.read_img_path_to);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python["image_open"] = function (block) {
+    var save_path_location = Blockly.Python.valueToCode(block, 'save_path', Blockly.Python.ORDER_ATOMIC);
+    Blockly.Python.definitions_['import_image'] = `from maix import image`;
+    var code = `image.load(${save_path_location})`;
+    return [code, Blockly.Python.ORDER_ATOMIC];
+};
+
+// 翻转
+{/* <block type="v831_lcd_invert"></block> */}
+Blockly.Blocks['v831_lcd_invert'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_text_let_canvas)
+            .appendField(Blockly.Msg.image_process_pixtovec_text_first)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.display_draw_vertical, "0"],
+                [Blockly.Msg.display_draw_horizontal, "1"]
+            ]), "invert")
+            .appendField(Blockly.Msg.MAIXDUINO_DISPLAY_ORIENTATION_ROTATE);
+        this.setOutput(true, null);
+        this.setColour(color);
+        let _this = this;
+        // this.setTooltip(Blockly.Msg.ai_lcd_invert_color_TOOLTIP);
+        this.setTooltip(function () {
+            const invert = _this.getFieldValue('invert');
+            const tooltip = {
+                "0": Blockly.Msg.MAIXDUINO_DISPLAY_ORIENTATION_ROTATE_title.replace('%1', Blockly.Msg.display_draw_vertical),
+                "1": Blockly.Msg.MAIXDUINO_DISPLAY_ORIENTATION_ROTATE_title.replace('%1', Blockly.Msg.display_draw_horizontal),
+            }
+            return tooltip[invert]
+        })
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['v831_lcd_invert'] = function (block) {
+    let invert = block.getFieldValue('invert');
+
+    // TODO: Assemble Python into code variable.
+    var code = `canvas.flip(${invert})`
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['image_rotating'] = {
+    init: function () {
+        this.appendValueInput("route")
+            .setCheck(null)
+            .appendField(Blockly.Msg.image_process_rotate)
+        this.appendDummyInput().appendField(Blockly.Msg.image_process_rotate_angle);
+        this.setOutput(false, null);
+        this.setTooltip(Blockly.Msg.image_process_rotate);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+    }
+}
+
+Blockly.Python['image_rotating'] = function (block) {
+    var route = Blockly.Python.valueToCode(block, 'route', Blockly.Python.ORDER_ATOMIC);
+    var code = `canvas = canvas.rotate(${route})`
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks.ai_lcd_XY_vision = {
+    init: function () {
+        var _input = this.appendDummyInput();
+        this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL);
+        this.setColour(color);
+        this.setOutput(!0, "Boolean");
+        _input.appendField(Blockly.Msg.image_process_xy_x);
+        this.appendValueInput("A").setCheck("Number");
+        _input = this.appendDummyInput();
+        _input.appendField(Blockly.Msg.image_process_xy_y)
+        this.appendValueInput("B").setCheck("Number");
+        this.setInputsInline(!0);
+    }
+};
+
+Blockly.Python.ai_lcd_XY_vision = function (block) {
+    var _x = Blockly.Python.valueToCode(block, "A", Blockly.Python.ORDER_ATOMIC);
+    var _y = Blockly.Python.valueToCode(block, "B", Blockly.Python.ORDER_ATOMIC);
+    var code = "" + _x + ", " + _y + "";
+    return [code, Blockly.Python.ORDER_ATOMIC];
+};
+Blockly.Blocks['image_crop'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_imgcut_cutting);
+        this.appendValueInput("xy")
+            .setCheck(null)
+            .appendField(Blockly.Msg.image_process_imgcut_start_coord);
+        this.appendValueInput("wh")
+            .setCheck(null)
+            .appendField(Blockly.Msg.image_process_imgcut_size);
+        this.setOutput(false, null);
+        this.setTooltip(Blockly.Msg.image_process_imgcut_cutting);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+    }
+}
+
+Blockly.Python['v831_lcd_img_cut'] = function (block) {
+    var xy = Blockly.Python.valueToCode(block, 'xy', Blockly.Python.ORDER_ATOMIC);
+    var wh = Blockly.Python.valueToCode(block, 'wh', Blockly.Python.ORDER_ATOMIC);
+
+    // TODO: Assemble Python into code variable.
+    // TODO: Change ORDER_NONE to the correct strength.
+    var code = `canvas = canvas.crop(${xy},${wh})`;
+    return code;
+};
+Blockly.Blocks.ai_lcd_WH_vision = {
+    init: function () {
+        var _input = this.appendDummyInput();
+        this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL);
+        this.setColour("#f0983e");
+        this.setOutput(!0, "Boolean");
+        _input.appendField(Blockly.Msg.image_process_wh_width);
+        this.appendValueInput("A").setCheck("Number");
+        _input = this.appendDummyInput();
+        _input.appendField(Blockly.Msg.image_process_wh_height)
+        this.appendValueInput("B").setCheck("Number");
+        this.setInputsInline(!0);
+    }
+};
+
+Blockly.Python.ai_lcd_WH_vision = function (block) {
+    var _x = Blockly.Python.valueToCode(block, "A", Blockly.Python.ORDER_ATOMIC);
+    var _y = Blockly.Python.valueToCode(block, "B", Blockly.Python.ORDER_ATOMIC);
+    var code = "" + _x + ", " + _y + "";
+    return [code, Blockly.Python.ORDER_ATOMIC];
+};
+
+Blockly.Blocks['image_resize'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_img_resize);
+        this.appendValueInput("wh")
+            .setCheck(null)
+        this.setOutput(false, null);
+        this.setTooltip(Blockly.Msg.image_process_img_resize);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setInputsInline(true);
+    }
+}
+Blockly.Python['image_resize'] = function (block) {
+    var wh = Blockly.Python.valueToCode(block, 'wh', Blockly.Python.ORDER_ATOMIC);
+    var code = `canvas = canvas.resize(${wh})`
+    return code;
+};
+
+
+Blockly.Blocks['ai_vision_get_threshold_default'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_vision_detection_color_threshold_set)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.ai_vision_detection_color_threshold_set_black, "black"],
+                [Blockly.Msg.ai_vision_detection_color_threshold_set_white, "white"],
+                [Blockly.Msg.ai_vision_detection_color_threshold_set_red, "red"],
+                [Blockly.Msg.ai_vision_detection_color_threshold_set_green, "green"],
+                [Blockly.Msg.ai_vision_detection_color_threshold_set_blue, "blue"],
+                [Blockly.Msg.ai_vision_detection_color_threshold_set_orange, "orange"]
+            ]), "color");
+        this.setOutput(true, null);
+        this.setColour("#f0983e");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('color');
+            var TOOLTIPS = {
+                'black': Blockly.Msg.ai_vision_get_threshold_default_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_detection_color_threshold_set_black),
+                'white': Blockly.Msg.ai_vision_get_threshold_default_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_detection_color_threshold_set_white),
+                'red': Blockly.Msg.ai_vision_get_threshold_default_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_detection_color_threshold_set_red),
+                'green': Blockly.Msg.ai_vision_get_threshold_default_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_detection_color_threshold_set_green),
+                'blue': Blockly.Msg.ai_vision_get_threshold_default_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_detection_color_threshold_set_blue),
+                'orange': Blockly.Msg.ai_vision_get_threshold_default_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_detection_color_threshold_set_orange)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_vision_get_threshold_default'] = function (block) {
+    var dropdown_color = block.getFieldValue('color');
+    // TODO: Assemble Python into code variable.
+
+    if (dropdown_color == "black") {
+        var code = '[[0,40]]';
+    } else if (dropdown_color == "white") {
+        var code = '[[64,100]]';
+    } else if (dropdown_color == "red") {
+        var code = '[[0, 80, 40, 80, 10, 80]]';
+    } else if (dropdown_color == "green") {
+        var code = '[[0, 80, -120, -10, 0, 30]]';
+    } else if (dropdown_color == "blue") {
+        var code = '[0, 80, 30, 100, -120, -60]';
+    } else if (dropdown_color == "orange") {
+        var code = '[[77, 55, 19, 61, 14, 108]]';
+    }
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['image_find_blobs'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_find_blobs);
+        this.appendValueInput("color")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_lane_tracking_setup_threshold);
+        this.appendValueInput("xy")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_find_blobs_start_coord);
+        this.appendValueInput("wh")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_find_blobs_size);
+        this.setOutput(true, null);
+        this.setColour(color);
+        this.setTooltip(Blockly.Msg.image_process_find_blobs);
+        this.setHelpUrl("");
+    }
+}
+
+Blockly.Python['image_find_blobs'] = function (block) {
+    var color = Blockly.Python.valueToCode(block, 'color', Blockly.Python.ORDER_ATOMIC);
+    var xy = Blockly.Python.valueToCode(block, 'xy', Blockly.Python.ORDER_ATOMIC);
+    var wh = Blockly.Python.valueToCode(block, 'wh', Blockly.Python.ORDER_ATOMIC);
+    let code = `img.find_blobs(color = ${color},roi=[${xy} , ${wh}],pixels_threshold=500)`;
+    return [code, Blockly.Python.ORDER_NONE];
+}
+
+
+Blockly.Blocks['ai_vision_get_blobs'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serial_read_data)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(Blockly.Msg.image_get_find_blobs_result)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "0"],
+                [Blockly.Msg.image_start_Y, "1"],
+                [Blockly.Msg.image_start_W, "2"],
+                [Blockly.Msg.image_start_H, "3"],
+                [Blockly.Msg.image_start_CX, "cx"],
+                [Blockly.Msg.image_start_CY, "cy"]
+            ]), "blob_type");
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour("#f0983e");
+        this.setTooltip(Blockly.Msg.image_get_find_blobs_result);
+        this.setHelpUrl("https://docs.singtown.com/micropython/zh/latest/openmvcam/library/omv.image.html?highlight=find_circles");
+    }
+};
+
+Blockly.Python['ai_vision_get_blobs'] = function (block) {
+    var variable_name = block.getFieldValue('varitem');
+    var type = block.getFieldValue('blob_type');
+    // TODO: Assemble Python into code variable.
+    var code = `${variable_name}["${type}"]`;
+    if (type == "cx") {
+        code = `int((${variable_name}[0] + ${variable_name}[2])/2)`
+    } else if (type == "cy") {
+        code = `int((${variable_name}[1] + ${variable_name}[3])/2)`
+    }
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['image_find_lines'] = {
+    init:function() {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_find_lines);
+        this.appendValueInput("color")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_lane_tracking_setup_threshold);
+        this.appendValueInput("xy")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_find_blobs_start_coord);
+        this.appendValueInput("wh")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_find_blobs_size);
+        this.setOutput(true, null);
+        this.setColour(color);
+        this.setTooltip(Blockly.Msg.image_process_find_lines);
+        this.setHelpUrl("");
+    }
+}
+
+Blockly.Python['image_find_lines'] = function(block) {
+    var color = Blockly.Python.valueToCode(block, 'color', Blockly.Python.ORDER_ATOMIC);
+    var xy = Blockly.Python.valueToCode(block, 'xy', Blockly.Python.ORDER_ATOMIC) || '0,0';
+    var wh = Blockly.Python.valueToCode(block, 'wh', Blockly.Python.ORDER_ATOMIC) || '0,0';
+    let code = `img.get_regression(color=${color},roi=[${xy} , ${wh}],area_threshold =1000)`;
+    return [code, Blockly.Python.ORDER_NONE];
+}
+
+Blockly.Blocks["image_get_lines_result"] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serial_read_data)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(Blockly.Msg.image_get_find_blobs_result)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "0"],
+                [Blockly.Msg.image_start_Y, "1"],
+                [Blockly.Msg.image_start_W, "2"],
+                [Blockly.Msg.image_start_H, "3"],
+                [Blockly.Msg.image_start_CX, "cx"],
+                [Blockly.Msg.image_start_CY, "cy"]
+            ]), "blob_type");
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour("#f0983e");
+        this.setTooltip(Blockly.Msg.image_get_find_blobs_result);
+        this.setHelpUrl("");
+    }
+}
+
+
+Blockly.Blocks['ai_lane_tracking_setup'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_vision_lane_tracking_setup);
+        this.appendValueInput("color")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_lane_tracking_setup_threshold);
+        this.appendValueInput("lsize")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_lane_tracking_setup_left);
+        this.appendValueInput("rsize")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_lane_tracking_setup_right);
+        this.appendValueInput("axis")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ai_vision_lane_tracking_setup_axis);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip(Blockly.Msg.ai_vision_lane_tracking_setup);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_lane_tracking_setup'] = function (block) {
+    let code = ``
+    return code
+}
+Blockly.Blocks["image_find_qrcodes"] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_find_qrcodes);
+        this.setOutput(true, null);
+        this.setColour(color);
+        this.setTooltip(Blockly.Msg.image_process_find_qrcodes);
+        this.setHelpUrl("");
+    }   
+};
+
+Blockly.Python["image_find_qrcodes"] = function (block) {
+    var code = "canvas.find_qrcodes()";
+    return [code, Blockly.Python.ORDER_NONE];
+}
+
+
+Blockly.Blocks['image_get_qrcodes_result'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(Blockly.Msg.image_process_get_qrcodes_result)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.ai_vision_pattern_detection_content, "payload"],
+                [Blockly.Msg.ai_vision_pattern_detection_x, "x"],
+                [Blockly.Msg.ai_vision_pattern_detection_y, "y"],
+                [Blockly.Msg.ai_vision_pattern_detection_w, "w1"],
+                [Blockly.Msg.ai_vision_pattern_detection_h, "h2"]
+            ]), "get_info");
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour("#f0983e");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('get_info');
+            var TOOLTIPS = {
+                'payload': Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_content),
+                'data_type': Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_type),
+                'x': Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_x),
+                'y': Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_y),
+                'w': Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_X_Destination),
+                'h': Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_Y_Destination),
+                'w1': Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_w),
+                'h1': Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_h)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['image_get_qrcodes_result'] = function (block) {
+    var variable_name = block.getFieldValue('varitem');
+    var dropdown_name = block.getFieldValue('get_info');
+    // TODO: Assemble Python into code variable.
+    var code = `${variable_name}["${dropdown_name}"]`;
+    if (dropdown_name == "w") {
+        code = `${variable_name}["${dropdown_name}"] + ${variable_name}["x"]`
+    } else if (dropdown_name == "h") {
+        code = `${variable_name}["${dropdown_name}"] + ${variable_name}["y"]`
+    } else if (dropdown_name == "w1") {
+        code = `${variable_name}["w"]`
+    } else if (dropdown_name == "h2") {
+        code = `${variable_name}["h"]`
+    }
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks["image_find_barcodes"] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_find_barcodes);
+        this.setOutput(true, null);
+        this.setColour(color);
+        this.setTooltip(Blockly.Msg.image_process_find_barcodes);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python["image_find_barcodes"] = function (block) {
+    var code = "canvas.find_barcodes()";
+    return [code, Blockly.Python.ORDER_NONE];
+}
+
+Blockly.Blocks['image_get_barcodes_result'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(Blockly.Msg.image_process_get_barcodes_result)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.ai_vision_pattern_detection_content, "payload"],
+                [Blockly.Msg.ai_vision_pattern_detection_x, "x"],
+                [Blockly.Msg.ai_vision_pattern_detection_y, "y"],
+                [Blockly.Msg.ai_vision_pattern_detection_w, "w1"],
+                [Blockly.Msg.ai_vision_pattern_detection_h, "h2"]
+            ]), "get_info");
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour("#f0983e");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('get_info');
+            var TOOLTIPS = {
+                'payload': Blockly.Msg.ai_vision_barcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_content),
+                'x': Blockly.Msg.ai_vision_barcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_x),
+                'y': Blockly.Msg.ai_vision_barcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_y),
+                'w': Blockly.Msg.ai_vision_barcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_X_Destination),
+                'h': Blockly.Msg.ai_vision_barcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_Y_Destination),
+                'w1': Blockly.Msg.ai_vision_barcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_w),
+                'h1': Blockly.Msg.ai_vision_barcode_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_h)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['image_get_barcodes_result'] = function (block) {
+    var variable_name = block.getFieldValue('varitem');
+    var dropdown_name = block.getFieldValue('get_info');
+    // TODO: Assemble Python into code variable.
+    var code = `${variable_name}["${dropdown_name}"]`;
+    if (dropdown_name == "w") {
+        code = `${variable_name}["${dropdown_name}"] + ${variable_name}["x"]`
+    } else if (dropdown_name == "h") {
+        code = `${variable_name}["${dropdown_name}"] + ${variable_name}["y"]`
+    } else if (dropdown_name == "w1") {
+        code = `${variable_name}["w"]`
+    } else if (dropdown_name == "h2") {
+        code = `${variable_name}["h"]`
+    }
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks["image_find_apriltag"] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_find_apriltag);
+        this.setOutput(true, null);
+        this.setColour(color);
+        this.setTooltip(Blockly.Msg.image_process_find_apriltag);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python["image_find_apriltag"] = function (block) {
+    var code = "canvas.find_barcodes()";
+    return [code, Blockly.Python.ORDER_NONE];
+}
+
+Blockly.Blocks['image_get_apriltag_result'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(Blockly.Msg.ai_vision_apriltag_get_info)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.ai_vision_pattern_detection_content, "payload"],
+                [Blockly.Msg.ai_vision_pattern_detection_x, "x"],
+                [Blockly.Msg.ai_vision_pattern_detection_y, "y"],
+                [Blockly.Msg.ai_vision_pattern_detection_w, "w1"],
+                [Blockly.Msg.ai_vision_pattern_detection_h, "h2"]
+            ]), "get_info");
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour("#f0983e");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('get_info');
+            var TOOLTIPS = {
+                'payload': Blockly.Msg.ai_vision_apriltag_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_content),
+                'x': Blockly.Msg.ai_vision_apriltag_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_x),
+                'y': Blockly.Msg.ai_vision_apriltag_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_y),
+                'w': Blockly.Msg.ai_vision_apriltag_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_X_Destination),
+                'h': Blockly.Msg.ai_vision_apriltag_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_Y_Destination),
+                'w1': Blockly.Msg.ai_vision_apriltag_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_w),
+                'h1': Blockly.Msg.ai_vision_apriltag_get_info_TOOLTIP.replace('%1', Blockly.Msg.ai_vision_pattern_detection_h)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['image_get_apriltag_result'] = function (block) {
+    var variable_name = block.getFieldValue('varitem');
+    var dropdown_name = block.getFieldValue('get_info');
+    // TODO: Assemble Python into code variable.
+    var code = `${variable_name}["${dropdown_name}"]`;
+    if (dropdown_name == "w") {
+        code = `${variable_name}["${dropdown_name}"] + ${variable_name}["x"]`
+    } else if (dropdown_name == "h") {
+        code = `${variable_name}["${dropdown_name}"] + ${variable_name}["y"]`
+    } else if (dropdown_name == "w1") {
+        code = `${variable_name}["w"]`
+    } else if (dropdown_name == "h2") {
+        code = `${variable_name}["h"]`
+    }
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+// 视频处理
+const videoColor = "#4d9994"
+Blockly.Blocks["record_video"] = {
+    init:function () { 
+        this.appendDummyInput().appendField("视频录制设置")
+        this.appendValueInput("time")
+            .setCheck(null)
+            .appendField("录制时长")
+        this.appendValueInput("save_path")
+            .setCheck(null)
+            .appendField("保存路径");
+        this.setNextStatement(true, null);
+        this.setPreviousStatement(true, null);
+        this.setColour(videoColor);
+        this.setTooltip("设置视频录制参数");
+
+    }
+}
+
+Blockly.Python['record_video'] = function(block) { 
+    return ""
+};
+
+Blockly.Blocks['play_video'] = { 
+    init: function() { 
+        this.appendDummyInput()
+            .appendField('播放视频');
+        this.appendValueInput("video_path")
+            .setCheck(null)
+            .appendField("视频路径");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(videoColor);
+
+    }
+}
+
+Blockly.Python['play_video'] = function(block) { 
+    let code = '播放视频\n';
+    return code;
+};
+
+
+export default Blockly

+ 801 - 0
src/Blockly/blocks/ai.js

@@ -0,0 +1,801 @@
+import * as Blockly from "blockly"
+import { pythonGenerator } from "blockly/python"
+import { getAllGobalVariables } from "../../utils/blocklyFunction"
+
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) }
+
+const aiColor = "#ee783a"
+
+Blockly.Blocks['ai_set_object_classification'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("开始物体分类识别");
+        this.setPreviousStatement(true, null)
+        this.setNextStatement(true, null)
+        this.setColour(aiColor);
+        this.setTooltip("开始物体分类识别");
+    }
+}
+
+Blockly.Python['ai_set_object_classification'] = function (block) {
+    var code = 'ai.set_object_classification()\n';
+    return code;
+};
+
+Blockly.Blocks['ai_get_object_classification_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取物体分类的")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取物体分类结果");
+    }
+}
+
+Blockly.Python['ai_get_object_classification_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_classification_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_object_detection_is_result'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_model_digital_new_text)
+        this.appendStatementInput("input")
+            .setCheck(null)
+            .appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);
+        this.itemCount_ = 0;
+        this.updateShape_();
+        this.setMutator(new Blockly.icons.MutatorIcon(['ai_model_false_create_with_item'], this));
+        this.setColour(aiColor);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setTooltip("");
+        this.setHelpUrl("");
+    },
+    mutationToDom: function () {
+        if (!this.itemCount_)
+            return null;
+        var container = document.createElement('mutation');
+        this.itemCount_ && container.setAttribute('aielse', 1);
+        return container;
+    },
+    domToMutation: function (a) {
+        this.itemCount_ = parseInt(a.getAttribute('aielse'), 10);
+        this.updateShape_();
+    },
+    decompose: function (a) {
+        var b = a.newBlock('ai_model_false_create_with_container');
+        b.initSvg();
+        var c = b.nextConnection
+        this.itemCount_ && (a = a.newBlock("ai_model_false_create_with_item"),
+            a.initSvg(),
+            c.connect(a.previousConnection));
+        console.log("this.elseCount_", a)
+        return b
+    },
+    compose: function (a) {
+        var b = a.nextConnection.targetBlock();
+        this.itemCount_ = 0;
+        var e = null;
+        if (b && b.type === "ai_model_false_create_with_item") {
+            this.itemCount_++;
+            e = b.statementConnection_;
+            b = b.nextConnection && b.nextConnection.targetBlock()
+        }
+        this.updateShape_()
+        Blockly.icons.MutatorIcon.reconnect(e, this, "AIELSE")
+    },
+    saveConnections: function (a) {
+        a = a.nextConnection.targetBlock();
+        var AIELSE = ""
+        if (a && a.type === "ai_model_false_create_with_item") {
+            AIELSE = this.getInput("AIELSE");
+            a.statementConnection_ = AIELSE && AIELSE.connection.targetConnection;
+
+            a = a.nextConnection && a.nextConnection.targetBlock()
+        }
+    },
+    updateShape_: function () {
+        this.getInput("AIELSE") && this.removeInput("AIELSE");
+        this.itemCount_ && this.appendStatementInput("AIELSE").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE)
+    },
+};
+
+Blockly.Blocks['ai_model_false_create_with_container'] = {
+    init: function () {
+        this.setColour(aiColor);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);
+        this.setNextStatement(true)
+        this.setTooltip('');
+        this.contextMenu = false;
+    }
+};
+
+Blockly.Blocks['ai_model_false_create_with_item'] = {
+    init: function () {
+        this.setColour(aiColor);
+        this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE);
+        this.setPreviousStatement(!0);
+        this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP);
+        this.contextMenu = !1
+    }
+};
+
+Blockly.Python['ai_get_object_detection_is_result'] = function (block) {
+    var statements_input = Blockly.Python.statementToCode(block, 'input');
+    var statements_input1 = Blockly.Python.statementToCode(block, 'AIELSE');
+    let global = getAllGobalVariables(block)
+    Blockly.Python.definitions_['objectStatements'] = `def objectStatements(BOXESI):
+  ${global != '' ? `global ${global}` : ''}
+${statements_input}
+`
+    var code = `if (len(BOXES)):
+  for BOXESI in BOXES:
+    digitalStatements(BOXESI)
+else:
+${statements_input1 != "" ? statements_input1 : "    pass"}
+`
+    return code;
+};
+
+Blockly.Blocks['ai_set_object_detection'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("开始物体检测");
+        this.setPreviousStatement(true, null)
+        this.setNextStatement(true, null)
+        this.setColour(aiColor);
+        this.setTooltip("开始物体检测");
+    }
+}
+Blockly.Python['ai_set_object_detection'] = function (block) {
+    var code = 'ai.set_object_detection()\n';
+    return code;
+};
+
+Blockly.Blocks['ai_get_object_detection_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取物体检测结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取物体检测结果");
+    }
+}
+
+Blockly.Python['ai_get_object_detection_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+
+Blockly.Blocks['ai_set_face_and_keypoint_detection'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始人脸关键点检测");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+
+Blockly.Python['ai_set_face_and_keypoint_detection'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_face_and_keypoint_detection_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取人脸检测结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取人脸检测结果");
+    }
+}
+
+Blockly.Python['ai_get_face_and_keypoint_detection_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_facial_Keypoint_detection'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始人脸多关键点检测");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+
+Blockly.Python['ai_set_facial_Keypoint_detection'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_facial_Keypoint_detection_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取人脸多关键点检测结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取人脸多关键点检测结果");
+    }
+}
+
+Blockly.Python['ai_get_facial_Keypoint_detection_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_face_recognition'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始人脸识别");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+Blockly.Python['ai_set_face_recognition'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_face_recognition_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取人脸识别结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取人脸识别结果");
+    }
+}
+Blockly.Python['ai_get_face_recognition_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_facial_expression_recognition'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始情绪识别");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+
+Blockly.Python['ai_set_facial_expression_recognition'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_facial_expression_recognition_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取情绪识别结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取情绪识别结果");
+    }
+}
+
+Blockly.Python['ai_get_facial_expression_recognition_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_human_keypoint_detection'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始人体检测");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+
+Blockly.Python['ai_set_human_keypoint_detection'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_human_keypoint_detection_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取人体检测结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取人体检测结果");
+    }
+}
+
+Blockly.Python['ai_get_human_keypoint_detection_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_self_learning_classifier_init'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField("自学分类器初始化");
+        this.appendValueInput("class_input")
+            .setCheck(null)
+            .appendField("设置识别的名字");
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip(Blockly.Msg.ai_model_self_learning_load);
+        this.setHelpUrl("");
+    }
+}
+
+Blockly.Python['ai_set_self_learning_classifier_init'] = function (block) {
+    var value_class_input = Blockly.Python.valueToCode(block, 'class_input', Blockly.Python.ORDER_ATOMIC);
+    var code = value_class_input + '.init()\n';
+    return code;
+};
+
+Blockly.Blocks['ai_set_self_learning_classifier_add_train_data'] = {
+    init: function () {
+        this.appendDummyInput().appendField('添加训练数据')
+        this.setColour(aiColor);
+        this.setTooltip('添加训练数据');
+        this.setHelpUrl("");
+        this.setNextStatement(true);
+        this.setPreviousStatement(true);
+    }
+};
+
+Blockly.Python['ai_set_self_learning_classifier_add_train_data'] = function (block) {
+    var code = '.train()\n';
+    return code;
+};
+
+Blockly.Blocks['ai_set_self_learning_classifier_save_model'] = {
+    init: function () {
+        this.appendDummyInput().appendField('保存模型')
+        this.setNextStatement(true);
+        this.setColour(aiColor);
+        this.setTooltip('保存模型');
+        this.setPreviousStatement(true);
+    }
+}
+
+Blockly.Python['ai_set_self_learning_classifier_save_model'] = function (block) {
+    let code = ""
+    return code;
+};
+
+Blockly.Blocks['ai_set_self_learning_classifier_load_model'] = {
+    init: function () {
+        this.appendDummyInput().appendField('加载保存模型')
+        this.setNextStatement(true);
+        this.setColour(aiColor);
+        this.setTooltip('加载保存模型');
+        this.setPreviousStatement(true);
+    }
+}
+Blockly.Python['ai_set_self_learning_classifier_load_model'] = function (block) {
+    let code = ""
+    return code;
+};
+
+Blockly.Blocks['ai_set_self_learning_classifier_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField('自学习识别结果')
+            .appendField(new Blockly.FieldDropdown([
+                ["名称", "name"],
+                ["置信度", "confidence"]
+            ]), "TYPE");
+        this.setNextStatement(true);
+        this.setColour(aiColor);
+        this.setTooltip('加载保存模型');
+        this.setPreviousStatement(true);
+    }
+}
+Blockly.Python['ai_set_self_learning_classifier_result'] = function (block) {
+    let code = ""
+    return code;
+};
+
+Blockly.Blocks['ai_set_object_trajectory_tracking_and_counting'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始物体轨迹识别");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+Blockly.Python['ai_set_object_trajectory_tracking_and_counting'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_object_trajectory_tracking_and_counting_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取物体轨迹结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取物体轨迹结果");
+    }
+}
+Blockly.Python['ai_set_object_trajectory_tracking_and_counting_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_ocr_text_recognition'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始文字识别");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+Blockly.Python['ai_set_ocr_text_recognition'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_ocr_text_recognition_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取文字识别结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取文字识别结果");
+    }
+}
+Blockly.Python['ai_get_ocr_text_recognition_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_gesture_recognition'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始手势识别");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+Blockly.Python['ai_set_gesture_recognition'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_gesture_recognition_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取手势识别结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取手势识别结果");
+    }
+}
+Blockly.Python['ai_set_gesture_recognition_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_pose_recognition'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始姿态识别");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+Blockly.Python['ai_set_pose_recognition'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_pose_recognition_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取姿态识别结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取姿态识别结果");
+    }
+}
+Blockly.Python['ai_set_pose_recognition_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+// 语音识别
+Blockly.Blocks['ai_set_real_time_speech_recognition'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始语音识别");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+Blockly.Python['ai_set_real_time_speech_recognition'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_real_time_speech_recognition_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取语音识别结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取语音识别结果");
+    }
+}
+Blockly.Python['ai_get_real_time_speech_recognition_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_keyword_recognition'] = {
+    init: function () {
+        this.appendDummyInput().appendField("开始关键词识别");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(aiColor);
+        this.setTooltip("");
+
+    }
+}
+Blockly.Python['ai_set_keyword_recognition'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_get_keyword_recognition_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取关键词识别结果")
+            .appendField(Blockly.Msg.ai_vision_from)
+            .appendField(new Blockly.FieldVariable("i"), "varitem")
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_start_X, "x"],
+                [Blockly.Msg.image_start_Y, "y"],
+                [Blockly.Msg.image_start_W, "w"],
+                [Blockly.Msg.image_start_H, "h"],
+                [Blockly.Msg.image_start_result, "result"],
+                [Blockly.Msg.image_start_confidence, "confidence"]
+            ]), "from");
+        this.setColour(aiColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取关键词识别结果");
+    }
+}
+Blockly.Python['ai_get_keyword_recognition_result'] = function (block) {
+    var from = block.getFieldValue('from');
+    var code = 'ai.get_object_detection_result("' + from + '")';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+
+
+// AIGC
+const AIGCColor = "#0000FF"
+Blockly.Blocks['Initialize_the_AIGC_large_model'] = {
+    init: function () {
+        this.appendDummyInput().appendField("初始化AIGC大模型")
+            .appendField(new Blockly.FieldDropdown([
+                ["Qwen", "Qwen"],
+                ["DeepSeek", "DeepSeek"],
+                ["InternVl", "InternVl"]
+            ]),"selectModel");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(AIGCColor);
+        this.setTooltip("");
+    }
+}
+Blockly.Python['Initialize_the_AIGC_large_model'] = function (block) {
+    var selectModel = block.getFieldValue('selectModel');
+    var code = 'ai.initialize_the_AIGC_large_model()';
+    return code;
+}
+
+Blockly.Blocks['ai_set_aigc_image_generation'] = {
+    init: function () {
+        this.appendDummyInput().appendField("设置提问的问题")
+        this.appendValueInput("generation").setCheck(null);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(AIGCColor);
+        this.setTooltip("");
+        this.setInputsInline(true);
+    }
+}
+
+Blockly.Python['ai_set_aigc_image_generation'] = function (block) {
+    var generation = Blockly.Python.valueToCode(block, 'generation', Blockly.Python.ORDER_ATOMIC);
+    var code = 'ai.set_aigc_image_generation(' + generation + ')\n';
+    return code;
+}
+
+Blockly.Blocks['ai_get_aigc_image_generation_result'] = {
+    init: function () {
+        this.appendDummyInput().appendField("获取AIGC大模型生成结果");
+        this.setColour(AIGCColor);
+        this.setOutput(true, null);
+        this.setTooltip("获取AIGC大模型生成结果");
+    }
+}
+Blockly.Python['ai_get_aigc_image_generation_result'] = function (block) {
+    var code = 'ai.get_aigc_image_generation_result()';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks['ai_set_ai_agent'] = {
+    init: function () {
+        this.appendValueInput("NAME")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ChatGpt_ai_agent_chat_set_appID);
+        this.appendValueInput("NAME1")
+            .setCheck(null)
+            .appendField(Blockly.Msg.ChatGpt_set_problem_content);
+        this.appendDummyInput().appendField(Blockly.Msg.ChatGpt_ai_agent_chat_result)
+        this.setOutput(true, null);
+        this.setInputsInline(false);
+        this.setColour(AIGCColor);
+        this.setTooltip(Blockly.Msg.ai_set_ai_agent_title);
+        this.setHelpUrl("");
+    }
+}
+Blockly.Python['ai_set_ai_agent'] = function (block) {
+    var appID = Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_ATOMIC);
+    var problem = Blockly.Python.valueToCode(block, 'NAME1', Blockly.Python.ORDER_ATOMIC);
+    var code = 'ai.set_ai_agent(' + appID + ',' + problem + ')';
+    return code;
+}
+
+
+export default Blockly;

+ 1375 - 525
src/Blockly/blocks/basic.js

@@ -1,608 +1,1458 @@
 /* eslint-disable no-unused-expressions */
 import * as Blockly from 'blockly';
-// import { pythonGenerator } from "blockly/python";
-import CategoryColors from './define_color'
+import { pythonGenerator } from 'blockly/python';
+import { getBlocksByTypeName } from "../../utils/blocklyFunction"
 
-// Blockly.Python = pythonGenerator
-Blockly.Blocks['custom_text_block'] = {
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) };
+// 基础
+const basicColor = "#d42b03";
+Blockly.Blocks['ai_v831_button_read_pressed'] = {
     init: function () {
         this.appendDummyInput()
-            .appendField(Blockly.Msg.numpy_mnist_clear)
-            .appendField(new Blockly.FieldTextInput("张三丰"), "TEXT_INPUT");
-        // this.setOutput(true, null);
-        this.setPreviousStatement(true, null)
-        this.setNextStatement(true, null)
-        this.setTooltip("");
+            .appendField(Blockly.Msg.ai_basic_button_when)
+            .appendField(new Blockly.FieldDropdown([
+                ["A", "A"],
+                ["B", "B"],
+                ["C", "C"],
+                ["D", "D"]
+            ]), "button_type")
+            .appendField(Blockly.Msg.ai_basic_pressed)
+        this.setOutput(true, null);
+        this.setColour(basicColor);
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('button_type');
+            console.log(mode)
+            var TOOLTIPS = {
+                'A': Blockly.Msg.ai_k210_button_read_pressed_TOOLTIP.replace('%1', "A"),
+                'B': Blockly.Msg.ai_k210_button_read_pressed_TOOLTIP.replace('%1', "B"),
+                'C': Blockly.Msg.ai_k210_button_read_pressed_TOOLTIP.replace('%1', "C"),
+                'D': Blockly.Msg.ai_k210_button_read_pressed_TOOLTIP.replace('%1', "D"),
+            };
+            return TOOLTIPS[mode];
+        });
         this.setHelpUrl("");
-        this.setStyle('custom_text_blocks')
     }
 };
-Blockly.Blocks["CocoRobo_return"] = {
+
+Blockly.Python['ai_v831_button_read_pressed'] = function (block) {
+    var _type = block.getFieldValue('button_type');
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_CocoPi_BUTTON'] = `from CocoPi import BUTTON`
+    // Blockly.Python.definitions_['v831_import_CocoPi'] = `sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_define_x_button'] = `key_A = BUTTON(14)
+key_B = BUTTON(8)
+key_C = BUTTON(13)
+key_D = BUTTON(7)
+`
+
+    var code = `key_${_type}.is_pressed()`
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
+};
+
+Blockly.Blocks['ai_v831_button_read_released'] = {
     init: function () {
-        this.jsonInit({
-            inputsInline: !0,
-            nextStatement: null,
-            previousStatement: null,
-            colour: CategoryColors.Logic,
-            tooltip: Blockly.Msg.CocoRobo_RETURN_TOOLTIP,
-            message0: Blockly.Msg.CocoRobo_RETURN_MESSAGE0,
-            args0: [{
-                type: "input_value",
-                name: "VAR"
-            }]
-        })
-    }
-}
-Blockly.Blocks.CocoRobo_try_except = {
-    init: function () {
-        this.jsonInit({
-            message0: "",
-            previousStatement: null,
-            nextStatement: null,
-            colour: CategoryColors.Logic,
-            tooltip: Blockly.Msg.CocoRobo_try_except_TOOLTIP,
-            helpUrl: ""
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_basic_button_when)
+            .appendField(new Blockly.FieldDropdown([
+                ["A", "A"],
+                ["B", "B"],
+                ["C", "C"],
+                ["D", "D"]
+            ]), "button_type_released")
+            .appendField(Blockly.Msg.ai_basic_released)
+        this.setOutput(true, null);
+        this.setColour("#d42b03");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('button_type_released');
+            var TOOLTIPS = {
+                'A': Blockly.Msg.ai_k210_button_read_released_TOOLTIP.replace('%1', "A"),
+                'B': Blockly.Msg.ai_k210_button_read_released_TOOLTIP.replace('%1', "B"),
+                'C': Blockly.Msg.ai_k210_button_read_released_TOOLTIP.replace('%1', "C"),
+                'D': Blockly.Msg.ai_k210_button_read_released_TOOLTIP.replace('%1', "D"),
+            };
+            return TOOLTIPS[mode];
         });
-        this.appendStatementInput("TRY").appendField("try");
-        this.appendStatementInput("EXCEPT").appendField("except");
+        this.setHelpUrl("");
     }
-}
+};
 
-Blockly.Blocks.CocoRobo_try_except_finally = {
+Blockly.Python['ai_v831_button_read_released'] = function (block) {
+    var _type = block.getFieldValue('button_type_released');
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_CocoPi_BUTTON'] = `from CocoPi import BUTTON`
+    // Blockly.Python.definitions_['v831_import_CocoPi'] = `sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_define_x_button'] = `key_A = BUTTON(14)
+key_B = BUTTON(8)
+key_C = BUTTON(13)
+key_D = BUTTON(7)
+`
+
+    var code = `key_${_type}.is_pressed() == False`
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
+};
+Blockly.Blocks['ai_v831_led_light_up'] = {
     init: function () {
-        this.jsonInit({
-            message0: "",
-            previousStatement: null,
-            nextStatement: null,
-            colour: CategoryColors.Logic,
-            tooltip: Blockly.Msg.CocoRobo_try_except_finally_TOOLTIP,
-            helpUrl: ""
-        });
-        this.appendStatementInput("TRY").appendField("try");
-        this.appendStatementInput("EXCEPT").appendField("except");
-        this.appendStatementInput("FINALLY").appendField("finally")
-    }
-};
-
-Blockly.Blocks.CocoRobo_type = {
-    init: function () {
-        this.jsonInit({
-            message0: "值 %1 的类型",
-            args0: [{
-                type: "input_value",
-                name: "VAR"
-            }],
-            output: null,
-            colour: CategoryColors.Logic,
-            tooltip: "返回当前值的类型",
-            helpUrl: ""
-        })
-    }
-};
-Blockly.Blocks.CocoRobo_type_is = {
-    init: function () {
-        this.jsonInit({
-            message0: '值 %1 的类型为 %2',
-            args0: [{
-                type: "input_value",
-                name: "VAR"
-            }, {
-                name: "TYPE",
-                options: [
-                    ["int", "int"],
-                    ["float", "float"],
-                    ["bool", "bool"],
-                    ["str", "str"],
-                    ["list", "list"],
-                    ["tuple", "tuple"],
-                    ["set", "set"],
-                    ["dict", "dict"],
-                    ["bytes", "bytes"],
-                    ["bytearray", "bytearray"],
-                    ["complex", "complex"]
-                ],
-                type: "field_dropdown"
-            }],
-            output: "Boolean",
-            colour: CategoryColors.Logic,
-            // tooltip: Blockly.Msg.CocoRobo_TYPE_IS_TOOLTIP,
-            helpUrl: Blockly.Msg.CocoRobo_TYPE_IS_HELPURL
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_basic_led_set)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.ai_basic_led_blue, "blue"],
+                // [Blockly.Msg.ai_basic_led_red, "red"]
+            ]), "type")
+            .appendField(Blockly.Msg.ai_basic_led_on);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour("#d42b03");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('type');
+            var TOOLTIPS = {
+                'blue': Blockly.Msg.ai_k210_led_light_up_TOOLTIP.replace('%1', Blockly.Msg.ai_basic_led_blue),
+                'red': Blockly.Msg.ai_k210_led_light_up_TOOLTIP.replace('%1', Blockly.Msg.ai_basic_led_red)
+            };
+            return TOOLTIPS[mode];
         });
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_v831_led_light_up'] = function (block) {
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_smbus2'] = `import smbus2`
+    Blockly.Python.definitions_['import_time'] = `import time`
+    Blockly.Python.definitions_['import_CocoPi_LED'] = `from CocoPi import LED
+LED = LED()
+`
+    // TODO: Assemble Python into code variable.
+    var code = `LED.out(1)
+`;
+    return code;
+};
+
+Blockly.Blocks['ai_v831_led_light_off'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_basic_led_set)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.ai_basic_led_blue, "blue"],
+                // [Blockly.Msg.ai_basic_led_red, "red"]
+            ]), "type")
+            .appendField(Blockly.Msg.ai_basic_led_off);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour("#d42b03");
         var thisBlock = this;
         this.setTooltip(function () {
-            return Blockly.Msg.CocoRobo_TYPE_IS_TOOLTIP.replace('%2',
-                thisBlock.getFieldValue('TYPE'));
+            var mode = thisBlock.getFieldValue('type');
+            var TOOLTIPS = {
+                'blue': Blockly.Msg.ai_k210_led_light_off_TOOLTIP.replace('%1', Blockly.Msg.ai_basic_led_blue),
+                'red': Blockly.Msg.ai_k210_led_light_off_TOOLTIP.replace('%1', Blockly.Msg.ai_basic_led_red)
+            };
+            return TOOLTIPS[mode];
         });
+        this.setHelpUrl("");
     }
 };
-Blockly.Blocks.CocoRobo_eval = {
+
+Blockly.Python['ai_v831_led_light_off'] = function (block) {
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_smbus2'] = `import smbus2`
+    Blockly.Python.definitions_['import_time'] = `import time`
+    Blockly.Python.definitions_['import_CocoPi_LED'] = `from CocoPi import LED
+LED = LED()
+`
+    // TODO: Assemble Python into code variable.
+    var code = `LED.out(0)
+`;
+    return code;
+};
+
+Blockly.Blocks['ai_v831_rgb_light_up'] = {
     init: function () {
-        this.jsonInit({
-            message0: '计算表达式 %1 的结果',
-            args0: [{
-                check: "String",
-                type: "input_value",
-                name: "VAR"
-            }],
-            output: null,
-            colour: CategoryColors.Logic,
-            tooltip: '计算字符串表达式,并返回结果',
-            helpUrl: ""
-        })
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_basic_rgb_set_on)
+        this.appendValueInput("rgb_value")
+            .setCheck(null)
+            .appendField("");
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.LED_BRTN).appendField(new Blockly.FieldNumber(50, 0, 255), "uart_bps");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour("#d42b03");
+        this.setTooltip(Blockly.Msg.ai_basic_rgb_set_on);
+        this.setHelpUrl("");
     }
 };
 
-const HUE = "#9d64fd"
-Blockly.Blocks.controls_repeat_forever = {
+Blockly.Python['ai_v831_rgb_light_up'] = function (block) {
+    var value_name = Blockly.Python.valueToCode(block, 'rgb_value', Blockly.Python.ORDER_ATOMIC);
+    var content = block.getFieldValue('uart_bps');
+    console.log(value_name.slice(1, -1))
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_smbus2'] = `import smbus2`
+    Blockly.Python.definitions_['import_time'] = `import time`
+    Blockly.Python.definitions_['import_CocoPi_RGB'] = `from CocoPi import singleRgb
+singleRgb=singleRgb()`;
+
+    var code = `singleRgb.setBrightness(${content})
+singleRgb.setColor(${value_name.slice(1, -1)})
+singleRgb.show()
+time.sleep(0.05)
+`;
+    return code;
+};
+
+Blockly.Blocks['ai_v831_rgb_light_off'] = {
     init: function () {
-        this.jsonInit({
-            message0: Blockly.Msg.CONTROLS_REPEAT_FOREVER,
-            previousStatement: null,
-            nextStatement: null,
-            colour: HUE,
-            tooltip: Blockly.Msg.CONTROLS_REPEAT_FOREVER_TOOLTIP,
-            helpUrl: Blockly.Msg.CONTROLS_REPEAT_HELPURL
-        });
-        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)
-    }
-};
-Blockly.Blocks.controls_repeat_ext = {
-    init: function () {
-        this.jsonInit({
-            message0: Blockly.Msg.CONTROLS_REPEAT_TITLE,
-            args0: [{
-                type: "input_value",
-                name: "TIMES",
-                check: "Number"
-            }],
-            previousStatement: null,
-            nextStatement: null,
-            colour: HUE,
-            tooltip: Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,
-            helpUrl: Blockly.Msg.CONTROLS_REPEAT_HELPURL
-        });
-        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)
-    }
-};
-Blockly.Blocks.controls_repeat = {
-    init: function () {
-        this.jsonInit({
-            message0: Blockly.Msg.CONTROLS_REPEAT_TITLE,
-            args0: [{
-                type: "field_number",
-                name: "TIMES",
-                value: 10,
-                min: 0,
-                precision: 1
-            }],
-            previousStatement: null,
-            nextStatement: null,
-            colour: HUE,
-            tooltip: Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,
-            helpUrl: Blockly.Msg.CONTROLS_REPEAT_HELPURL
-        });
-        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ai_basic_rgb_set_off)
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour("#d42b03");
+        this.setTooltip(Blockly.Msg.ai_basic_rgb_set_off);
+        this.setHelpUrl("");
     }
 };
-Blockly.Blocks.controls_whileUntil = {
+
+Blockly.Python['ai_v831_rgb_light_off'] = function (block) {
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_smbus2'] = `import smbus2`
+    Blockly.Python.definitions_['import_time'] = `import time`
+    Blockly.Python.definitions_['import_CocoPi_RGB'] = `from CocoPi import singleRgb
+singleRgb=singleRgb()`;
+
+    // TODO: Assemble Python into code variable.
+    var code = `singleRgb.setColor(0,0,0)
+singleRgb.show()
+time.sleep(0.05)
+`;
+    return code;
+};
+
+Blockly.Blocks['ai_lcd_rgb_value_input'] = {
     init: function () {
-        var a = [[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE, "WHILE"], [Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL, "UNTIL"]];
-        this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);
-        this.setColour(HUE);
-        this.appendValueInput("BOOL").setCheck("Boolean").appendField(new Blockly.FieldDropdown(a), "MODE");
-        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);
-        this.setPreviousStatement(!0);
-        this.setNextStatement(!0);
-        var b = this;
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.rgb_R);
+        this.appendValueInput("rgb_value_r")
+            .setCheck(null)
+            .appendField("");
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.rgb_G);
+        this.appendValueInput("rgb_value_g")
+            .setCheck(null)
+            .appendField("");
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.rgb_B);
+        this.appendValueInput("rgb_value_b")
+            .setCheck(null)
+            .appendField("");
+        this.setInputsInline(true);
+        this.setOutput(true, null);
+        this.setColour("#5bb2d6");
+        this.setTooltip(Blockly.Msg.ai_lcd_rgb_value_input_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_lcd_rgb_value_input'] = function (block) {
+    var value_rgb_value_r = Blockly.Python.valueToCode(block, 'rgb_value_r', Blockly.Python.ORDER_ATOMIC);
+    var value_rgb_value_g = Blockly.Python.valueToCode(block, 'rgb_value_g', Blockly.Python.ORDER_ATOMIC);
+    var value_rgb_value_b = Blockly.Python.valueToCode(block, 'rgb_value_b', Blockly.Python.ORDER_ATOMIC);
+    // TODO: Assemble Python into code variable.
+    var code = '' + value_rgb_value_r + ',' + value_rgb_value_g + ',' + value_rgb_value_b + '';
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+
+const SensorsColor = "#5fcd8e";
+Blockly.Blocks['esp32_main_controller_get_light'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.basic_light_get);
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour(SensorsColor);
+        this.setTooltip(Blockly.Msg.basic_light_get);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['esp32_main_controller_get_light'] = function (block) {
+    Blockly.Python.definitions_['import_LIGHTINTENSITY'] = `class v83x_ADC():
+    def __init__(self, addr=b"0x05070080") -> None:
+        self.addr = addr
+        self.path = "/sys/class/sunxi_dump/dump"
+        self.file = open(self.path, "wb+")
+        self.last = self.value()
+    def __del__(self):
+        try:
+            if self.file:
+                self.file.close()
+                del self.file
+        except Exception as e:
+            pass
+    def value(self):
+        self.file.write(b"0x05070080")
+        self.file.seek(0)
+        return int(self.file.read()[:-1], 16)
+
+v831_adc0 = v83x_ADC()
+`
+    var code = 'v831_adc0.value()';
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
+};
+
+Blockly.Blocks['esp32_main_controller_get_environmental_value'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ESP32_ENV_GET_TEXT)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.basic_temperature, "temperature"],
+                [Blockly.Msg.basic_humidity, "humidity"]
+            ]), "env_get_type")
+            .appendField(Blockly.Msg.basic_env_value);
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour(SensorsColor);
+        this.setHelpUrl("");
+        var thisBlock = this;
         this.setTooltip(function () {
-            var a = b.getFieldValue("MODE");
-            return {
-                WHILE: Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE,
-                UNTIL: Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL
-            }[a]
-        })
-    }
-};
-Blockly.Blocks.controls_for = {
-    init: function () {
-        this.jsonInit({
-            message0: Blockly.Msg.CONTROLS_FOR_TITLE,
-            args0: [{
-                type: "field_variable",
-                name: "VAR",
-                variable: null
-            }, {
-                type: "input_value",
-                name: "FROM",
-                check: "Number",
-                align: "RIGHT"
-            }, {
-                type: "input_value",
-                name: "TO",
-                check: "Number",
-                align: "RIGHT"
-            }, {
-                type: "input_value",
-                name: "BY",
-                check: "Number",
-                align: "RIGHT"
-            }],
-            inputsInline: !0,
-            previousStatement: null,
-            nextStatement: null,
-            colour: HUE,
-            helpUrl: Blockly.Msg.CONTROLS_FOR_HELPURL
+            var mode = thisBlock.getFieldValue('env_get_type');
+            var TOOLTIPS = {
+                'temperature': Blockly.Msg.Esp32_Main_Controller_Get_Environmental_Value_TOOLTIP.replace('%1', Blockly.Msg.basic_temperature),
+                'humidity': Blockly.Msg.Esp32_Main_Controller_Get_Environmental_Value_TOOLTIP.replace('%1', Blockly.Msg.basic_humidity)
+            };
+            return TOOLTIPS[mode];
         });
-        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_FOR_INPUT_DO);
-        var a = this;
+    }
+};
+
+Blockly.Python['esp32_main_controller_get_environmental_value'] = function (block) {
+    var _type_selected = block.getFieldValue('env_get_type');
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_AHT20'] = `from CocoPi import AHT20`
+    // Blockly.Python.definitions_['v831_import_CocoPi'] = `sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_AHT20_object'] = `aht20 = AHT20(2)`
+
+    let code = ''
+    if (_type_selected == 'temperature') {
+        code = `aht20.get_temperature()`
+    } else if (_type_selected == 'humidity') {
+        code = `aht20.get_humidity()`;
+    } else {
+        code = _type_selected;
+    }
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
+};
+
+Blockly.Blocks['esp32_main_controller_motion_acceleration'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.basic_motion_get_along)
+            .appendField(new Blockly.FieldDropdown([
+                ["X", "4"],
+                ["Y", "3"],
+                ["Z", "5"]
+            ]), "accel_type")
+            .appendField(Blockly.Msg.basic_motion_accel);
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour(SensorsColor);
+        var thisBlock = this;
         this.setTooltip(function () {
-            return Blockly.Msg.CONTROLS_FOR_TOOLTIP.replace("%1", a.getFieldValue("VAR"))
-        })
-    },
-    // customContextMenu: function (a) {
-    //     if (!this.isCollapsed()) {
-    //         var b = {
-    //             enabled: !0
-    //         }
-    //             , c = this.getFieldValue("VAR");
-    //         b.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1", c);
-    //         c = goog.dom.createDom("field", null, c);
-    //         c.setAttribute("name", "VAR");
-    //         c = goog.dom.createDom("block", null, c);
-    //         c.setAttribute("type", "variables_get");
-    //         b.callback = Blockly.ContextMenu.callbackFactory(this, c);
-    //         a.push(b)
-    //     }
-    // }
-};
-Blockly.Blocks.controls_forEach = {
-    init: function () {
-        this.jsonInit({
-            message0: Blockly.Msg.CONTROLS_FOREACH_TITLE,
-            args0: [{
-                type: "field_variable",
-                name: "VAR",
-                variable: null
-            }, {
-                type: "input_value",
-                name: "LIST",
-                check: "Array"
-            }],
-            previousStatement: null,
-            nextStatement: null,
-            colour: HUE,
-            helpUrl: Blockly.Msg.CONTROLS_FOREACH_HELPURL
+            var mode = thisBlock.getFieldValue('accel_type');
+            var TOOLTIPS = {
+                '4': Blockly.Msg.Esp32_Main_Controller_Motion_Acceleration_TOOLTIP.replace('%1', 'X'),
+                '3': Blockly.Msg.Esp32_Main_Controller_Motion_Acceleration_TOOLTIP.replace('%1', 'Y'),
+                '5': Blockly.Msg.Esp32_Main_Controller_Motion_Acceleration_TOOLTIP.replace('%1', 'Z')
+            };
+            return TOOLTIPS[mode];
         });
-        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_DO);
-        var a = this;
-        this.setTooltip(function () {
-            return Blockly.Msg.CONTROLS_FOREACH_TOOLTIP.replace("%1", a.getFieldValue("VAR"))
-        })
-    },
-    customContextMenu: Blockly.Blocks.controls_for.customContextMenu
-};
-Blockly.Blocks.controls_flow_statements = {
-    init: function () {
-        var a = [[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK, "BREAK"], [Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE, "CONTINUE"]];
-        this.setHelpUrl(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL);
-        this.setColour(HUE);
-        this.appendDummyInput().appendField(new Blockly.FieldDropdown(a), "FLOW");
-        this.setPreviousStatement(!0);
-        var b = this;
-        this.setTooltip(function () {
-            var a = b.getFieldValue("FLOW");
-            return {
-                BREAK: Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK,
-                CONTINUE: Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE
-            }[a]
-        })
-    },
-    onchange: function (a) {
-        if (!this.workspace.isDragging()) {
-            a = !1;
-            var b = this;
-            do {
-                if (-1 != this.LOOP_TYPES.indexOf(b.type)) {
-                    a = !0;
-                    break
-                }
-                b = b.getSurroundParent()
-            } while (b); a ? (this.setWarningText(null),
-                this.isInFlyout || this.setDisabled(!1)) : (this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING),
-                    this.isInFlyout || this.getInheritedDisabled() || this.setDisabled(!0))
-        }
-    },
-    LOOP_TYPES: "controls_repeat_forever controls_repeat controls_repeat_ext controls_forEach controls_for controls_whileUntil tello_repeat_forever".split(" ")
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['esp32_main_controller_motion_acceleration'] = function (block) {
+    var _type_selected = block.getFieldValue('accel_type');
+    // var is_unit = block.getFieldValue('isUnit');
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_QMI8658'] = `from CocoPi import QMI8658`
+    Blockly.Python.definitions_['QMI8658_import_path'] = `
+#初始化设置
+qmi8658=QMI8658()
+#校准
+qmi8658.calibrate()
+#标定初始方位
+initData={}
+initData["AcX"]=qmi8658.get_accel(10)["AcX"]
+initData["AcY"]=qmi8658.get_accel(10)["AcY"]
+initData["AcZ"]=qmi8658.get_accel(10)["AcZ"]
+initData["GyX"]=qmi8658.get_accel(10)["GyX"]
+initData["GyY"]=qmi8658.get_accel(10)["GyY"]
+initData["GyZ"]=qmi8658.get_accel(10)["GyZ"]
+`;
+
+
+    var code = `round(qmi8658.getPitchYawRollGxGyGz(initData)[${_type_selected}],2)`;
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
 };
-// 获取原始积木定义
-const originalIfBlock = Blockly.Blocks['controls_if'];
 
-Blockly.Blocks.controls_if = {
+Blockly.Blocks['esp32_main_controller_motion_rotation_measurement'] = {
     init: function () {
-        originalIfBlock.init.call(this);
-        this.setColour(CategoryColors.Logic);
-    },
-    
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.basic_motion_get_along)
+            .appendField(new Blockly.FieldDropdown([
+                ["X", "4"],
+                ["Y", "3"],
+                ["Z", "5"]
+            ]), "accel_type")
+            .appendField(Blockly.Msg.basic_motion_rotation_measurement);
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour(SensorsColor);
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('accel_type');
+            var TOOLTIPS = {
+                '4': Blockly.Msg.Esp32_Main_Controller_Motion_Rotation_Measurement_TOOLTIP.replace('%1', 'X'),
+                '3': Blockly.Msg.Esp32_Main_Controller_Motion_Rotation_Measurement_TOOLTIP.replace('%1', 'Y'),
+                '5': Blockly.Msg.Esp32_Main_Controller_Motion_Rotation_Measurement_TOOLTIP.replace('%1', 'Z')
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
 };
-Blockly.Blocks.controls_if_elseif = {
-    init: function () {
-        this.setColour(CategoryColors.Logic);
-        this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF);
-        this.setPreviousStatement(!0);
-        this.setNextStatement(!0);
-        this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP);
-        this.contextMenu = !1
-    }
-};
-Blockly.Blocks.controls_if_else = {
-    init: function () {
-        this.setColour(CategoryColors.Logic);
-        this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE);
-        this.setPreviousStatement(!0);
-        this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP);
-        this.contextMenu = !1
-    }
-};
-Blockly.Blocks.controls_if_if = {
-    init: function () {
-        this.setColour(CategoryColors.Logic);
-        this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_IF_TITLE_IF);
-        this.setNextStatement(!0);
-        this.setTooltip(Blockly.Msg.CONTROLS_IF_IF_TOOLTIP);
-        this.contextMenu = !1
-    }
-};
-Blockly.Blocks['logic_compare'] = {
-    /**
-     * Block for comparison operator.
-     * @this Blockly.Block
-     */
-    init: function () {
-        var rtlOperators = [
-            ['==', 'EQ'],
-            ['!=', 'NEQ'],
-            ['>', 'LT'],
-            ['>=', 'LTE'],
-            ['<', 'GT'],
-            ['<=', 'GTE']
-        ];
-        var ltrOperators = [
-            ['==', 'EQ'],
-            ['!=', 'NEQ'],
-            ['<', 'LT'],
-            ['<=', 'LTE'],
-            ['>', 'GT'],
-            ['>=', 'GTE']
-        ];
-        var OPERATORS = this.RTL ? rtlOperators : ltrOperators;
-        this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);
-        this.setColour(CategoryColors.Logic);
-        this.setOutput(true, 'Boolean');
-        this.appendValueInput('A');
-        this.appendValueInput('B')
-            .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP');
-        this.setInputsInline(true);
-        // Assign 'this' to a variable for use in the tooltip closure below.
+
+Blockly.Python['esp32_main_controller_motion_rotation_measurement'] = function (block) {
+    var _type_selected = block.getFieldValue('accel_type');
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_QMI8658'] = `from CocoPi import QMI8658`
+    Blockly.Python.definitions_['QMI8658_import_path'] = `
+#初始化设置
+qmi8658=QMI8658()
+#校准
+qmi8658.calibrate()
+#标定初始方位
+initData={}
+initData["AcX"]=qmi8658.get_accel(10)["AcX"]
+initData["AcY"]=qmi8658.get_accel(10)["AcY"]
+initData["AcZ"]=qmi8658.get_accel(10)["AcZ"]
+initData["GyX"]=qmi8658.get_accel(10)["GyX"]
+initData["GyY"]=qmi8658.get_accel(10)["GyY"]
+initData["GyZ"]=qmi8658.get_accel(10)["GyZ"]
+`;
+    var code = `round(qmi8658.getPitchYawRollGxGyGz(initData)[${_type_selected}],2)`;
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
+};
+
+Blockly.Blocks['esp32_main_controller_motion_tilt_angle'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.basic_motion_get_along)
+            .appendField(new Blockly.FieldDropdown([
+                ["X", "1"],
+                ["Y", "0"],
+                // ["Z", "2"]
+            ]), "tilt_angle_type")
+            .appendField(Blockly.Msg.basic_motion_angle);
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour(SensorsColor);
         var thisBlock = this;
         this.setTooltip(function () {
-            var op = thisBlock.getFieldValue('OP');
+            var mode = thisBlock.getFieldValue('tilt_angle_type');
             var TOOLTIPS = {
-                'EQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,
-                'NEQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,
-                'LT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,
-                'LTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,
-                'GT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,
-                'GTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE
+                '1': Blockly.Msg.Esp32_Main_Controller_Motion_Tilt_Angle_TOOLTIP.replace('%1', 'X'),
+                '0': Blockly.Msg.Esp32_Main_Controller_Motion_Tilt_Angle_TOOLTIP.replace('%1', 'Y')
             };
-            return TOOLTIPS[op];
+            return TOOLTIPS[mode];
         });
-        this.prevBlocks_ = [null, null];
-    },
-    /**
-     * Called whenever anything on the workspace changes.
-     * Prevent mismatched types from being compared.
-     * @param {!Blockly.Events.Abstract} e Change event.
-     * @this Blockly.Block
-     */
-    onchange: function (e) {
-        var blockA = this.getInputTargetBlock('A');
-        var blockB = this.getInputTargetBlock('B');
-        // Disconnect blocks that existed prior to this change if they don't match.
-        if (blockA && blockB &&
-            !blockA.outputConnection.checkType_(blockB.outputConnection)) {
-            // Mismatch between two inputs.  Disconnect previous and bump it away.
-            // Ensure that any disconnections are grouped with the causing event.
-            Blockly.Events.setGroup(e.group);
-            for (var i = 0; i < this.prevBlocks_.length; i++) {
-                var block = this.prevBlocks_[i];
-                if (block === blockA || block === blockB) {
-                    block.unplug();
-                    block.bumpNeighbours_();
+        this.setHelpUrl("");
+    }
+};
+
+
+Blockly.Python['esp32_main_controller_motion_tilt_angle'] = function (block) {
+    var _type_selected = block.getFieldValue('tilt_angle_type');
+    // var is_unit = block.getFieldValue('isUnit');
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_QMI8658'] = `from CocoPi import QMI8658`
+    Blockly.Python.definitions_['QMI8658_import_path'] = `
+#初始化设置
+qmi8658=QMI8658()
+#校准
+qmi8658.calibrate()
+#标定初始方位
+initData={}
+initData["AcX"]=qmi8658.get_accel(10)["AcX"]
+initData["AcY"]=qmi8658.get_accel(10)["AcY"]
+initData["AcZ"]=qmi8658.get_accel(10)["AcZ"]
+initData["GyX"]=qmi8658.get_accel(10)["GyX"]
+initData["GyY"]=qmi8658.get_accel(10)["GyY"]
+initData["GyZ"]=qmi8658.get_accel(10)["GyZ"]
+`
+    var code = `round(qmi8658.getPitchYawRollGxGyGz(initData)[${_type_selected}],2)`
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
+};
+
+// 动力
+const servoColor = "#386dc8";
+Blockly.Blocks['extension_servo_setup_on_ai'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(new Blockly.FieldImage("/media/esp32_servo_setup.png", 50, 40, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.servo_setup_ai);
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(servoColor);
+        this.setTooltip(Blockly.Msg.extension_servo_setup_on_ai_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['extension_servo_setup_on_ai'] = function (block) {
+    Blockly.Python.definitions_['import_smbus2'] = `import smbus2`
+    Blockly.Python.definitions_['import_time'] = `import time`
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    Blockly.Python.definitions_['import_CocoPi_multiFuncGpio'] = `from CocoPi import multiFuncGpio`;
+    //     Blockly.Python.definitions_["v831_set_servo_S1_S2"] = `S1= multiFuncGpio(0,1)
+    // S2= multiFuncGpio(1,1)`
+    Blockly.Python.definitions_['import_CocoPi_multiFuncGpio'] = `from CocoPi import multiFuncGpio`;
+
+    try {
+        const allBlocks = getBlocksByTypeName("extension_servo_write_on_ai")
+        let onedegree = allBlocks.length > 0 ? allBlocks[0].textContent : "";
+        if (onedegree.indexOf("S1") != -1) {
+            let degree = 0
+            for (let i = 0; i < allBlocks.length; i++) {
+                if (allBlocks[i].textContent.indexOf("S1") == 0) {
+                    degree = allBlocks[i].children[1].textContent;
+                    break;
                 }
             }
-            Blockly.Events.setGroup(false);
+            Blockly.Python.definitions_["servo_initS1"] = `S1= multiFuncGpio(0,1)
+S1.servoCtrl(${isNaN(Number(degree)) ? 90 : degree})`
+        }
+        if (onedegree.indexOf("S2") != -1) {
+            let degree1 = 0
+            for (let i = 0; i < allBlocks.length; i++) {
+                if (allBlocks[i].textContent.indexOf("S2") == 0) {
+                    degree1 = allBlocks[i].children[1].textContent;
+                    break;
+                }
+            }
+            Blockly.Python.definitions_["servo_initS2"] = `S2= multiFuncGpio(1,1)
+S2.servoCtrl(${isNaN(Number(degree1)) ? 90 : degree1})`
+        }
+    } catch (e) {
+        console.log("error", e)
+    }
+    var code = '';
+    return code;
+};
+
+
+Blockly.Blocks['extension_servo_write_on_ai'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.servo_set_gpio_ai)
+            .appendField(new Blockly.FieldDropdown([
+                ["S1", "S1"],
+                ["S2", "S2"],
+                ["P0", "P0"],
+                ["P1", "P1"],
+                ["P2", "P2"],
+                ["P3", "P3"]
+            ]), "gpio");
+        this.appendValueInput("degree")
+            .setCheck(null)
+            .appendField(Blockly.Msg.servo_rotate_to_ai);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.servo_degree_ai);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(servoColor);
+        this.setTooltip(Blockly.Msg.extension_servo_write_on_ai_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['extension_servo_write_on_ai'] = function (block) {
+    var value_degree = Blockly.Python.valueToCode(block, 'degree', Blockly.Python.ORDER_ATOMIC);
+    var value_gpio = block.getFieldValue('gpio');
+    let code = ""
+    // console.log('1. ',performance.now())
+    if (value_gpio == "S1" || value_gpio == "S2") {
+        code = `${value_gpio}.servoCtrl(${value_degree})\n`
+    } else {
+        Blockly.Python.definitions_['import_smbus2'] = `import smbus2`
+        Blockly.Python.definitions_['import_CocoPi_extServo'] = `
+class PCA9685(object):
+    bus=smbus2.SMBus(2)
+    def __init__(self,freq=400,min_us=460,max_us=2400,address=0x40,degrees=180):
+        self.address=address
+        self.period=1000000/freq
+        self.min_duty = self._us2duty(min_us)
+        self.max_duty = self._us2duty(max_us)
+        self.freq(freq)
+        self.reset()
+        #for i in range(0,16):
+            #self.duty(i,0)
+        print("Pca9685 init")
+        
+    def write(self, addr, val):
+        for i in range(0, 2):
+            try:
+                self.bus.write_byte_data(self.address, addr, val)
+                #time.sleep(0.001) # 1ms
+                # print(addr, val) # debug
+                return True
+            except Exception:
+                time.sleep(0.001)
+                continue
+        return False
+        
+    def read(self,addr):
+        for i in range(0, 3):
+            try:
+                tmp = self.bus.read_byte_data(self.address, addr)
+                #time.sleep(0.001) # 1ms
+                # print(addr, tmp) # debug
+                return tmp
+            except Exception:
+                time.sleep(0.01)
+                continue
+        return None
+    
+    def reset(self):
+        self.write(0x00,0x00)        #初始化
+    
+    def freq(self,freq=None):
+        if freq is None:
+            return int(25000000.0/4096/(self.read(0xfe)-0.5))
+        #设定频率freq,预分频prescale=int(25000000.0 / (4096.0 * freq) + 0.5)
+        prescale=int(25000000.0/4096/freq+0.5)
+        self.write(0x00,0x10)        #设定pca9685为睡眠模式
+        self.write(0xfe,prescale)    #设定频率
+        self.reset()
+        time.sleep(0.01)
+        self.write(0x00,0xa1)        #设定pca9685为活跃模式
+    
+    def pwm(self,index,on=None,off=None):            #on和off来调节PWM的占空比
+        if not 0<= index <=15:
+            raise ValueError("Pin ID out of range!")
+        if on is None or off is None:
+            data = self.bus.read_i2c_block_data(self.address,0x06+index*4,4)
+            return data
+        data= [0]*4
+        data[0]=int(hex(on & 0xff),16)
+        data[1]=int(hex((on >> 8) & 0xff),16)
+        data[2]=int(hex(off & 0xff),16)
+        data[3]=int(hex((off >> 8) & 0xff),16)
+        # print(data)
+        for i in range(0,4):
+            self.write(0x06+i+index*4,data[i])
+        
+    def duty(self,index,value=None):
+        if value == None:
+            return self.pwm(index)
+        elif not 0 <= value <=4095:
+            raise ValueError("Out of range!")
+        elif value==0:
+            self.pwm(index,0,4096)
+        elif value == 4095:
+            self.pwm(index,4096,0)
+        else:
+            self.pwm(index,0,value)  
+
+    def _us2duty(self,value):
+        return 4095*value/self.period
+        
+    def __del__(self):
+        print("del pac9685")
+        time.sleep(1)
+        for i in range(0,16):
+            self.duty(i,0)
+        time.sleep(0.001)
+    
+class extServo(PCA9685):
+    def __init__(self,servoId):
+        PCA9685.__init__(self)
+        self.servoId=servoId
+        self.servoPin=[14,15,1,0]
+        self.degrees=180
+        pass      
+        
+    def position(self,degrees=None):        #index:0,1,2,3
+        if degrees == 180:
+            self.max_duty = 3800
+        span = self.max_duty - self.min_duty
+        duty = self.min_duty + span * degrees / self.degrees
+        duty = int(min(self.max_duty, max(self.min_duty, int(duty))))
+        self.duty(self.servoPin[self.servoId], duty)
+        
+    def release(self):
+        self.duty(self.servoPin[self.servoId],0)
+    
+    def __del__(self):  
+        self.duty(self.servoPin[self.servoId],0)
+ `;
+        Blockly.Python.definitions_["servo_init_" + value_gpio] = `${value_gpio} = extServo(${value_gpio[1]})`
+        code = `${value_gpio}.position(${value_degree})\n`
+    }
+    return code;
+};
+Blockly.Blocks['ai_motor_setup'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(new Blockly.FieldImage("/media/motor_setup.png", 50, 40, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.x_motor_set_motor_ai)
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(servoColor);
+        this.setTooltip(Blockly.Msg.ai_motor_setup_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_motor_setup'] = function (block) {
+    // TODO: Assemble Python into code variable.
+    Blockly.Python.definitions_['import_smbus2'] = `import smbus2`
+    Blockly.Python.definitions_['import_time'] = `import time`
+    Blockly.Python.definitions_['import_sys'] = `import sys
+sys.path.append("/root/")`
+    //     Blockly.Python.definitions_["v831_motor_init"] = `M1=dcMotor(1)
+    // M2=dcMotor(2)`
+
+    var code = '';
+    return code;
+};
+Blockly.Blocks['ai_motor_run'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.x_motor_set_motor_turn_ai)
+            .appendField(new Blockly.FieldDropdown([
+                ["M1", "M1"],
+                ["M2", "M2"],
+                ["M3", "C"],
+                ["M4", "D"],
+                ["M5", "E"],
+                ["M6", "F"]
+            ]), "motor_type")
+            .appendField(Blockly.Msg.x_motor_set_motor_speed_ai);
+        this.appendValueInput("speed")
+            .setCheck(null);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.x_motor_exec_ai)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.x_motor_cw_ai, "pos"],
+                [Blockly.Msg.x_motor_acw_ai, "neg"]
+            ]), "direction")
+            .appendField(Blockly.Msg.x_motor_set_motor_turns_ai);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(servoColor);
+        this.setTooltip(Blockly.Msg.ai_motor_run_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_motor_run'] = function (block) {
+    var dropdown_motor_type = block.getFieldValue('motor_type');
+    var value_speed = Blockly.Python.valueToCode(block, 'speed', Blockly.Python.ORDER_ATOMIC);
+    var dropdown_direction = block.getFieldValue('direction');
+    var code = ''
+    if (dropdown_motor_type === "M1" || dropdown_motor_type === "M2") {
+        Blockly.Python.definitions_['import_CocoPi_stm8s_init'] = `from CocoPi import stm8s
+iic_slaver=stm8s()
+iic_slaver.clear()
+del iic_slaver`;
+        Blockly.Python.definitions_['import_CocoPi_stm8s'] = `from CocoPi import dcMotor`;
+        Blockly.Python.definitions_["dcMotorCtrlFun" + dropdown_motor_type] = `${dropdown_motor_type} = dcMotor(${dropdown_motor_type.slice(1, 2)})`
+        if (dropdown_direction == 'pos') {
+            code = `${dropdown_motor_type}.dcMotorCtrl(1,${value_speed})\n`
+        }
+        else {
+            code = `${dropdown_motor_type}.dcMotorCtrl(0,${value_speed})\n`
+        }
+    } else {
+        Blockly.Python.definitions_['import_CocoPi_extDcMotor'] = `from CocoPi import extDcMotor`;
+        Blockly.Python.definitions_["dcMotorCtrlFun" + dropdown_motor_type] = `${dropdown_motor_type} = extDcMotor("${dropdown_motor_type}")`
+        if (dropdown_direction == 'pos') {
+            code = `${dropdown_motor_type}.speedControl(${value_speed})\n`
+        }
+        else {
+            code = `${dropdown_motor_type}.speedControl(-${value_speed})\n`
         }
-        this.prevBlocks_[0] = blockA;
-        this.prevBlocks_[1] = blockB;
     }
+    return code;
 };
-Blockly.Blocks['logic_operation'] = {
-    /**
-     * Block for logical operations: 'and', 'or'.
-     * @this Blockly.Block
-     */
+
+// 屏幕
+
+const screenColor = "#5cb2d6";
+Blockly.Blocks["ai_lcd_screeninit"] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(new Blockly.FieldImage("/media/screen_init_header.png", 45, 45, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_lcd_init);
+        this.appendDummyInput().appendField(Blockly.Msg.image_process_lcd_direction)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_process_lcd_landscape_screen, "False"],
+                [Blockly.Msg.image_process_lcd_vertical_screen, "True"]
+            ]), "isScreen")
+        this.setInputsInline(false);
+        this.setPreviousStatement(true);
+        this.setNextStatement(true);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_screeninit_TOOLTIP);
+        this.setHelpUrl('');
+    }
+}
+
+Blockly.Python.ai_lcd_screeninit = function (block) {
+    var isScreen = block.getFieldValue('isScreen');
+    Blockly.Python.definitions_['import_display'] = `from maix import display`;
+    Blockly.Python.definitions_['import_image'] = `from maix import image`;
+    Blockly.Python.definitions_['import_camera'] = `from maix import camera`;
+    Blockly.Python.definitions_['import_os'] = `import os`
+    return _code;;
+}
+Blockly.Blocks['ai_lcd_rgb_value_input'] = {
     init: function () {
-        var OPERATORS =
-            [[Blockly.Msg.LOGIC_OPERATION_AND, 'AND'],
-            [Blockly.Msg.LOGIC_OPERATION_OR, 'OR']];
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.rgb_R);
+        this.appendValueInput("rgb_value_r")
+            .setCheck(null)
+            .appendField("");
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.rgb_G);
+        this.appendValueInput("rgb_value_g")
+            .setCheck(null)
+            .appendField("");
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.rgb_B);
+        this.appendValueInput("rgb_value_b")
+            .setCheck(null)
+            .appendField("");
+        this.setInputsInline(true);
+        this.setOutput(true, null);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_rgb_value_input_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_lcd_rgb_value_input'] = function (block) {
+    var value_rgb_value_r = Blockly.Python.valueToCode(block, 'rgb_value_r', Blockly.Python.ORDER_ATOMIC);
+    var value_rgb_value_g = Blockly.Python.valueToCode(block, 'rgb_value_g', Blockly.Python.ORDER_ATOMIC);
+    var value_rgb_value_b = Blockly.Python.valueToCode(block, 'rgb_value_b', Blockly.Python.ORDER_ATOMIC);
+    var code = '' + value_rgb_value_r + ',' + value_rgb_value_g + ',' + value_rgb_value_b + '';
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Blocks.ai_lcd_XY = {
+    init: function () {
+        var _input = this.appendDummyInput();
         this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL);
-        this.setColour(CategoryColors.Logic);
-        this.setOutput(true, 'Boolean');
-        this.appendValueInput('A')
-            .setCheck('Boolean');
-        this.appendValueInput('B')
-            .setCheck('Boolean')
-            .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP');
+        this.setTooltip(Blockly.Msg.ai_lcd_XY_TOOLTIP);
+        this.setColour(screenColor);
+        this.setOutput(!0, "Boolean");
+        _input.appendField(Blockly.Msg.image_process_xy_x);
+        this.appendValueInput("A").setCheck("Number");
+        _input = this.appendDummyInput();
+        _input.appendField(Blockly.Msg.image_process_xy_y)
+        this.appendValueInput("B").setCheck("Number");
+        this.setInputsInline(!0);
+    }
+};
+
+Blockly.Python.ai_lcd_XY = function (block) {
+    var _x = Blockly.Python.valueToCode(block, "A", Blockly.Python.ORDER_ATOMIC);
+    var _y = Blockly.Python.valueToCode(block, "B", Blockly.Python.ORDER_ATOMIC);
+    var code = "" + _x + ", " + _y + "";
+    return [code, Blockly.Python.ORDER_ATOMIC];
+};
+Blockly.Blocks['lcd_set_width_height'] = {
+    init: function () {
+        this.appendValueInput("WIDTH")
+            .setCheck("Number")
+            .appendField(Blockly.Msg.image_process_wh_width);
+        this.appendValueInput("HEIGHT")
+            .setCheck("Number")
+            .appendField(Blockly.Msg.image_process_wh_height);
+        this.setOutput(true, "String");
+        this.setInputsInline(true);
+        this.setColour(screenColor);
+        this.setTooltip("");
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['lcd_set_width_height'] = function (block) {
+    var width = Blockly.Python.valueToCode(block, 'WIDTH', Blockly.Python.ORDER_ATOMIC);
+    var height = Blockly.Python.valueToCode(block, 'HEIGHT', Blockly.Python.ORDER_ATOMIC);
+    var code = width + ', ' + height;
+    return [code, Blockly.Python.ORDER_ATOMIC];
+};
+Blockly.Blocks['ai_lcd_font'] = {
+    init: function () {
+        this.appendDummyInput().appendField(Blockly.Msg.image_lcd_set_font)
+        this.appendValueInput("save_path")
+            .setCheck(null)
+        this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.image_lcd_set_font);
+        this.setHelpUrl('');
+    }
+}
+
+Blockly.Python.ai_lcd_font = function (block) {
+    var font_path = Blockly.Python.valueToCode(block, 'save_path', Blockly.Python.ORDER_ATOMIC);
+    Blockly.Python.definitions_['ai_lcd_font'] = `image.load_freetype(${font_path})
+`
+    var _code = "";
+    return _code;;
+}
+Blockly.Blocks["ai_lcd_createnonecarvas"] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_create_blank_canvas)
+            ;
+        this.appendValueInput("wh")
+            .setCheck(null)
+            .appendField(Blockly.Msg.image_process_text_size);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_createnonecarvas_TOOLTIP);
+        this.setHelpUrl('');
+    }
+}
+
+Blockly.Python.ai_lcd_createnonecarvas = function (block) {
+    var value_wh = Blockly.Python.valueToCode(block, 'wh', Blockly.Python.ORDER_ATOMIC);
+
+    var _code = "canvas = image.new(size = (" + value_wh + "))\n";
+    return _code;
+}
+Blockly.Blocks['ai_lcd_fill_screen_with_rgb'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_text_let_canvas_filled_with_color);
+        this.appendValueInput("rgb_value")
+            .setCheck(null)
+            .appendField("");
+        this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_fill_screen_with_rgb_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python['ai_lcd_fill_screen_with_rgb'] = function (block) {
+    var value_name = Blockly.Python.valueToCode(block, 'rgb_value', Blockly.Python.ORDER_ATOMIC);
+    // TODO: Assemble Python into code variable.
+    if (value_name.charAt(0) == '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == value_name.length && (d = parseInt(value_name.substring(1, 3), 16),
+                e = parseInt(value_name.substring(3, 5), 16),
+                f = parseInt(value_name.substring(5, 7), 16))
+        } catch (g) { }
+        // TODO: Assemble Python into code variable.
+        value_name = "(" + d + "," + e + "," + f + ")";
+    }
+    var code = ``;
+    return code;
+};
+Blockly.Blocks['ai_lcd_textcarvas'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_text_on_draw);
+        this.appendValueInput("POSA")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_start_coord);
+        this.appendValueInput("CONTENT")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_content);
+        this.appendValueInput("COLOR")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_color);
+        this.appendValueInput("Scale")
+            .setCheck("Number")
+            .appendField(Blockly.Msg.image_process_draw_text_font_size);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true);
+        this.setNextStatement(true);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_textcarvas_TOOLTIP);
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python.ai_lcd_textcarvas = function (block) {
+    var color = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_ATOMIC);
+    var _code = ""
+    if (color.charAt(0) == '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == color.length && (d = parseInt(color.substring(1, 3), 16),
+                e = parseInt(color.substring(3, 5), 16),
+                f = parseInt(color.substring(5, 7), 16))
+        } catch (g) { }
+        var content = Blockly.Python.valueToCode(block, 'CONTENT', Blockly.Python.ORDER_ATOMIC);
+        var xy = Blockly.Python.valueToCode(block, 'POSA', Blockly.Python.ORDER_ATOMIC);
+        var scale = Blockly.Python.valueToCode(block, 'Scale', Blockly.Python.ORDER_ATOMIC);
+        // color=(" + d + "," + e + "," + f + ")" + ", font_size=" + size + ")\n"
+        _code = 'canvas.draw_string(' + xy + ', ' + content + ', scale = ' + scale + ', color = (' + d + ',' + e + ',' + f + ') , thickness = 1)\n'; // #在红色画布上写下hello world
+    } else if (color.charAt(0) != '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == color.length && (d = parseInt(color.substring(1, 3), 16),
+                e = parseInt(color.substring(3, 5), 16),
+                f = parseInt(color.substring(5, 7), 16))
+        } catch (g) { }
+        var content = Blockly.Python.valueToCode(block, 'CONTENT', Blockly.Python.ORDER_ATOMIC);
+        var xy = Blockly.Python.valueToCode(block, 'POSA', Blockly.Python.ORDER_ATOMIC);
+        var scale = Blockly.Python.valueToCode(block, 'Scale', Blockly.Python.ORDER_ATOMIC);
+        _code = 'canvas.draw_string(' + xy + ', ' + content + ', scale = ' + scale + ', color = ' + color + ', thickness = 1)\n' + // #在红色画布上写下hello world
+            '';
+    }
+    return _code;
+}
+Blockly.Blocks['ai_lcd_linecarvas'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_draw_line);
+        this.appendValueInput("POSA")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_start_coord);
+        this.appendValueInput("POSB")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_end_coord);
+        this.appendValueInput("COLOR")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_color);
+        this.appendValueInput("Scale")
+            .setCheck("Number")
+            .appendField(Blockly.Msg.image_process_text_thick);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true);
+        this.setNextStatement(true);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_linecarvas_TOOLTIP);
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python.ai_lcd_linecarvas = function (block) {
+    var color = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_ATOMIC);
+    if (color.charAt(0) == '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == color.length && (d = parseInt(color.substring(1, 3), 16),
+                e = parseInt(color.substring(3, 5), 16),
+                f = parseInt(color.substring(5, 7), 16))
+        } catch (g) { }
+
+        var size = Blockly.Python.valueToCode(block, 'Scale', Blockly.Python.ORDER_ATOMIC);
+        var xy = Blockly.Python.valueToCode(block, 'POSA', Blockly.Python.ORDER_ATOMIC);
+        var xy2 = Blockly.Python.valueToCode(block, 'POSB', Blockly.Python.ORDER_ATOMIC);
+        var _code = "canvas.draw_line(" + xy + ", " + xy2 + ", color=(" + d + "," + e + "," + f + "), thickness=" + size + ")\n";
+    } else if (color.charAt(0) != '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == color.length && (d = parseInt(color.substring(1, 3), 16),
+                e = parseInt(color.substring(3, 5), 16),
+                f = parseInt(color.substring(5, 7), 16))
+        } catch (g) { }
+
+        var size = Blockly.Python.valueToCode(block, 'Scale', Blockly.Python.ORDER_ATOMIC);
+        var xy = Blockly.Python.valueToCode(block, 'POSA', Blockly.Python.ORDER_ATOMIC);
+        var xy2 = Blockly.Python.valueToCode(block, 'POSB', Blockly.Python.ORDER_ATOMIC);
+        var _code = "canvas.draw_line(" + xy + ", " + xy2 + ", color=" + color + ", thickness=" + size + ")\n";
+    }
+    return _code;
+}
+Blockly.Blocks['ai_lcd_ractanglecarvas'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_text_on_draw)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_process_text_filled, "fillrect"],
+                [Blockly.Msg.image_process_text_stroked, "rect"]
+            ]), "rect_type")
+            .appendField(Blockly.Msg.image_process_draw_rectangle_text);
+        this.appendValueInput("POSA")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_start_coord);
+        this.appendValueInput("POSB")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_end_coord);
+        this.appendValueInput("COLOR")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_color);
+        // this.appendValueInput("Scale")
+        //     .setCheck("Number")
+        //     .appendField(Blockly.Msg.image_process_text_thick);
         this.setInputsInline(true);
-        // Assign 'this' to a variable for use in the tooltip closure below.
+        this.setPreviousStatement(true);
+        this.setNextStatement(true);
+        this.setColour("#5bb2d6");
         var thisBlock = this;
         this.setTooltip(function () {
-            var op = thisBlock.getFieldValue('OP');
+            var mode = thisBlock.getFieldValue('rect_type');
             var TOOLTIPS = {
-                'AND': Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND,
-                'OR': Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR
+                'fillrect': Blockly.Msg.ai_lcd_ractanglecarvas_TOOLTIP.replace('%1', Blockly.Msg.image_process_text_filled),
+                'rect': Blockly.Msg.ai_lcd_ractanglecarvas_TOOLTIP.replace('%1', Blockly.Msg.image_process_text_stroked)
             };
-            return TOOLTIPS[op];
+            return TOOLTIPS[mode];
         });
+        this.setHelpUrl('');
     }
 };
 
-Blockly.Blocks['logic_negate'] = {
-    /**
-     * Block for negation.
-     * @this Blockly.Block
-     */
+Blockly.Python.ai_lcd_ractanglecarvas = function (block) {
+    var color = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_ATOMIC);
+
+    var type = block.getFieldValue('rect_type') == "fillrect" ? "-1" : "1";
+    var th = Blockly.Python.valueToCode(block, 'Scale', Blockly.Python.ORDER_ATOMIC);
+    var xy = Blockly.Python.valueToCode(block, 'POSA', Blockly.Python.ORDER_ATOMIC);
+    var size = Blockly.Python.valueToCode(block, 'POSB', Blockly.Python.ORDER_ATOMIC);
+    var _code = ''
+    if (color.charAt(0) == '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == color.length && (d = parseInt(color.substring(1, 3), 16),
+                e = parseInt(color.substring(3, 5), 16),
+                f = parseInt(color.substring(5, 7), 16))
+        } catch (g) { }
+        _code = `canvas.draw_rectangle(${xy},${size}, color=(${d},${e},${f}), thickness=${type})
+`
+    } else if (color.charAt(0) != '#') {
+        _code = `canvas.draw_rectangle(${xy},${size}, color=${color}, thickness=${type})
+`
+    }
+    return _code;
+}
+Blockly.Blocks['lcd_set_position'] = {
     init: function () {
-        this.jsonInit({
-            "message0": Blockly.Msg.LOGIC_NEGATE_TITLE,
-            "args0": [
-                {
-                    "type": "input_value",
-                    "name": "BOOL",
-                    "check": "Boolean"
-                }
-            ],
-            "output": "Boolean",
-            "colour": CategoryColors.Logic,
-            "tooltip": Blockly.Msg.LOGIC_NEGATE_TOOLTIP,
-            "helpUrl": Blockly.Msg.LOGIC_NEGATE_HELPURL
-        });
+        this.appendValueInput("POSX")
+            .setCheck("Number")
+            .appendField("X:");
+        this.appendValueInput("POSY")
+            .setCheck("Number")
+            .appendField("Y:");
+        this.setOutput(true, "String");
+        this.setInputsInline(true);
+        this.setColour(screenColor);
+        this.setTooltip("");
+        this.setHelpUrl("");
     }
 };
 
-Blockly.Blocks['logic_boolean'] = {
-    /**
-     * Block for boolean data type: true and false.
-     * @this Blockly.Block
-     */
+Blockly.Python['lcd_set_position'] = function (block) {
+    var pos_x = Blockly.Python.valueToCode(block, 'POSX', Blockly.Python.ORDER_ATOMIC);
+    var pos_y = Blockly.Python.valueToCode(block, 'POSY', Blockly.Python.ORDER_ATOMIC);
+    var code = pos_x + "," + pos_y;
+    return [code, Blockly.Python.ORDER_ATOMIC];
+};
+Blockly.Blocks['lcd_set_color'] = {
     init: function () {
-        this.jsonInit({
-            "message0": "%1",
-            "args0": [
-                {
-                    "type": "field_dropdown",
-                    "name": "BOOL",
-                    "options": [
-                        [Blockly.Msg.LOGIC_BOOLEAN_TRUE, "TRUE"],
-                        [Blockly.Msg.LOGIC_BOOLEAN_FALSE, "FALSE"]
-                    ]
-                }
-            ],
-            "output": "Boolean",
-            "colour": CategoryColors.Logic,
-            "tooltip": Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP,
-            "helpUrl": Blockly.Msg.LOGIC_BOOLEAN_HELPURL
-        });
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.COLOR)
+            .appendField(new Blockly.FieldColour("#ff0000"), "COLOR");
+        this.setOutput(true, "String");
+        this.setColour("#5bb2d6");
+        this.setTooltip("");
+        this.setHelpUrl("");
     }
 };
 
-Blockly.Blocks['logic_null'] = {
-    /**
-     * Block for null data type.
-     * @this Blockly.Block
-     */
+Blockly.Python['lcd_set_color'] = function (block) {
+    var code = block.getFieldValue('COLOR');
+    return [code, Blockly.Python.ORDER_ATOMIC];
+};
+Blockly.Blocks['ai_lcd_draw_rectangle'] = {
     init: function () {
-        this.jsonInit({
-            "message0": Blockly.Msg.LOGIC_NULL,
-            "output": null,
-            "colour": CategoryColors.Logic,
-            "tooltip": Blockly.Msg.LOGIC_NULL_TOOLTIP,
-            "helpUrl": Blockly.Msg.LOGIC_NULL_HELPURL
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_text_on_draw)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_process_text_filled, "fillrect"],
+                [Blockly.Msg.image_process_text_stroked, "rect"]
+            ]), "rect_type")
+            .appendField(Blockly.Msg.image_process_draw_rectangle_text);
+        this.appendValueInput("POSA")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_start_coord);
+        this.appendValueInput("POSB")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_size);
+        this.appendValueInput("COLOR")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_color);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true);
+        this.setNextStatement(true);
+        this.setColour(screenColor);
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('rect_type');
+            var TOOLTIPS = {
+                'fillrect': Blockly.Msg.ai_lcd_ractanglecarvas_TOOLTIP.replace('%1', Blockly.Msg.image_process_text_filled),
+                'rect': Blockly.Msg.ai_lcd_ractanglecarvas_TOOLTIP.replace('%1', Blockly.Msg.image_process_text_stroked)
+            };
+            return TOOLTIPS[mode];
         });
+        this.setHelpUrl('');
     }
 };
 
-Blockly.Blocks['logic_ternary'] = {
-    /**
-     * Block for ternary operator.
-     * @this Blockly.Block
-     */
-    init: function () {
-        this.setHelpUrl(Blockly.Msg.LOGIC_TERNARY_HELPURL);
-        this.setColour(CategoryColors.Logic);
-        this.appendValueInput('IF')
-            .setCheck('Boolean')
-            .appendField(Blockly.Msg.LOGIC_TERNARY_CONDITION);
-        this.appendValueInput('THEN')
-            .appendField(Blockly.Msg.LOGIC_TERNARY_IF_TRUE);
-        this.appendValueInput('ELSE')
-            .appendField(Blockly.Msg.LOGIC_TERNARY_IF_FALSE);
-        this.setOutput(true);
-        this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP);
-        this.prevParentConnection_ = null;
-    },
-    /**
-     * Called whenever anything on the workspace changes.
-     * Prevent mismatched types.
-     * @param {!Blockly.Events.Abstract} e Change event.
-     * @this Blockly.Block
-     */
-    onchange: function (e) {
-        var blockA = this.getInputTargetBlock('THEN');
-        var blockB = this.getInputTargetBlock('ELSE');
-        var parentConnection = this.outputConnection.targetConnection;
-        // Disconnect blocks that existed prior to this change if they don't match.
-        if ((blockA || blockB) && parentConnection) {
-            for (var i = 0; i < 2; i++) {
-                var block = (i == 1) ? blockA : blockB;
-                if (block && !block.outputConnection.checkType_(parentConnection)) {
-                    // Ensure that any disconnections are grouped with the causing event.
-                    Blockly.Events.setGroup(e.group);
-                    if (parentConnection === this.prevParentConnection_) {
-                        this.unplug();
-                        parentConnection.getSourceBlock().bumpNeighbours_();
-                    } else {
-                        block.unplug();
-                        block.bumpNeighbours_();
-                    }
-                    Blockly.Events.setGroup(false);
-                }
-            }
-        }
-        this.prevParentConnection_ = parentConnection;
+Blockly.Python.ai_lcd_draw_rectangle = function (block) {
+    var color = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_ATOMIC);
+    var type = block.getFieldValue('rect_type') == "fillrect" ? "-1" : "1";
+    var xy = Blockly.Python.valueToCode(block, 'POSA', Blockly.Python.ORDER_ATOMIC);
+    var size = Blockly.Python.valueToCode(block, 'POSB', Blockly.Python.ORDER_ATOMIC);
+    // console.log(xy.split(','),size.split(','))
+    let a = xy.split(',')
+    let b = size.split(',')
+    let w = Number(a[0]) + Number(b[0])
+    let h = Number(a[1]) + Number(b[1])
+    var _code = ''
+    if (color.charAt(0) == '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == color.length && (d = parseInt(color.substring(1, 3), 16),
+                e = parseInt(color.substring(3, 5), 16),
+                f = parseInt(color.substring(5, 7), 16))
+        } catch (g) { }
+        _code = `canvas.draw_rectangle(${xy}, ${a[0]}+${b[0]},${a[1]}+${b[1]}, color=(${d},${e},${f}), thickness=${type})
+`
+    } else if (color.charAt(0) != '#') {
+        _code = `canvas.draw_rectangle(${xy}, ${a[0]}+${b[0]},${a[1]}+${b[1]}, color=${color}, thickness=${type})
+`
+    }
+    return _code;
+}
+
+Blockly.Blocks['ai_lcd_drawcirclecarvas'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_text_on_draw)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.image_process_text_filled, "fillrect"],
+                [Blockly.Msg.image_process_text_stroked, "rect"]
+            ]), "rect_type")
+            .appendField(Blockly.Msg.image_process_draw_circle_text);
+        this.appendValueInput("POSA")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_draw_circle_text_start);
+        this.appendValueInput("Scale")
+            .setCheck("Number")
+            .appendField(Blockly.Msg.image_process_text_radius);
+        this.appendValueInput("COLOR")
+            .setCheck("String")
+            .appendField(Blockly.Msg.image_process_text_color);
+        this.appendValueInput("Scale_0")
+            .setCheck("Number")
+            .appendField(Blockly.Msg.image_process_text_thick);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true);
+        this.setNextStatement(true);
+        this.setColour(screenColor);
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('rect_type');
+            var TOOLTIPS = {
+                'fillrect': Blockly.Msg.ai_lcd_drawcirclecarvas_TOOLTIP.replace('%1', Blockly.Msg.image_process_text_filled),
+                'rect': Blockly.Msg.ai_lcd_drawcirclecarvas_TOOLTIP.replace('%1', Blockly.Msg.image_process_text_stroked)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl('');
     }
 };
 
-Blockly.Blocks['logic_isIn'] = {
-    /**
-     * Block for testing if something contains something.
-     * @this Blockly.Block
-     */
+Blockly.Python.ai_lcd_drawcirclecarvas = function (block) {
+    var color = Blockly.Python.valueToCode(block, 'COLOR', Blockly.Python.ORDER_ATOMIC);
+    if (color.charAt(0) == '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == color.length && (d = parseInt(color.substring(1, 3), 16),
+                e = parseInt(color.substring(3, 5), 16),
+                f = parseInt(color.substring(5, 7), 16))
+        } catch (g) { }
+        var type = block.getFieldValue('rect_type') == "fillrect" ? "-1" : "1";
+        var th = Blockly.Python.valueToCode(block, 'Scale', Blockly.Python.ORDER_ATOMIC);
+        var xy = Blockly.Python.valueToCode(block, 'POSA', Blockly.Python.ORDER_ATOMIC);
+        var th0 = Blockly.Python.valueToCode(block, 'Scale_0', Blockly.Python.ORDER_ATOMIC);
+        var _code = "canvas.draw_circle(" + xy + ", " + th + ", color=(" + d + ", " + e + ", " + f + "), thickness=" + type + ")\n";
+    } else if (color.charAt(0) != '#') {
+        var d = 0,
+            e = 0,
+            f = 0;
+        try {
+            7 == color.length && (d = parseInt(color.substring(1, 3), 16),
+                e = parseInt(color.substring(3, 5), 16),
+                f = parseInt(color.substring(5, 7), 16))
+        } catch (g) { }
+        var type = block.getFieldValue('rect_type') == "fillrect" ? "-1" : "1";
+        var th = Blockly.Python.valueToCode(block, 'Scale', Blockly.Python.ORDER_ATOMIC);
+        var xy = Blockly.Python.valueToCode(block, 'POSA', Blockly.Python.ORDER_ATOMIC);
+        var th0 = Blockly.Python.valueToCode(block, 'Scale_0', Blockly.Python.ORDER_ATOMIC);
+        var _code = "canvas.draw_circle(" + xy + ", " + th + ", color=" + color + ", thickness=" + type + ")\n";
+    }
+    return _code;
+}
+
+Blockly.Blocks['ai_lcd_draw_image_on_canvas'] = {
     init: function () {
-        var OPERATORS =
-            [["is in", 'IN'],
-            ["is not in", 'NOTIN']];
-        this.setColour(CategoryColors.Logic);
-        this.setOutput(true, 'Boolean');
-        this.appendValueInput('ITEM');
-        this.appendValueInput('LIST')
-            .setCheck(['Array', 'String'])
-            .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP');
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_text_on_canvas)
+
+            .appendField(Blockly.Msg.image_process_draw_image_title);
+        this.appendValueInput("image_path")
+            .setCheck(null)
+            .appendField(Blockly.Msg.image_process_draw_sensor_image_path);
+        this.appendValueInput("scale_y")
+            .setCheck(null)
+            .appendField(Blockly.Msg.OLCD_COORDINATE);
         this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_draw_image_on_canvas_TOOLTIP);
+        this.setHelpUrl("");
     }
 };
 
 
-Blockly.Blocks['logic_none'] = {
-    /**
-     * Block for testing if something contains something.
-     * @this Blockly.Block
-     */
+Blockly.Python['ai_lcd_draw_image_on_canvas'] = function (block) {
+    var value_image_path = Blockly.Python.valueToCode(block, 'image_path', Blockly.Python.ORDER_ATOMIC);
+    var value_scale_y = Blockly.Python.valueToCode(block, 'scale_y', Blockly.Python.ORDER_ATOMIC);
+    var code = '' +
+        'canvas.draw_image(' + value_image_path + ',' + value_scale_y + ',alpha=1)\n' +
+        '\n';
+
+    return code;
+};
+Blockly.Blocks['ai_lcd_rotation'] = {
     init: function () {
         this.appendDummyInput()
-            .appendField("None");
-        this.setColour(CategoryColors.Logic);
-        this.setOutput(true);
+            .appendField(Blockly.Msg.LCD_CANVAS)
+
+            .appendField(Blockly.Msg.image_process_set_lcd_rotation)
+            .appendField(new Blockly.FieldDropdown([
+                ["0°", "0"],
+                ["90°", "90"],
+                ["180°", "180"],
+                ["270°", "270"]
+            ]), "DEGREE")
+            .appendField(Blockly.Msg.CATEGORY_SHOW)
+        this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_rotation_TOOLTIP);
+        this.setHelpUrl('');
+    }
+}
+
+Blockly.Python.ai_lcd_rotation = function (block) {
+    var dropdown_name = block.getFieldValue('DEGREE');
+
+    let w = ''
+    let h = ''
+    if (dropdown_name == 90 || dropdown_name == 270) {
+        w = 240
+        h = 320
+    } else {
+        w = 320
+        h = 240
     }
+    var _code = `
+`;
+    return _code;;
+}
+Blockly.Blocks['ai_lcd_showcarvas_set_display'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_show_canvas)
+            ;
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_showcarvas_set_display_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Python.ai_lcd_showcarvas_set_display = function (block) {
+    Blockly.Python.definitions_['import_base64'] = `import base64`
+    Blockly.Python.definitions_['import_time'] = `import time`
+    var code = `
+`;
+    return code;
 };
+Blockly.Blocks['ai_lcd_clearcanvas'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.image_process_clear_canvas_2);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(screenColor);
+        this.setTooltip(Blockly.Msg.ai_lcd_clearcanvas_TOOLTIP);
+        this.setHelpUrl('');
+    }
+}
+
+Blockly.Python.ai_lcd_clearcanvas = function (block) {
+    var _code = "canvas.clear()\n";
+    return _code;;
+}
 export default Blockly

+ 93 - 0
src/Blockly/blocks/camera.js

@@ -0,0 +1,93 @@
+import * as Blockly from 'blockly';
+import { pythonGenerator } from 'blockly/python';
+
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) };
+
+const color = '#60c1bb';
+
+Blockly.Blocks['ai_camera_init'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('摄像头初始化');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('初始化摄像头');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['ai_camera_init'] = function (block) {
+    var code = 'camera.init()\n';
+    return code;
+};
+
+Blockly.Blocks['ai_camera_windows'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('获取相机图像');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('获取相机图像');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['ai_camera_windows'] = function (block) {
+    var code = 'camera.windows()\n';
+    return code;
+};
+
+Blockly.Blocks['ai_camera_image_property_change'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('摄像头窗口');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('打开摄像头窗口');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['ai_camera_image_property_change'] = function (block) {
+    var code = 'display.show(image)\n';
+    return code;
+}
+
+Blockly.Blocks['ai_camera_snapshot'] = { 
+    init: function () {
+        this.appendDummyInput()
+            .appendField('摄像头拍照');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('拍摄一张照片');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['ai_camera_snapshot'] = function (block) {
+    var code = 'camera.snapshot()\n';
+    return code;
+};
+
+Blockly.Blocks['v831_camera_graph_transmission'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('V831摄像头图像传输');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('V831摄像头图像传输');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['v831_camera_graph_transmission'] = function (block) {
+    var code = 'V831摄像头图像传输()\n';
+    return code;
+};
+
+export default Blockly;

+ 8 - 1
src/Blockly/blocks/index.js

@@ -14,10 +14,17 @@ import output from "./output";
 import file from "./file";
 import time from "./time";
 import serial from "./serial";
+import MediaProcessing from "./MediaProcessing"
+import Camera from "./camera.js"
+import Mircrohone from "./microphone.js";
+import System from "./system.js"
+import AI from "./ai.js"
+import IOT from "./Iot.js"
 
 const Blockly = {
     ...basic, ...logic, ...math, ...variable, ...text, ...list, ...dictionary,
-    ...tuples, ...set, ...procedures, ...output, ...file, ...time, ...serial
+    ...tuples, ...set, ...procedures, ...output, ...file, ...time, ...serial, ...MediaProcessing, ...Camera,
+    ...Mircrohone, ...System, ...AI, ...IOT
 };
 
 export default Blockly;

+ 600 - 0
src/Blockly/blocks/logic.js

@@ -1,7 +1,607 @@
 import * as Blockly from "blockly";
 
 import CategoryColors from "./define_color";
+Blockly.Blocks['custom_text_block'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.numpy_mnist_clear)
+            .appendField(new Blockly.FieldTextInput("张三丰"), "TEXT_INPUT");
+        // this.setOutput(true, null);
+        this.setPreviousStatement(true, null)
+        this.setNextStatement(true, null)
+        this.setTooltip("");
+        this.setHelpUrl("");
+        this.setStyle('custom_text_blocks')
+    }
+};
+Blockly.Blocks["CocoRobo_return"] = {
+    init: function () {
+        this.jsonInit({
+            inputsInline: !0,
+            nextStatement: null,
+            previousStatement: null,
+            colour: CategoryColors.Logic,
+            tooltip: Blockly.Msg.CocoRobo_RETURN_TOOLTIP,
+            message0: Blockly.Msg.CocoRobo_RETURN_MESSAGE0,
+            args0: [{
+                type: "input_value",
+                name: "VAR"
+            }]
+        })
+    }
+}
+Blockly.Blocks.CocoRobo_try_except = {
+    init: function () {
+        this.jsonInit({
+            message0: "",
+            previousStatement: null,
+            nextStatement: null,
+            colour: CategoryColors.Logic,
+            tooltip: Blockly.Msg.CocoRobo_try_except_TOOLTIP,
+            helpUrl: ""
+        });
+        this.appendStatementInput("TRY").appendField("try");
+        this.appendStatementInput("EXCEPT").appendField("except");
+    }
+}
+
+Blockly.Blocks.CocoRobo_try_except_finally = {
+    init: function () {
+        this.jsonInit({
+            message0: "",
+            previousStatement: null,
+            nextStatement: null,
+            colour: CategoryColors.Logic,
+            tooltip: Blockly.Msg.CocoRobo_try_except_finally_TOOLTIP,
+            helpUrl: ""
+        });
+        this.appendStatementInput("TRY").appendField("try");
+        this.appendStatementInput("EXCEPT").appendField("except");
+        this.appendStatementInput("FINALLY").appendField("finally")
+    }
+};
+
+Blockly.Blocks.CocoRobo_type = {
+    init: function () {
+        this.jsonInit({
+            message0: "值 %1 的类型",
+            args0: [{
+                type: "input_value",
+                name: "VAR"
+            }],
+            output: null,
+            colour: CategoryColors.Logic,
+            tooltip: "返回当前值的类型",
+            helpUrl: ""
+        })
+    }
+};
+Blockly.Blocks.CocoRobo_type_is = {
+    init: function () {
+        this.jsonInit({
+            message0: '值 %1 的类型为 %2',
+            args0: [{
+                type: "input_value",
+                name: "VAR"
+            }, {
+                name: "TYPE",
+                options: [
+                    ["int", "int"],
+                    ["float", "float"],
+                    ["bool", "bool"],
+                    ["str", "str"],
+                    ["list", "list"],
+                    ["tuple", "tuple"],
+                    ["set", "set"],
+                    ["dict", "dict"],
+                    ["bytes", "bytes"],
+                    ["bytearray", "bytearray"],
+                    ["complex", "complex"]
+                ],
+                type: "field_dropdown"
+            }],
+            output: "Boolean",
+            colour: CategoryColors.Logic,
+            // tooltip: Blockly.Msg.CocoRobo_TYPE_IS_TOOLTIP,
+            helpUrl: Blockly.Msg.CocoRobo_TYPE_IS_HELPURL
+        });
+        var thisBlock = this;
+        this.setTooltip(function () {
+            return Blockly.Msg.CocoRobo_TYPE_IS_TOOLTIP.replace('%2',
+                thisBlock.getFieldValue('TYPE'));
+        });
+    }
+};
+Blockly.Blocks.CocoRobo_eval = {
+    init: function () {
+        this.jsonInit({
+            message0: '计算表达式 %1 的结果',
+            args0: [{
+                check: "String",
+                type: "input_value",
+                name: "VAR"
+            }],
+            output: null,
+            colour: CategoryColors.Logic,
+            tooltip: '计算字符串表达式,并返回结果',
+            helpUrl: ""
+        })
+    }
+};
+
+const HUE = "#9d64fd"
+Blockly.Blocks.controls_repeat_forever = {
+    init: function () {
+        this.jsonInit({
+            message0: Blockly.Msg.CONTROLS_REPEAT_FOREVER,
+            previousStatement: null,
+            nextStatement: null,
+            colour: HUE,
+            tooltip: Blockly.Msg.CONTROLS_REPEAT_FOREVER_TOOLTIP,
+            helpUrl: Blockly.Msg.CONTROLS_REPEAT_HELPURL
+        });
+        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)
+    }
+};
+Blockly.Blocks.controls_repeat_ext = {
+    init: function () {
+        this.jsonInit({
+            message0: Blockly.Msg.CONTROLS_REPEAT_TITLE,
+            args0: [{
+                type: "input_value",
+                name: "TIMES",
+                check: "Number"
+            }],
+            previousStatement: null,
+            nextStatement: null,
+            colour: HUE,
+            tooltip: Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,
+            helpUrl: Blockly.Msg.CONTROLS_REPEAT_HELPURL
+        });
+        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)
+    }
+};
+Blockly.Blocks.controls_repeat = {
+    init: function () {
+        this.jsonInit({
+            message0: Blockly.Msg.CONTROLS_REPEAT_TITLE,
+            args0: [{
+                type: "field_number",
+                name: "TIMES",
+                value: 10,
+                min: 0,
+                precision: 1
+            }],
+            previousStatement: null,
+            nextStatement: null,
+            colour: HUE,
+            tooltip: Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,
+            helpUrl: Blockly.Msg.CONTROLS_REPEAT_HELPURL
+        });
+        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)
+    }
+};
+Blockly.Blocks.controls_whileUntil = {
+    init: function () {
+        var a = [[Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_WHILE, "WHILE"], [Blockly.Msg.CONTROLS_WHILEUNTIL_OPERATOR_UNTIL, "UNTIL"]];
+        this.setHelpUrl(Blockly.Msg.CONTROLS_WHILEUNTIL_HELPURL);
+        this.setColour(HUE);
+        this.appendValueInput("BOOL").setCheck("Boolean").appendField(new Blockly.FieldDropdown(a), "MODE");
+        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_WHILEUNTIL_INPUT_DO);
+        this.setPreviousStatement(!0);
+        this.setNextStatement(!0);
+        var b = this;
+        this.setTooltip(function () {
+            var a = b.getFieldValue("MODE");
+            return {
+                WHILE: Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_WHILE,
+                UNTIL: Blockly.Msg.CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL
+            }[a]
+        })
+    }
+};
+Blockly.Blocks.controls_for = {
+    init: function () {
+        this.jsonInit({
+            message0: Blockly.Msg.CONTROLS_FOR_TITLE,
+            args0: [{
+                type: "field_variable",
+                name: "VAR",
+                variable: null
+            }, {
+                type: "input_value",
+                name: "FROM",
+                check: "Number",
+                align: "RIGHT"
+            }, {
+                type: "input_value",
+                name: "TO",
+                check: "Number",
+                align: "RIGHT"
+            }, {
+                type: "input_value",
+                name: "BY",
+                check: "Number",
+                align: "RIGHT"
+            }],
+            inputsInline: !0,
+            previousStatement: null,
+            nextStatement: null,
+            colour: HUE,
+            helpUrl: Blockly.Msg.CONTROLS_FOR_HELPURL
+        });
+        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_FOR_INPUT_DO);
+        var a = this;
+        this.setTooltip(function () {
+            return Blockly.Msg.CONTROLS_FOR_TOOLTIP.replace("%1", a.getFieldValue("VAR"))
+        })
+    },
+    // customContextMenu: function (a) {
+    //     if (!this.isCollapsed()) {
+    //         var b = {
+    //             enabled: !0
+    //         }
+    //             , c = this.getFieldValue("VAR");
+    //         b.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace("%1", c);
+    //         c = goog.dom.createDom("field", null, c);
+    //         c.setAttribute("name", "VAR");
+    //         c = goog.dom.createDom("block", null, c);
+    //         c.setAttribute("type", "variables_get");
+    //         b.callback = Blockly.ContextMenu.callbackFactory(this, c);
+    //         a.push(b)
+    //     }
+    // }
+};
+Blockly.Blocks.controls_forEach = {
+    init: function () {
+        this.jsonInit({
+            message0: Blockly.Msg.CONTROLS_FOREACH_TITLE,
+            args0: [{
+                type: "field_variable",
+                name: "VAR",
+                variable: null
+            }, {
+                type: "input_value",
+                name: "LIST",
+                check: "Array"
+            }],
+            previousStatement: null,
+            nextStatement: null,
+            colour: HUE,
+            helpUrl: Blockly.Msg.CONTROLS_FOREACH_HELPURL
+        });
+        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_FOREACH_INPUT_DO);
+        var a = this;
+        this.setTooltip(function () {
+            return Blockly.Msg.CONTROLS_FOREACH_TOOLTIP.replace("%1", a.getFieldValue("VAR"))
+        })
+    },
+    customContextMenu: Blockly.Blocks.controls_for.customContextMenu
+};
+Blockly.Blocks.controls_flow_statements = {
+    init: function () {
+        var a = [[Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK, "BREAK"], [Blockly.Msg.CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE, "CONTINUE"]];
+        this.setHelpUrl(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_HELPURL);
+        this.setColour(HUE);
+        this.appendDummyInput().appendField(new Blockly.FieldDropdown(a), "FLOW");
+        this.setPreviousStatement(!0);
+        var b = this;
+        this.setTooltip(function () {
+            var a = b.getFieldValue("FLOW");
+            return {
+                BREAK: Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK,
+                CONTINUE: Blockly.Msg.CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE
+            }[a]
+        })
+    },
+    onchange: function (a) {
+        if (!this.workspace.isDragging()) {
+            a = !1;
+            var b = this;
+            do {
+                if (-1 != this.LOOP_TYPES.indexOf(b.type)) {
+                    a = !0;
+                    break
+                }
+                b = b.getSurroundParent()
+            } while (b); a ? (this.setWarningText(null),
+                this.isInFlyout || this.setDisabled(!1)) : (this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING),
+                    this.isInFlyout || this.getInheritedDisabled() || this.setDisabled(!0))
+        }
+    },
+    LOOP_TYPES: "controls_repeat_forever controls_repeat controls_repeat_ext controls_forEach controls_for controls_whileUntil tello_repeat_forever".split(" ")
+};
+// 获取原始积木定义
+const originalIfBlock = Blockly.Blocks['controls_if'];
 
+Blockly.Blocks.controls_if = {
+    init: function () {
+        originalIfBlock.init.call(this);
+        this.setColour(CategoryColors.Logic);
+    },
+    
+};
+Blockly.Blocks.controls_if_elseif = {
+    init: function () {
+        this.setColour(CategoryColors.Logic);
+        this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF);
+        this.setPreviousStatement(!0);
+        this.setNextStatement(!0);
+        this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP);
+        this.contextMenu = !1
+    }
+};
+Blockly.Blocks.controls_if_else = {
+    init: function () {
+        this.setColour(CategoryColors.Logic);
+        this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE);
+        this.setPreviousStatement(!0);
+        this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP);
+        this.contextMenu = !1
+    }
+};
+Blockly.Blocks.controls_if_if = {
+    init: function () {
+        this.setColour(CategoryColors.Logic);
+        this.appendDummyInput().appendField(Blockly.Msg.CONTROLS_IF_IF_TITLE_IF);
+        this.setNextStatement(!0);
+        this.setTooltip(Blockly.Msg.CONTROLS_IF_IF_TOOLTIP);
+        this.contextMenu = !1
+    }
+};
+Blockly.Blocks['logic_compare'] = {
+    /**
+     * Block for comparison operator.
+     * @this Blockly.Block
+     */
+    init: function () {
+        var rtlOperators = [
+            ['==', 'EQ'],
+            ['!=', 'NEQ'],
+            ['>', 'LT'],
+            ['>=', 'LTE'],
+            ['<', 'GT'],
+            ['<=', 'GTE']
+        ];
+        var ltrOperators = [
+            ['==', 'EQ'],
+            ['!=', 'NEQ'],
+            ['<', 'LT'],
+            ['<=', 'LTE'],
+            ['>', 'GT'],
+            ['>=', 'GTE']
+        ];
+        var OPERATORS = this.RTL ? rtlOperators : ltrOperators;
+        this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL);
+        this.setColour(CategoryColors.Logic);
+        this.setOutput(true, 'Boolean');
+        this.appendValueInput('A');
+        this.appendValueInput('B')
+            .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP');
+        this.setInputsInline(true);
+        // Assign 'this' to a variable for use in the tooltip closure below.
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var op = thisBlock.getFieldValue('OP');
+            var TOOLTIPS = {
+                'EQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ,
+                'NEQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ,
+                'LT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT,
+                'LTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE,
+                'GT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT,
+                'GTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE
+            };
+            return TOOLTIPS[op];
+        });
+        this.prevBlocks_ = [null, null];
+    },
+    /**
+     * Called whenever anything on the workspace changes.
+     * Prevent mismatched types from being compared.
+     * @param {!Blockly.Events.Abstract} e Change event.
+     * @this Blockly.Block
+     */
+    onchange: function (e) {
+        var blockA = this.getInputTargetBlock('A');
+        var blockB = this.getInputTargetBlock('B');
+        // Disconnect blocks that existed prior to this change if they don't match.
+        if (blockA && blockB &&
+            !blockA.outputConnection.checkType_(blockB.outputConnection)) {
+            // Mismatch between two inputs.  Disconnect previous and bump it away.
+            // Ensure that any disconnections are grouped with the causing event.
+            Blockly.Events.setGroup(e.group);
+            for (var i = 0; i < this.prevBlocks_.length; i++) {
+                var block = this.prevBlocks_[i];
+                if (block === blockA || block === blockB) {
+                    block.unplug();
+                    block.bumpNeighbours_();
+                }
+            }
+            Blockly.Events.setGroup(false);
+        }
+        this.prevBlocks_[0] = blockA;
+        this.prevBlocks_[1] = blockB;
+    }
+};
+Blockly.Blocks['logic_operation'] = {
+    /**
+     * Block for logical operations: 'and', 'or'.
+     * @this Blockly.Block
+     */
+    init: function () {
+        var OPERATORS =
+            [[Blockly.Msg.LOGIC_OPERATION_AND, 'AND'],
+            [Blockly.Msg.LOGIC_OPERATION_OR, 'OR']];
+        this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL);
+        this.setColour(CategoryColors.Logic);
+        this.setOutput(true, 'Boolean');
+        this.appendValueInput('A')
+            .setCheck('Boolean');
+        this.appendValueInput('B')
+            .setCheck('Boolean')
+            .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP');
+        this.setInputsInline(true);
+        // Assign 'this' to a variable for use in the tooltip closure below.
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var op = thisBlock.getFieldValue('OP');
+            var TOOLTIPS = {
+                'AND': Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND,
+                'OR': Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR
+            };
+            return TOOLTIPS[op];
+        });
+    }
+};
+
+Blockly.Blocks['logic_negate'] = {
+    /**
+     * Block for negation.
+     * @this Blockly.Block
+     */
+    init: function () {
+        this.jsonInit({
+            "message0": Blockly.Msg.LOGIC_NEGATE_TITLE,
+            "args0": [
+                {
+                    "type": "input_value",
+                    "name": "BOOL",
+                    "check": "Boolean"
+                }
+            ],
+            "output": "Boolean",
+            "colour": CategoryColors.Logic,
+            "tooltip": Blockly.Msg.LOGIC_NEGATE_TOOLTIP,
+            "helpUrl": Blockly.Msg.LOGIC_NEGATE_HELPURL
+        });
+    }
+};
+
+Blockly.Blocks['logic_boolean'] = {
+    /**
+     * Block for boolean data type: true and false.
+     * @this Blockly.Block
+     */
+    init: function () {
+        this.jsonInit({
+            "message0": "%1",
+            "args0": [
+                {
+                    "type": "field_dropdown",
+                    "name": "BOOL",
+                    "options": [
+                        [Blockly.Msg.LOGIC_BOOLEAN_TRUE, "TRUE"],
+                        [Blockly.Msg.LOGIC_BOOLEAN_FALSE, "FALSE"]
+                    ]
+                }
+            ],
+            "output": "Boolean",
+            "colour": CategoryColors.Logic,
+            "tooltip": Blockly.Msg.LOGIC_BOOLEAN_TOOLTIP,
+            "helpUrl": Blockly.Msg.LOGIC_BOOLEAN_HELPURL
+        });
+    }
+};
+
+Blockly.Blocks['logic_null'] = {
+    /**
+     * Block for null data type.
+     * @this Blockly.Block
+     */
+    init: function () {
+        this.jsonInit({
+            "message0": Blockly.Msg.LOGIC_NULL,
+            "output": null,
+            "colour": CategoryColors.Logic,
+            "tooltip": Blockly.Msg.LOGIC_NULL_TOOLTIP,
+            "helpUrl": Blockly.Msg.LOGIC_NULL_HELPURL
+        });
+    }
+};
+
+Blockly.Blocks['logic_ternary'] = {
+    /**
+     * Block for ternary operator.
+     * @this Blockly.Block
+     */
+    init: function () {
+        this.setHelpUrl(Blockly.Msg.LOGIC_TERNARY_HELPURL);
+        this.setColour(CategoryColors.Logic);
+        this.appendValueInput('IF')
+            .setCheck('Boolean')
+            .appendField(Blockly.Msg.LOGIC_TERNARY_CONDITION);
+        this.appendValueInput('THEN')
+            .appendField(Blockly.Msg.LOGIC_TERNARY_IF_TRUE);
+        this.appendValueInput('ELSE')
+            .appendField(Blockly.Msg.LOGIC_TERNARY_IF_FALSE);
+        this.setOutput(true);
+        this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP);
+        this.prevParentConnection_ = null;
+    },
+    /**
+     * Called whenever anything on the workspace changes.
+     * Prevent mismatched types.
+     * @param {!Blockly.Events.Abstract} e Change event.
+     * @this Blockly.Block
+     */
+    onchange: function (e) {
+        var blockA = this.getInputTargetBlock('THEN');
+        var blockB = this.getInputTargetBlock('ELSE');
+        var parentConnection = this.outputConnection.targetConnection;
+        // Disconnect blocks that existed prior to this change if they don't match.
+        if ((blockA || blockB) && parentConnection) {
+            for (var i = 0; i < 2; i++) {
+                var block = (i == 1) ? blockA : blockB;
+                if (block && !block.outputConnection.checkType_(parentConnection)) {
+                    // Ensure that any disconnections are grouped with the causing event.
+                    Blockly.Events.setGroup(e.group);
+                    if (parentConnection === this.prevParentConnection_) {
+                        this.unplug();
+                        parentConnection.getSourceBlock().bumpNeighbours_();
+                    } else {
+                        block.unplug();
+                        block.bumpNeighbours_();
+                    }
+                    Blockly.Events.setGroup(false);
+                }
+            }
+        }
+        this.prevParentConnection_ = parentConnection;
+    }
+};
+
+Blockly.Blocks['logic_isIn'] = {
+    /**
+     * Block for testing if something contains something.
+     * @this Blockly.Block
+     */
+    init: function () {
+        var OPERATORS =
+            [["is in", 'IN'],
+            ["is not in", 'NOTIN']];
+        this.setColour(CategoryColors.Logic);
+        this.setOutput(true, 'Boolean');
+        this.appendValueInput('ITEM');
+        this.appendValueInput('LIST')
+            .setCheck(['Array', 'String'])
+            .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP');
+        this.setInputsInline(true);
+    }
+};
+
+
+Blockly.Blocks['logic_none'] = {
+    /**
+     * Block for testing if something contains something.
+     * @this Blockly.Block
+     */
+    init: function () {
+        this.appendDummyInput()
+            .appendField("None");
+        this.setColour(CategoryColors.Logic);
+        this.setOutput(true);
+    }
+};
 Blockly.Blocks.CocoRobo_return = {
     init: function () {
         this.jsonInit({

+ 174 - 0
src/Blockly/blocks/microphone.js

@@ -0,0 +1,174 @@
+import * as Blockly from 'blockly';
+import { pythonGenerator } from 'blockly/python';
+
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) };
+
+const color = '#5fcd8e';
+
+Blockly.Blocks['ai_mphone_record_init'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('Microphone Init');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('Initialize the microphone');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['ai_mphone_record_init'] = function (block) {
+    var code = 'microphone.init()\n';
+    return code;
+}
+
+Blockly.Blocks['ai_mphone_record_setting'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('Microphone Start');
+        this.appendValueInput("PATH")
+            .setCheck(null)
+            .appendField('音频文件路径');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('Start recording');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['ai_mphone_record_setting'] = function (block) {
+    let _path = Blockly.Python.valueToCode(block, 'PATH', Blockly.Python.ORDER_ATOMIC);
+    var code = _path + '\n';
+    return code;
+};
+
+Blockly.Blocks['ai_mphone_Record_audio_start'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('Microphone Stop');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('Stop recording');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['ai_mphone_Record_audio_start'] = function (block) {
+    var code = 'microphone.stop()\n';
+    return code;
+};
+
+Blockly.Blocks['ai_mphone_Record_audio_sound_loudness_analysis'] = { 
+    init: function() {
+        this.appendDummyInput()
+            .appendField('停止录音');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('停止录音');
+        this.setHelpUrl('');
+    }
+};
+Blockly.Python['ai_mphone_Record_audio_sound_loudness_analysis'] = function (block) {
+    var code = 'microphone.start()\n';
+    return code;
+};
+
+Blockly.Blocks['mphone_audio_spectrum_init'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('录音');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('录音');
+        this.setHelpUrl('');
+    }
+};
+
+Blockly.Python['mphone_audio_spectrum_init'] = function (block) {
+    var code = '录音\n';
+    return code;
+};
+
+Blockly.Blocks['mphone_audio_spectrum_setting'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('录音设置');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('设置录音参数');    
+        this.setHelpUrl('');
+    }
+    
+};
+
+Blockly.Python['mphone_audio_spectrum_setting'] = function (block) {
+    var code = '设置录音参数\n';    
+    return code;
+    
+};
+
+Blockly.Blocks['ai_mphone_read_sound_sensitivity'] = {
+    init: function() {
+        this.appendDummyInput()
+            .appendField('开始录音');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+        this.setTooltip('开始录音');
+        this.setHelpUrl('');
+    }
+    
+};
+
+Blockly.Python['ai_mphone_read_sound_sensitivity'] = function (block) {
+    var code = '开始录音\n';
+    return code;
+}
+
+const speakerColor = '#603ea0';
+// 扬声器
+Blockly.Blocks['ai_speaker_play_wav'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('播放音频文件');
+        this.appendValueInput("PATH")
+            .setCheck(null)
+            .appendField('音频文件路径');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setInputsInline(true);
+        this.setColour(speakerColor);
+        this.setTooltip('初始化扬声器');
+        this.setHelpUrl('');
+    }
+}
+
+Blockly.Python['ai_speaker_play_wav'] = function (block) {
+    var _path = Blockly.Python.valueToCode(block, 'PATH', Blockly.Python.ORDER_ATOMIC);
+    var code = _path + '\n';
+    return code;
+}
+
+Blockly.Blocks['set_volume'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('设置音量')
+            .appendField(new Blockly.FieldNumber(50, 0, 100), 'VOLUME');
+        this.setNextStatement(true, null);
+        this.setColour(speakerColor);
+        this.setPreviousStatement(true, null);
+    }
+}
+
+Blockly.Python['set_volume'] = function (block) { 
+    var volume = block.getFieldValue('VOLUME');
+    var code = 'speaker.set_volume(' + volume + ')\n';
+    return code;
+}
+
+export default Blockly;

+ 4 - 22
src/Blockly/blocks/serial.js

@@ -33,31 +33,19 @@ Blockly.Blocks['serial_write_data_coco'] = {
     init: function () {
         this.appendDummyInput()
             .appendField(new Blockly.FieldImage("./media/cocorobo.png", 65, 65, { alt: "*", flipRtl: "FALSE" }));
-        // this.appendDummyInput()
-        //     .appendField(Blockly.Msg.serialcomm_write_title_text_coco);
+
         this.appendDummyInput()
             .appendField(Blockly.Msg.serialcomm_write_data_bps_title)
             .appendField(new Blockly.FieldNumber(115200, 0, 500000, 1), "uart_bps");
         this.appendDummyInput()
             .appendField(Blockly.Msg.serial_send_data_on_send_data_cocorobo);
-        /*this.appendValueInput("first_input")
-            .setCheck(null)
-            .appendField("Field 0");*/
         this.itemCount_ = 1;
         this.updateShape_();
         this.setMutator(new Blockly.icons.MutatorIcon(['serial_write_data_create_with_item'],this));
         this.setColour("#22b845");
         this.setPreviousStatement(true, null);
         this.setNextStatement(true, null);
-        var thisBlock = this;
-        this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('type');
-            var TOOLTIPS = {
-                'iot': Blockly.Msg.Serial_Write_Data_TOOLTIP.replace('%1', Blockly.Msg.serialcomm_write_on_iot),
-                'ai': Blockly.Msg.Serial_Write_Data_TOOLTIP.replace('%1', Blockly.Msg.serialcomm_write_on_ai)
-            };
-            return TOOLTIPS[mode];
-        });
+        this.setTooltip(Blockly.Msg.Serial_Write_Data_TOOLTIP);
         this.setHelpUrl("");
     },
     mutationToDom: function () {
@@ -166,20 +154,14 @@ Blockly.Blocks['serial_write_data'] = {
             .appendField(Blockly.Msg.serialcomm_write_data_bps_attrib);
         this.appendValueInput("ADD1")
             .setCheck(null)
+            .appendField(Blockly.Msg.serialcomm_write_data);
         // .appendField("Field 0");
         this.itemCount_ = 1;
         this.setColour(serialColor);
         this.setPreviousStatement(true, null);
         this.setNextStatement(true, null);
         var thisBlock = this;
-        this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('type');
-            var TOOLTIPS = {
-                'iot': Blockly.Msg.Serial_Write_Data_TOOLTIP.replace('%1', Blockly.Msg.serialcomm_write_on_iot),
-                'ai': Blockly.Msg.Serial_Write_Data_TOOLTIP.replace('%1', Blockly.Msg.serialcomm_write_on_ai)
-            };
-            return TOOLTIPS[mode];
-        });
+        this.setTooltip(Blockly.Msg.Serial_Write_Data_TOOLTIP);
         this.setHelpUrl("");
     },
 };

+ 114 - 0
src/Blockly/blocks/system.js

@@ -0,0 +1,114 @@
+import * as Blockly from 'blockly';
+import { colour } from 'blockly/blocks';
+import { pythonGenerator } from 'blockly/python';
+
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) };
+const color = '#22398e';
+
+Blockly.Blocks['system_poweroff'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.system_poweroff);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+    }
+};
+Blockly.Python['system_poweroff'] = function (block) {
+    return 'os.system("poweroff")\n';
+};
+
+Blockly.Blocks['system_reboot'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.system_restart);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+    }
+};
+Blockly.Python['system_reboot'] = function (block) {
+    return 'os.system("reboot")\n';
+};
+
+Blockly.Blocks['system_get_cpu_temperature'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('系统重启');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+    }
+};
+Blockly.Python['system_get_cpu_temperature'] = function (block) {
+    return 'os.system("reboot")\n';
+};
+
+// 设置线程1
+Blockly.Blocks['system_set_thread1'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('设置线程')
+            .appendField(new Blockly.FieldDropdown([
+                ['1', '1'],
+                ['2', '2'],
+                ['3', '3'],
+                ['4', '4'],
+                ['5', '5']
+            ]), 'THREAD_COUNT');
+        this.appendStatementInput("input")
+            .setCheck(null)
+            .appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+    }
+};
+
+Blockly.Python['system_set_thread1'] = function (block) {
+    var dropdown_thread_count = block.getFieldValue('THREAD_COUNT');
+    var value_input = Blockly.Python.statementToCode(block, 'input');
+    Blockly.Python.definitions_['import_threading'] = `import threading`;
+    let allBlocks = block.workspace.getAllBlocks();
+    let global = ""
+    try {
+        global = allBlocks[0].workspace.variableList.toString()
+    }
+    catch (e) {
+        console.log(e)
+    }
+    Blockly.Python.definitions_['system_set_thread' + dropdown_thread_count] = `def system_set_thread${dropdown_thread_count}():
+  global ${global}
+${value_input}
+
+Thread${dropdown_thread_count} = threading.Thread(target=system_set_thread${dropdown_thread_count})
+`;
+    var code = '';
+    return code;
+}
+
+Blockly.Blocks["system_start_thread"] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField('启动线程')
+            .appendField(new Blockly.FieldDropdown([
+                ['1', '1'],
+                ['2', '2'],
+                ['3', '3'],
+                ['4', '4'],
+                ['5', '5']
+            ]), 'THREAD_COUNT');
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(color);
+    }
+};
+
+Blockly.Python['system_start_thread'] = function (block) {
+    var dropdown_thread_count = block.getFieldValue('THREAD_COUNT');
+    Blockly.Python.definitions_['import_threading'] = `import threading`;
+    var code = `Thread${dropdown_thread_count}.start()\n`;
+    return code;
+}
+
+export default Blockly;

+ 7 - 38
src/Blockly/blocks/variables.js

@@ -3,51 +3,20 @@ import * as Blockly from 'blockly';
 
 // variables
 const HUE =  '#ffab2f';
+const VariableGet = Blockly.Blocks['variables_get'];
+
+const VariableSet = Blockly.Blocks['variables_set'];
 Blockly.Blocks.variables_get = {
     init: function () {
-        this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL);
+        VariableGet.init.call(this);
         this.setColour(HUE);
-        this.appendDummyInput().appendField(new Blockly.FieldVariable(Blockly.Msg.VARIABLES_DEFAULT_NAME), 'VAR');
-        this.setOutput(!0);
-        this.setTooltip(Blockly.Msg.VARIABLES_GET_TOOLTIP);
-        this.contextMenuMsg_ = Blockly.Msg.VARIABLES_GET_CREATE_SET;
-    },
-    contextMenuType_: 'variables_set',
-    customContextMenu: function (a) {
-        var b = {
-            enabled: !0
-        }
-            , c = this.getFieldValue('VAR');
-        b.text = this.contextMenuMsg_.replace('%1', c);
-        c = this.dom.createDom('field', null, c);
-        c.setAttribute('name', 'VAR');
-        c = this.dom.createDom('block', null, c);
-        c.setAttribute('type', this.contextMenuType_);
-        b.callback = Blockly.ContextMenu.callbackFactory(this, c);
-        a.push(b);
     }
 };
 Blockly.Blocks.variables_set = {
     init: function () {
-        this.jsonInit({
-            message0: Blockly.Msg.VARIABLES_SET,
-            args0: [{
-                type: 'field_variable',
-                name: 'VAR',
-                variable: Blockly.Msg.VARIABLES_DEFAULT_NAME
-            }, {
-                type: 'input_value',
-                name: 'VALUE',
-            }],
-            previousStatement: null,
-            nextStatement: null,
-            colour: HUE,
-            tooltip: Blockly.Msg.VARIABLES_SET_TOOLTIP,
-            helpUrl: Blockly.Msg.VARIABLES_SET_HELPURL
-        });
-    },
-    contextMenuType_: 'variables_get',
-    customContextMenu: Blockly.Blocks.variables_get.customContextMenu
+        VariableSet.init.call(this);
+        this.setColour(HUE);
+    }
 };
 
 

+ 3 - 2
src/Blockly/generator/time.js

@@ -8,7 +8,7 @@ Blockly.Python['time_delay'] = function(block) {
     Blockly.Python.definitions_['import_time'] = 'import time';
     var delayTime = Blockly.Python.valueToCode(
         block, 'DELAY_TIME_MILI', Blockly.Python.ORDER_ATOMIC) || '0';
-    var code = 'time.sleep(' + delayTime + ');\n';
+    var code = 'time.sleep(' + delayTime + '/1000);\n';
     return code;
 };
 
@@ -110,7 +110,7 @@ Blockly.Python['esp32_main_controller_time_period_timer_clear'] = function (bloc
 Blockly.Python.addVariable = function (varName, code, overwrite) {
   var overwritten = false;
   if (overwrite || (Blockly.Python.variableDB_.dbReverse_[varName] === undefined)) {
-    // Blockly.Python.definitions_[varName] = code;
+    Blockly.Python.definitions_[varName] = code;
     // 创建变量并生成对应的变量积木
     if (Blockly && Blockly.Variables && Blockly.getMainWorkspace) {
       const workspace = Blockly.getMainWorkspace();
@@ -123,4 +123,5 @@ Blockly.Python.addVariable = function (varName, code, overwrite) {
   }
   return overwritten;
 };
+
 export default Blockly;

+ 1 - 0
src/Blockly/msg/en.js

@@ -17,6 +17,7 @@ Blockly.Msg["catOutput"] = "Output";
 Blockly.Msg["catFiles"] = "File";
 Blockly.Msg["catTime"] = "Time";
 Blockly.Msg["catSerial"] = "Serial";
+Blockly.Msg["catBasicFunctions"] = "Basic Functions";
 
 //
 Blockly.Msg["ADD_COMMENT"] = "Add Comment";

+ 331 - 2
src/Blockly/msg/zh-hans.js

@@ -1,6 +1,8 @@
 
 'use strict';
 
+import { Block } from "blockly";
+
 var Blockly = Blockly || { Msg: Object.create(null) };
 // category 
 Blockly.Msg["catLogic"] = "逻辑";
@@ -17,6 +19,25 @@ Blockly.Msg["catOutput"] = "输入/输出";
 Blockly.Msg["catFiles"] = "文件";
 Blockly.Msg["catTime"] = "时间";
 Blockly.Msg["catSerial"] = "串口";
+Blockly.Msg["catBasicFunctions"] = "基础功能";
+Blockly.Msg["catBasic"] = "基础";
+Blockly.Msg["catSensors"] = "传感器";
+Blockly.Msg["catPower"] = "动力";
+Blockly.Msg["catServo"] = "舵机";
+Blockly.Msg["catMOTOR"] = "电机";
+Blockly.Msg["catAIScreen"] = "屏幕";
+Blockly.Msg["catCamera"] = "摄像头";
+Blockly.Msg["catMicrophone"] = "麦克风";
+Blockly.Msg["catSpeaker"] = "扬声器";
+Blockly.Msg["catSystem"] = "系统功能";
+Blockly.Msg["ExtendedFunction"] = "媒体处理";
+Blockly.Msg["catImage"] = "图像处理";
+Blockly.Msg["AI"] = "人工智能";
+Blockly.Msg["catIOT"] = "物联网";
+Blockly.Msg["catIOT_WIFI"] = "Wi-Fi";
+Blockly.Msg["catNetworkCommunication"] = "网络通信";
+Blockly.Msg["Get_weather"] = "获取天气";
+
 
 
 
@@ -1166,7 +1187,6 @@ Blockly.Msg.CREATE_EMPTY_SET_TOOLTIP = '';
 Blockly.Msg.CREATE_EMPTY_SET_MESSAGE0 = '创建空集合 %1';
 
 // 输入输出
-
 Blockly.Msg.io_high = "高电平";
 Blockly.Msg.io_low = "低电平";
 Blockly.Msg.digital_set = "设置引脚 #";
@@ -1210,6 +1230,7 @@ Blockly.Msg.serialcomm_write_item_last = " 位数据:";
 Blockly.Msg.serialcomm_write_item = "项目";
 Blockly.Msg.serialcomm_write_data = "数据";
 Blockly.Msg.serialcomm_write_data_bps_title = "设置波特率为:";
+Blockly.Msg.serial_send_data_on_send_data_cocorobo = "CocoPi 发送数据至一代和二代";
 Blockly.Msg.serialcomm_write_data_bps_attrib = "比特/秒";
 Blockly.Msg.serialcomm_write_on = "使用";
 Blockly.Msg.serialcomm_write_on_ai = "AI 模块";
@@ -1291,10 +1312,318 @@ Blockly.Msg.Esp32_Main_Controller_Time_Period_Timer_Clear_TOOLTIP = "%1清除周
 
 // 串口
 Blockly.Msg.serial_Comm_Print_TOOLTIP = "串口打印";
-Blockly.Msg.Serial_Write_Data_TOOLTIP = "使用%1通过串口发送数据至其他设备";
+Blockly.Msg.Serial_Write_Data_TOOLTIP = "通过串口发送数据至其他设备";
 Blockly.Msg.Serial_Read_Data_Setup_TOOLTIP = "使用%1通过串口获取其他设备发送的数据初始化";
 Blockly.Msg.Serial_Read_Data_all_TOOLTIP = "获取串口的数据并存储到serial_data中";
 Blockly.Msg.Serial_Read_Data_TOOLTIP = "从serial_data获取接收到串口数据中的某一位数据";
 Blockly.Msg.Serial_Send_Data_To_Microbit_TOOLTIP = "在%1模块上发送数据至Microbit";
 
+
+Blockly.Msg.rgb_R = "红";
+Blockly.Msg.rgb_G = "绿";
+Blockly.Msg.rgb_B = "蓝";
+Blockly.Msg.ai_lcd_rgb_value_input_TOOLTIP = "返回指定的rgb值";
+Blockly.Msg.image_process_xy_x = "X";
+Blockly.Msg.image_process_xy_y = "Y";
+Blockly.Msg.image_process_wh_width = "宽";
+Blockly.Msg.image_process_wh_height = "高";
+Blockly.Msg.COLOR = "颜色";
+Blockly.Msg.image_start_X = "起点X轴坐标";
+Blockly.Msg.image_start_Y = "起点Y轴坐标";
+Blockly.Msg.image_start_W = "检测框的宽度";
+Blockly.Msg.image_start_H = "检测框的高度";
+Blockly.Msg.image_start_CX = "检测框中心点X轴坐标";
+Blockly.Msg.image_start_CY = "检测框中心点Y轴坐标";
+Blockly.Msg.image_start_result = "结果";
+Blockly.Msg.image_start_confidence = "置信度";
+Blockly.Msg.ai_model_digital_new_text = "对检测的每一个手写数字结果"
+
+// 基础
+Blockly.Msg.ai_basic_button_when = "当按钮";
+Blockly.Msg.ai_basic_pressed = "按下时";
+Blockly.Msg.ai_basic_released = "松开时";
+Blockly.Msg.ai_basic_led_set = "设置";
+Blockly.Msg.ai_basic_led_blue = "蓝色LED";
+Blockly.Msg.ai_basic_led_red = "LED2(右侧)";
+Blockly.Msg.ai_basic_led_on = "点亮";
+Blockly.Msg.ai_basic_led_off = "熄灭";
+Blockly.Msg.ai_basic_rgb_set_on = "点亮 RGB 灯,灯颜色为";
+Blockly.Msg.ai_basic_rgb_set_off = "熄灭 RGB 灯";
+
+Blockly.Msg.ai_basic_led_analog_set = "设置";
+Blockly.Msg.ai_basic_led_analog_led1 = "LED1";
+Blockly.Msg.ai_basic_led_analog_led2 = "LED2";
+Blockly.Msg.ai_basic_led_analog_brightness_text = "的灯光亮度为";
+Blockly.Msg.ai_basic_led_analog_range_text = "(数值范围: 0~100)";
+
+Blockly.Msg.ai_k210_button_read_pressed_TOOLTIP= "当按钮%1按下时";
+Blockly.Msg.ai_k210_button_read_released_TOOLTIP= "当按钮%1松开时";
+Blockly.Msg.ai_k210_led_light_up_TOOLTIP= "设置%1点亮";
+Blockly.Msg.ai_basic_light_up_led_analog_TOOLTIP= "设置%1的灯光亮度";
+Blockly.Msg.ai_k210_led_light_off_TOOLTIP= "设置%1熄灭";
+
+// 传感器
+Blockly.Msg.basic_light_get = "获取光线值(0~4095)";
+Blockly.Msg.ESP32_ENV_GET_TEXT = "获取";
+Blockly.Msg.basic_temperature = "温度";
+Blockly.Msg.basic_humidity = "湿度";
+Blockly.Msg.basic_env_value = "数值";
+Blockly.Msg.Esp32_Main_Controller_Get_Environmental_Value_TOOLTIP = "获取%1数值";
+Blockly.Msg.Esp32_Main_Controller_Motion_When_Shaking_STATEMENT_TOOLTIP = "当模块%1摇晃状态时,执行操作";
+Blockly.Msg.Esp32_Main_Controller_Motion_When_Tilting_STATEMENT_TOOLTIP= "当模块%1倾斜时,执行操作";
+Blockly.Msg.Esp32_Main_Controller_Motion_Acceleration_TOOLTIP= "获取%1轴的加速度";
+Blockly.Msg.Esp32_Main_Controller_Motion_Rotation_Measurement_TOOLTIP = "获取%1轴的旋转测量值";
+Blockly.Msg.Esp32_Main_Controller_Motion_Tilt_Angle_TOOLTIP= "获取%1轴的倾斜角度";
+Blockly.Msg.basic_motion_get_along = "获取沿";
+Blockly.Msg.basic_motion_accel = "轴的加速度";
+Blockly.Msg.basic_motion_angle = "轴的倾斜角度";
+Blockly.Msg.basic_motion_rotation_measurement = "轴的旋转测量值";
+Blockly.Msg.basic_when_tilting_get = "当模块";
+
+// 动力
+// 舵机
+Blockly.Msg.servo_setup_ai = "舵机初始化";
+Blockly.Msg.servo_set_gpio_ai = "设置位于引脚 #";
+Blockly.Msg.servo_rotate_to_ai = "的舵机转动至";
+Blockly.Msg.servo_degree_ai = "度 (0˚~180˚)";
+Blockly.Msg.extension_servo_setup_on_ai_TOOLTIP = "模块舵机初始化";
+Blockly.Msg.extension_servo_write_on_ai_TOOLTIP = "模块设置位于指定引脚的舵机转动至指定角度";
+// 电机
+Blockly.Msg.x_motor_set_motor_ai = "电机驱动初始化设置";
+Blockly.Msg.x_motor_set_motor_turn_ai = "设定电机";
+Blockly.Msg.x_motor_set_motor_speed_ai = "以速度";
+Blockly.Msg.x_motor_exec_ai = "(0~255)进行";
+Blockly.Msg.x_motor_cw_ai = "顺时针";
+Blockly.Msg.x_motor_acw_ai = "逆时针";
+Blockly.Msg.x_motor_set_motor_turns_ai = "转动";
+Blockly.Msg.ai_motor_setup_TOOLTIP = "电机驱动初始化";
+Blockly.Msg.ai_motor_run_TOOLTIP = "设置电机以指定速度进行指定方向的转动";
+
+
+// 屏幕
+Blockly.Msg.image_process_lcd_init = "LCD 屏幕初始化";
+Blockly.Msg.image_process_lcd_direction = "设置屏幕方向";
+Blockly.Msg.image_process_lcd_landscape_screen = "横屏";
+Blockly.Msg.image_process_lcd_vertical_screen = "竖屏";
+Blockly.Msg.image_process_text_let_canvas = "将图像";
+Blockly.Msg.image_process_text_image_canvas = "图片化";
+Blockly.Msg.image_process_text_let_canvas_filled_with_color = "铺满颜色";
+Blockly.Msg.image_process_text_on_canvas = "显示图像";
+Blockly.Msg.image_process_text_on_draw = "显示";
+Blockly.Msg.image_process_draw_line = "绘制直线";
+Blockly.Msg.image_text_on_draw = "绘制";
+Blockly.Msg.image_process_text_set_canvas_setup = "设置画布";
+Blockly.Msg.image_process_draw_qrcode = "二维码";
+Blockly.Msg.image_process_draw_qr_code_size = "二维码大小";
+Blockly.Msg.image_lcd_set_font = "设置字体为";
+Blockly.Msg.image_process_create_blank_canvas = "创建空白画布";
+Blockly.Msg.image_process_show_canvas = "显示画布";
+Blockly.Msg.image_process_clear_canvas_1 = "清除画布";
+Blockly.Msg.image_process_clear_canvas_2 = "清除所有内容";
+Blockly.Msg.image_process_set_lcd_rotation = "旋转至";
+Blockly.Msg.image_process_text_start_coord = "坐标:";
+Blockly.Msg.image_process_text_size = "尺寸:";
+Blockly.Msg.image_process_text_color = "颜色:";
+Blockly.Msg.image_process_background_color = "背景颜色:";
+Blockly.Msg.image_process_text_thick = "厚度:";
+Blockly.Msg.image_process_text_radius = "半径:";
+Blockly.Msg.image_process_text_content = "内容";
+Blockly.Msg.image_process_draw_text_font_size = "文本大小:(由 1 至 3 之间的整数)";
+Blockly.Msg.image_process_draw_rectangle_text = "矩形";
+Blockly.Msg.image_process_draw_circle_text = "圆形";
+Blockly.Msg.image_process_draw_circle_text_start = "圆心坐标";
+Blockly.Msg.image_process_draw_sensor_image_path = "设置图像源:";
+Blockly.Msg.OLCD_COORDINATE = "起始点坐标";
+
+Blockly.Msg.image_process_text_filled = "实心";
+Blockly.Msg.image_process_text_stroked = "空心";
+Blockly.Msg.ai_lcd_screeninit_TOOLTIP = "LCD屏幕初始化";
+Blockly.Msg.ai_lcd_rotation_TOOLTIP = "将LCD屏幕方向旋转指定的角度";
+Blockly.Msg.ai_lcd_filp_TOOLTIP = "是否将LCD屏幕进行镜面翻转";
+Blockly.Msg.ai_lcd_screen_TOOLTIP = "将LCD屏幕填充颜色为%1";
+Blockly.Msg.ai_lcd_fill_screen_with_rgb_TOOLTIP = "将LCD屏幕填充颜色为指定rgb值";
+Blockly.Msg.ai_lcd_clear_TOOLTIP = "清除屏幕";
+Blockly.Msg.ai_lcd_XY_TOOLTIP = "返回指定的x和y";
+Blockly.Msg.ai_lcd_WH_TOOLTIP = "返回指定的宽与高";
+Blockly.Msg.ai_lcd_createnonecarvas_TOOLTIP = "创建指定尺寸的空白画布";
+Blockly.Msg.ai_lcd_fillcanvas_TOOLTIP = "将画布铺满指定的颜色";
+Blockly.Msg.ai_lcd_createcarvas_TOOLTIP = "创建图像画布";
+Blockly.Msg.ai_lcd_showcarvas_set_cord_TOOLTIP = "设置画布的起始点坐标";
+Blockly.Msg.ai_lcd_textcarvas_TOOLTIP = "在画布上绘制文本";
+Blockly.Msg.ai_lcd_characterscarvas_TOOLTIP = "在画布上绘制汉字字符";
+Blockly.Msg.ai_lcd_linecarvas_TOOLTIP = "在画布上绘制直线";
+Blockly.Msg.ai_lcd_ractanglecarvas_TOOLTIP = "在画布上绘制%1矩形";
+Blockly.Msg.ai_lcd_drawcirclecarvas_TOOLTIP = "在画布上绘制%1圆形";
+Blockly.Msg.ai_lcd_draw_cross_sign_TOOLTIP = "在画布上绘制十字标";
+Blockly.Msg.ai_lcd_draw_arrow_sign_TOOLTIP = "在画布上绘制箭头";
+Blockly.Msg.ai_lcd_draw_image_on_canvas_TOOLTIP = "在画布上绘制图片";
+Blockly.Msg.ai_lcd_draw_sensor_image_on_canvas_TOOLTIP = "在画布上绘制相机捕捉的图像";
+Blockly.Msg.ai_lcd_showcarvas_set_display_TOOLTIP = "显示画布";
+Blockly.Msg.ai_lcd_clearcanvas_TOOLTIP = "清除画布中的所有内容";
+Blockly.Msg.ai_lcd_qrcode_TOOLTIP = "在画布上绘制二维码";
+
+
+
+// 图像处理
+Blockly.Msg.read_img_path_to = "读取图片文件自";
+Blockly.Msg.take_the_picture = "将图片";
+Blockly.Msg.save_img_path_to = "保存图片至";
+Blockly.Msg.display_draw_vertical = "垂直"
+Blockly.Msg.display_draw_horizontal = "水平";
+Blockly.Msg.MAIXDUINO_DISPLAY_ORIENTATION_ROTATE = "翻转";
+Blockly.Msg.MAIXDUINO_DISPLAY_ORIENTATION_ROTATE_title = "将图像进行 %1 翻转";
+Blockly.Msg.image_process_rotate = "将图像旋转";
+Blockly.Msg.image_process_rotate_angle = "度";
+Blockly.Msg.image_process_imgcut_cutting = "将图像进行裁剪处理";
+Blockly.Msg.image_process_imgcut_start_coord = "裁剪起始坐标:";
+Blockly.Msg.image_process_imgcut_size = "裁剪尺寸:";
+Blockly.Msg.image_process_img_resize = "将图像进行缩放至";
+Blockly.Msg.ai_vision_detection_color_threshold_set = "获取用于颜色追踪的默认颜色:";
+Blockly.Msg.ai_vision_get_threshold_default_TOOLTIP = "设置获取用于颜色追踪的默认颜色为%1";
+Blockly.Msg.ai_vision_detection_color_threshold_set_black = "黑色";
+Blockly.Msg.ai_vision_detection_color_threshold_set_white = "白色";
+Blockly.Msg.ai_vision_detection_color_threshold_set_red = "亮红色";
+Blockly.Msg.ai_vision_detection_color_threshold_set_green = "绿色";
+Blockly.Msg.ai_vision_detection_color_threshold_set_blue = "浅蓝色";
+Blockly.Msg.ai_vision_detection_color_threshold_set_orange = "橙色";
+Blockly.Msg.image_process_find_blobs = "寻找指定颜色的块";
+Blockly.Msg.image_get_find_blobs_result = "获取指定颜色的识别结果";
+Blockly.Msg.ai_vision_lane_tracking_setup_threshold = "设置追踪的颜色";
+Blockly.Msg.ai_vision_find_blobs_start_coord = "设置检测区域的起始坐标:";
+Blockly.Msg.ai_vision_find_blobs_size = "设置检测区域的尺寸:";
+Blockly.Msg.image_process_find_lines = "寻找指定颜色的线:";
+Blockly.Msg.image_get_find_lines_result = "获取寻找到线的识别结果";
+Blockly.Msg.ai_vision_lane_tracking_setup_left = "设置左侧识别区域:";
+Blockly.Msg.ai_vision_lane_tracking_setup_Right = "设置右侧识别区域:";
+Blockly.Msg.ai_vision_lane_tracking_setup_axis = "设置中心线位置:";
+Blockly.Msg.image_process_find_qrcodes = "获取图像二维码检测结果";
+Blockly.Msg.image_process_get_qrcodes_result = "获取二维码的";
+Blockly.Msg.image_process_find_barcodes = "获取图像条形码检测结果";
+Blockly.Msg.image_process_get_barcodes_result = "获取条形码的";
+Blockly.Msg.ai_vision_canvas_area_tuple = "创建区域元组";
+Blockly.Msg.ai_vision_pattern_detection_content = "源文本";
+Blockly.Msg.ai_vision_pattern_detection_x = "边界框X轴坐标";
+Blockly.Msg.ai_vision_pattern_detection_y = "边界框Y轴坐标";
+Blockly.Msg.ai_vision_pattern_detection_w = "边界框宽度";
+Blockly.Msg.ai_vision_pattern_detection_h = "边界框高度";
+Blockly.Msg.ai_vision_qrcode_get_info_TOOLTIP = "获取二维码的%1";
+Blockly.Msg.ai_vision_barcode_get_info_TOOLTIP = "获取条形码的%1";
+Blockly.Msg.image_process_find_apriltag = "获取图像AprilTag检测结果";
+Blockly.Msg.ai_vision_apriltag_get_info = "获取AprilTag的";
+Blockly.Msg.ai_vision_apriltag_get_info_TOOLTIP = "获取AprilTag的%1";
+
+
+
+
+// 系统功能
+Blockly.Msg.system_poweroff = "关机";
+Blockly.Msg.system_restart = "重启系统";
+Blockly.Msg.system_gc = "启动内存回收";
+Blockly.Msg.system_create_file = "创建文件";
+Blockly.Msg.system_create_file_name = "文件名:";
+Blockly.Msg.system_create_file_path = "文件路径为:";
+Blockly.Msg.system_run_file = "运行程序文件";
+Blockly.Msg.system_run_file_name = "文件名:";
+
+// AI 
+Blockly.Msg.ChatGpt_get_problem_result = "返回提问结果";
+Blockly.Msg.ChatGpt_ai_agent_chat_set_appID = "设置AI智能体apiKey";
+Blockly.Msg.ChatGpt_ai_agent_chat_result = "返回AI智能体结果";
+Blockly.Msg.ai_set_ai_agent_title = "设置智能体apikey和问题,并返回结果";
+Blockly.Msg.ChatGpt_set_problem_content = "设置文字提问内容";
+
+
+// IOT
+Blockly.Msg.set_weather_city = "设置获取天气城市";
+Blockly.Msg.beijing = "北京";
+Blockly.Msg.shanghai = "上海";
+Blockly.Msg.guangzhou = "广州";
+Blockly.Msg.shenzhen = "深圳";
+Blockly.Msg.tianjin= "天津";
+Blockly.Msg.HongKong = "香港"
+Blockly.Msg.weather_resulet= "天气结果"
+Blockly.Msg.weather_condition = "天气状况"
+Blockly.Msg.windDir = "风向"
+Blockly.Msg.windScale = "风向等级"
+Blockly.Msg.windSpeed = "风速"
+Blockly.Msg.image_process_humidity = "湿度";
+Blockly.Msg.image_process_temperature = "温度";
+// IFTTT
+Blockly.Msg.iotservice_ifttt_send_title = "发送数据到 IFTTT Webhooks 事件";
+Blockly.Msg.iotservice_ifttt_send_webhook = "Webhooks API Key:";
+Blockly.Msg.iotservice_ifttt_send_eventname = "事件名称:";
+Blockly.Msg.iotservice_ifttt_send_1 = "数据 1:";
+Blockly.Msg.iotservice_ifttt_send_2 = "数据 2:";
+Blockly.Msg.iotservice_ifttt_send_3 = "数据 3:";
+Blockly.Msg.iotservice_ifttt_trigger_title = "触发 IFTTT 事件";
+Blockly.Msg.iotservice_ifttt_trigger_webhook = "Webhook API Key:";
+Blockly.Msg.iotservice_ifttt_trigger_eventname = "事件名称:";
+Blockly.Msg.Esp32_Main_Controller_Ifttt_Touched_TOOLTIP= "触发指定的IFTTT事件";
+Blockly.Msg.Esp32_Main_Controller_Ifttt_Send_Data_TOOLTIP= "发送数据到IFTTT Webhooks事件";
+// ThingSpeak
+Blockly.Msg.iotservice_thingspeak_send_title = "发送数据至 ThingSpeak 频道 (Channel)";
+Blockly.Msg.iotservice_thingspeak_send_api_set = "设置频道 API Key:";
+Blockly.Msg.iotservice_thingspeak_send_title = "发送数据至 ThingSpeak 频道";
+Blockly.Msg.iotservice_thingspeak_send_api = "频道 API Key:";
+Blockly.Msg.iotservice_thingspeak_query_title = "查找 ThingSpeak 指定频道的数据";
+Blockly.Msg.iotservice_thingspeak_query_api = "频道 API Key:";
+Blockly.Msg.iotservice_thingspeak_channel_id = "频道 ID:";
+Blockly.Msg.iotservice_thingspeak_read_total = "获取 ThingSpeak 频道中的数据总量";
+Blockly.Msg.iotservice_thingspeak_get_title = "获取 ThingSpeak 频道中第";
+Blockly.Msg.iotservice_thingspeaK_get_field = "条数据的 Field";
+Blockly.Msg.iotservice_thingspeaK_get_value = "的数值";
+Blockly.Msg.Iot_Service_Thingspeak_TOOLTIP= "发送数据至指定ThingSpeak频道";
+Blockly.Msg.Iot_Service_Thingspeak_Read_TOOLTIP= "查找ThingSpeak指定频道的数据";
+Blockly.Msg.Iot_Service_Thingspeak_Read_Total_TOOLTIP= "获取ThingSpeak频道中的数据总量";
+Blockly.Msg.Iot_Service_Thingspeak_Read_Specific_TOOLTIP= "获取ThingSpeak频道中指定数据的指定Field的数值";
+
+// cloud
+Blockly.Msg.Iot_Service_Cococloud_TOOLTIP= "发送数据至CocoCloud指定事件";
+Blockly.Msg.Iot_Service_Cococloud_Read_TOOLTIP= "获取CocoCloud指定事件中的数据";
+Blockly.Msg.Iot_Service_Cococloud_Read_Data_TOOLTIP= "获取CocoCloud事件中指定属性的数据";
+
+
+// 发送邮件
+Blockly.Msg.send_email_title = "发送邮件";
+Blockly.Msg.send_email_to = "发送到";
+Blockly.Msg.send_email_content = "邮件内容:";
+Blockly.Msg.send_email_title_title = "发送邮件到指定邮箱";
+
+// Flask 
+Blockly.Msg.wifi_web_http_server_setup = "HTTP 服务器初始化";
+Blockly.Msg.wifi_web_http_server_route_setting_title = "HTTP 服务器设置访问路径";
+Blockly.Msg.wifi_web_http_server_route_setting_path = "当路径:";
+Blockly.Msg.wifi_web_http_server_route_setting_being_requested = "被请求时";
+Blockly.Msg.wifi_web_http_server_route_setting_property = "设置请求属性为:";
+Blockly.Msg.wifi_web_http_server_route_setting_get = "GET 请求";
+Blockly.Msg.wifi_web_http_server_route_setting_post = "POST 请求";
+Blockly.Msg.wifi_web_http_server_route_setting_do = "运行";
+Blockly.Msg.wifi_web_http_server_respond_title = "HTTP 服务器设置响应内容";
+Blockly.Msg.wifi_web_http_server_respond_type = "设置返回数据类型:";
+Blockly.Msg.wifi_web_http_server_respond_text = "纯文本";
+Blockly.Msg.wifi_web_http_server_respond_json = "字典类型数据 (JSON)";
+Blockly.Msg.wifi_web_http_server_respond_html = "网页 (HTML 代码)";
+Blockly.Msg.wifi_web_http_server_respond_exec = "响应";
+Blockly.Msg.wifi_web_http_server_get_title = "HTTP 服务器获取从客户端收到的数据,类型为";
+Blockly.Msg.wifi_web_http_server_get_as_json = "字典类型数据 (JSON)";
+Blockly.Msg.wifi_web_http_server_get_as_text = "文本";
+Blockly.Msg.Esp32_Network_Http_Server_Route_TOOLTIP= "當指定路徑被請求時,設定請求屬性爲%1請求,並執行操作";
+Blockly.Msg.Esp32_Network_Http_Server_Route_Respond_TOOLTIP= "HTTP伺服器設置響應內容,並設置返回數據類型爲%1";
+Blockly.Msg.Esp32_Network_Http_Server_Get_Data_TOOLTIP= "HTTP伺服器獲取從客戶端收到的數據,類型爲%1";
+Blockly.Msg.internet_http_get_title = "发送 HTTP GET 请求";
+Blockly.Msg.internet_http_get_url = "设置目标网址:";
+Blockly.Msg.internet_http_post_title = "发送 HTTP POST 请求";
+Blockly.Msg.internet_http_post_url = "设置目标网址:";
+Blockly.Msg.internet_http_post_json = "提交数据 (JSON):";
+Blockly.Msg.Esp32_Network_Http_Get_TOOLTIP= "發送http get請求";
+Blockly.Msg.Esp32_Network_Http_Post_TOOLTIP= "發送http post請求";
+Blockly.Msg.CocoRobo_get_TOOLTIP= "獲取HTTP響應內容的%1";
+Blockly.Msg.internet_response_http_content_title = "获取 HTTP 响应内容的";
+Blockly.Msg.internet_response_text = "文本";
+Blockly.Msg.internet_response_content = "内容";
+Blockly.Msg.internet_response_status = "状态码";
+Blockly.Msg.internet_response_json = "JSON数据";
+Blockly.Msg.internet_response_encode = "编码";
+Blockly.Msg.internet_response_reason = "原因短语";
+
 export default Blockly.Msg

+ 1 - 0
src/Blockly/msg/zh-hant.js

@@ -17,6 +17,7 @@ Blockly.Msg["catOutput"] = "輸入/輸出";
 Blockly.Msg["catFiles"] = "變量";
 Blockly.Msg["catTime"] = "時間";
 Blockly.Msg["catSerial"] = "串口";
+Blockly.Msg["catBasicFunctions"] = "基本功能";
 
 
 

+ 1 - 0
src/asstes/css/content.css

@@ -3,6 +3,7 @@
     justify-content: space-between;
     align-items: center;
     height: 60px;
+    min-width: 400px;
 }
 
 .header-text {

+ 1 - 1
src/components/deviceOperations/AdbHeader.tsx

@@ -76,7 +76,7 @@ const AdbHeader: React.FC = () => {
             <span>设备</span>
             <Select defaultValue="1" style={{ width: 100, margin: '0 5px' }} onChange={switchConnectType}>
                 <Select.Option value="1">有线连接</Select.Option>
-                {/* <Select.Option value="2">无线连接</Select.Option> */}
+                <Select.Option value="2">无线连接</Select.Option>
             </Select>
             {!currentBackend && <img style={imgStyle} onClick={()=>setAdbVisible(true)} src={disConnectImg} alt="" />}
             {currentBackend && <img style={imgStyle} src={connectImg} alt="" />}

+ 2 - 1
src/components/deviceOperations/ConnectDevice.tsx

@@ -283,7 +283,8 @@ const ConnectDevice: React.FC<DeviceConnectionProps> = (props) => {
           连接
         </Button>
       ) : (
-        <></>
+        <>
+        </>
       )}
     </>
   );

+ 0 - 1
src/components/fileManager/printData.tsx

@@ -15,7 +15,6 @@ const PrintData: React.FC = () => {
         const container = printDataRef.current;
         if (container) {
             container.scrollTop = container.scrollHeight;
-            console.log("scrollToBottom",container.scrollTop,container.scrollHeight);
         }
     }, []);
     return (

+ 51 - 21
src/components/terminal/RunCommandShell.tsx

@@ -61,13 +61,13 @@ const RunCommandShell: React.FC = () => {
   );
   const dispatch = useDispatch();
   useEffect(() => {
-    
+
   }, [currentDevice]);
   const handleOnSearch = async () => {
     console.log("开始上传文件", pythonCode);
     try {
-      // await uploadFile()
-      // await uploadFileOut();
+      await uploadFile()
+      await uploadFileOut();
       await runCode();
     } catch (e: any) {
       console.log("上传错误:", e);
@@ -121,7 +121,40 @@ os.close(1)
 os.close(2)
 
 try:
-    source_code = r'''${pythonCode}
+    source_code = r'''import time
+from maix import *
+import gc
+import os,sys
+import sys
+sys.path.append('/root/')
+from CocoPi import BUTTON
+from CocoPi import stm8s
+from CocoPi import multiFuncGpio
+from CocoPi import singleRgb
+from CocoPi import LED
+
+gc.enable()
+gc.collect()
+iic_slaver=stm8s()
+iic_slaver.clear()
+PIXEL_LED1= multiFuncGpio(0,0)
+PIXEL_LED2= multiFuncGpio(1,0)
+PIXEL_LED1.pixelInit_()
+PIXEL_LED2.pixelInit_()
+time.sleep(0.1)
+L1=singleRgb()
+L1.setColor(0,0,0)
+L1.show()
+time.sleep(0.2)
+L2=LED()
+L2.out(0)
+del iic_slaver
+del PIXEL_LED1
+del PIXEL_LED2
+del L1
+del L2
+
+${pythonCode}
 '''
     exec(source_code)
 except Exception as e:
@@ -206,23 +239,23 @@ loop.close()
   const runCode = async () => {
     if (command) {
       command.kill().then(() => {
-        window.device?.subprocess.shell(`(echo '' > /root/output.log ; touch /tmp/disable) && python -u /root/out.py;`).then(e => {
-          setCommand(e);
-          serverPrint(e);
-        }).catch(err => {
-          console.log(err);
-        })
+        runCommand()
       })
     } else {
-      window.device?.subprocess.shell(`(echo '' > /root/output.log ; touch /tmp/disable) && python -u /root/out.py;`).then(e => {
-        setCommand(e);
-        serverPrint(e);
-      }).catch(err => {
-        console.log(err);
-      })
+      runCommand()
     }
   }
 
+  // 运行命令
+  const runCommand = async () => {
+    window.device?.subprocess.shell(`(echo '' > /root/output.log ; touch /tmp/disable) && python -u /root/out.py;`).then(e => {
+      setCommand(e);
+      serverPrint(e);
+    }).catch(err => {
+      console.log(err);
+    })
+  };
+
   const serverPrint = async (e: any) => {
     let _socketAbortController = new AbortController()
     setRunState(true);
@@ -231,11 +264,8 @@ loop.close()
       write: (chunk) => {
         // Decode the chunk to obtain the output text
         const outputText = new TextDecoder().decode(chunk);
-
-        if (outputText.length > 2) {
-          data = `<p>${outputText}</p>` + data;
-          dispatch(updatePrintData(data));
-        }
+        data = data +`<p>${outputText}</p>`;
+        dispatch(updatePrintData(data));
 
         // this.output.push(outputText);
 

+ 11 - 8
src/components/terminal/Terminal.tsx

@@ -64,6 +64,7 @@ const Terminal: React.FC<TerminalProps> = (props) => {
   const [api, contextHolder] = notification.useNotification();
 
   const currentDevice = useSelector((state: AppState) => state.currentDevice);
+  const connectType = useSelector((state: AppState) => state.connectType);
   const currentTerminalCommand = useSelector(
     (state: AppState) => state.currentTerminalCommand,
   );
@@ -143,6 +144,7 @@ const Terminal: React.FC<TerminalProps> = (props) => {
 
   // handles the terminal connection
   useEffect(() => {
+    console.log("connectType :",connectType)
     if (!terminal) {
       return;
     }
@@ -155,6 +157,7 @@ const Terminal: React.FC<TerminalProps> = (props) => {
     if (!terminal.socket) {
       currentDevice.subprocess.shell().then(
         (shell) => {
+          console.log("currentDevice", shell);
           terminal!.socket = shell;
         },
         (e) => {
@@ -166,18 +169,18 @@ const Terminal: React.FC<TerminalProps> = (props) => {
       terminal.setDispatch(dispatch);
       terminal.fit();
     }
-  }, [terminal, currentDevice]);
+  }, [terminal, currentDevice,connectType]);
   return (
     <>
       {contextHolder}
       {props.needCardWrapper ? (
-          <div
-            ref={handleContainerRefTerminal}
-            style={{
-              height: props.height,
-              width: props.width,
-            }}
-          />
+        <div
+          ref={handleContainerRefTerminal}
+          style={{
+            height: props.height,
+            width: props.width,
+          }}
+        />
       ) : (
         <div
           ref={handleContainerRefTerminal}

+ 24 - 0
src/components/webssh/sshConnect.tsx

@@ -0,0 +1,24 @@
+import axios from "axios";
+import React, { useEffect, useRef } from "react";
+
+const sshConfig = {
+    host: '192.168.0.176',
+    port: 22,
+    username: 'root',
+    password: 'root'
+    // 密码通过后端服务安全传输
+};
+const SshConnect: React.FC = () => {
+    useEffect(() => {
+        getShell()
+    }, [])
+    const getShell = () => { 
+    }
+    return (
+        <div >
+            {/* <iframe style={{width:"100%",height:"100%"}} src="http://192.168.0.176:8888/" ></iframe> */}
+        </div>
+    )
+}
+
+export default SshConnect;

+ 43 - 8
src/index.css

@@ -57,33 +57,68 @@ code {
   zoom: 1;
 }
 
-.ant-dropdown .ant-dropdown-menu-item{
+.ant-dropdown .ant-dropdown-menu-item {
   padding: 0 !important;
 }
 
-.ant-dropdown-content-style{
+.ant-dropdown-content-style {
   display: block;
-  padding: 10px 12px; 
+  padding: 10px 12px;
   color: #26a69a !important;
 }
 
-.ant-modal-header .ant-modal-title{
+.ant-modal-header .ant-modal-title {
   font-size: 36px;
   font-weight: 400;
 }
 
-.run-reboot{
+.run-reboot {
   display: flex;
   justify-content: space-between;
 }
-.run-reboot button{
+
+.run-reboot button {
   width: 19%;
 }
 
-.ant-modal-content{
+.ant-modal-content {
   height: 650px;
 }
 
-.ant-modal-body{
+.ant-modal-body {
   height: calc(100% - 110px);
 }
+
+@media (max-width: 1620px) {
+  .content-right-header-title .header-text {
+    max-width: initial;
+    width: 80px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+}
+
+@media (max-width: 1150px) {
+  .header-right .header-right-text {
+    padding: 0;
+  }
+
+  .header-right-text span {
+    padding: 0 !important;
+  }
+
+  .content-right-header-title .header-text {
+    max-width: initial;
+    width: 50px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+}
+
+@media (max-width: 1150px) {
+  .header-right-text span {
+    display: none !important;
+  }
+}

+ 5 - 3
src/pages/Home.tsx

@@ -62,6 +62,7 @@ import ContentRightHeader from "../components/contentRightHeader";
 import PrintData from "../components/fileManager/printData";
 import UpdateLog from "../components/footer/updateLog";
 import AdbHeader from "../components/deviceOperations/AdbHeader";
+import WebSSH from "../components/webssh/sshConnect";
 
 const { Header, Content, Footer } = Layout;
 const { Text } = Typography;
@@ -220,16 +221,16 @@ const Home: React.FC = () => {
               <Col span={17}>
                 <BlocklyHome />
               </Col>
-              <Col span={7} style={{width: "100%",paddingLeft:0}}>
+              <Col span={7} style={{width: "100%",paddingLeft:0,height: "100%" }}>
                 <Row style={{ height: "calc(100% - 175px)" }}
                   gutter={20}>
-                  <Col span={24}>
+                  <Col span={24} style={{ height: "100%" }}>
                     <Row>
                       <Col span={24}>
                         <ContentRightHeader hangdEditable={editable} handleChildValue={getChildValue} />
                       </Col>
                     </Row>
-                    <Row style={{ height: "calc(100% - 60px)" }}>
+                    <Row style={{ height: "calc(100% - 60px)",overflowY: "auto" }}>
                       {contentRightTopShow === 0 ? <Col span={24} style={{ height: "100%" }}><PrintData /></Col> : ""}
                       {contentRightTopShow === 1 ? <Col span={24} style={{ height: "100%" }}> 
                         <FileManagerReadFile setEditable={editableValue} />
@@ -282,6 +283,7 @@ const Home: React.FC = () => {
             <Col span={8}>
               可可乐博(深圳)科技有线公司 © {year} 版权所有
             </Col>
+            
             <Col span={16} style={footerRightStyle}>
               <UpdateLog />
               <span>CocoBlockly Pi</span>

+ 24 - 0
src/utils/blocklyFunction.ts

@@ -0,0 +1,24 @@
+import * as Blockly from 'blockly';
+
+export function getBlocksByTypeName(typeName: string) {
+    let blocks: any = Blockly.Xml.workspaceToDom(window.blockly).getElementsByTagName('block');
+    let filtersBlocks: any = []
+    for (let i = 0; i < blocks.length; i++) {
+        if (blocks[i].getAttribute("type") === typeName) {
+            filtersBlocks.push(blocks[i]);
+        }
+    }
+    return filtersBlocks;
+}
+
+export function getAllGobalVariables(block: any) {
+    let allGobalList: any = [];
+    try {
+        let blocksList = block.workspace.getAllBlocks()[0].workspace.variableMap.variableMap
+        blocksList.get("").map((item: any) => { allGobalList.push(item.name) })
+    }
+    catch (e) {
+        return ""
+    }
+    return allGobalList.join(",")
+}