chao 2 months ago
parent
commit
5dc2eb8517
42 changed files with 7523 additions and 1204 deletions
  1. 15 5
      package-lock.json
  2. 3 1
      package.json
  3. 1010 138
      src/blockly/blocklyXml.js
  4. 1 1
      src/blockly/blocks/BlocklyFunction.js
  5. 1035 0
      src/blockly/blocks/Iot.js
  6. 665 0
      src/blockly/blocks/MediaProcessing.js
  7. 801 0
      src/blockly/blocks/ai.js
  8. 1376 628
      src/blockly/blocks/basic.js
  9. 93 0
      src/blockly/blocks/camera.js
  10. 75 0
      src/blockly/blocks/customblocks.js
  11. 3 9
      src/blockly/blocks/dictionary.js
  12. 1 3
      src/blockly/blocks/file.js
  13. 27 15
      src/blockly/blocks/index.js
  14. 3 8
      src/blockly/blocks/list.js
  15. 609 10
      src/blockly/blocks/logic.js
  16. 157 164
      src/blockly/blocks/math.js
  17. 174 0
      src/blockly/blocks/microphone.js
  18. 1 3
      src/blockly/blocks/output.js
  19. 1 4
      src/blockly/blocks/procedures.js
  20. 282 0
      src/blockly/blocks/serial.js
  21. 2 7
      src/blockly/blocks/set.js
  22. 114 0
      src/blockly/blocks/system.js
  23. 34 22
      src/blockly/blocks/text.js
  24. 155 0
      src/blockly/blocks/time.js
  25. 1 7
      src/blockly/blocks/tuples.js
  26. 18 54
      src/blockly/blocks/variables.js
  27. 374 17
      src/blockly/msg/zh-hans.js
  28. 73 72
      src/blockly/pythonCode/basicCode.js
  29. 1 1
      src/blockly/pythonCode/file.js
  30. 35 0
      src/blockly/pythonCode/generator.js
  31. 15 13
      src/blockly/pythonCode/index.js
  32. 1 0
      src/blockly/pythonCode/list.js
  33. 15 15
      src/blockly/pythonCode/logic.js
  34. 1 1
      src/blockly/pythonCode/output.js
  35. 1 2
      src/blockly/pythonCode/python.js
  36. 129 0
      src/blockly/pythonCode/serial.js
  37. 0 1
      src/blockly/pythonCode/text.js
  38. 127 0
      src/blockly/pythonCode/time.js
  39. 66 0
      src/components/BlocklyComponent.css
  40. 4 2
      src/components/BlocklyComponent.vue
  41. 1 1
      src/components/device/device.vue
  42. 24 0
      src/utils/blocklyFunction.tsx

+ 15 - 5
package-lock.json

@@ -33,7 +33,9 @@
         "vue-codemirror": "^6.1.1",
         "vue-i18n": "^11.0.0-rc.1",
         "vue-router": "^4.2.5",
-        "xterm-addon-fit": "^0.8.0"
+        "xterm": "^5.3.0",
+        "xterm-addon-fit": "^0.8.0",
+        "xterm-addon-web-links": "^0.9.0"
       },
       "devDependencies": {
         "monaco-editor-webpack-plugin": "^6.0.0"
@@ -3862,19 +3864,27 @@
     },
     "node_modules/xterm": {
       "version": "5.3.0",
-      "resolved": "https://mirrors.cloud.tencent.com/npm/xterm/-/xterm-5.3.0.tgz",
+      "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.",
-      "peer": true
+      "deprecated": "This package is now deprecated. Move to @xterm/xterm instead."
     },
     "node_modules/xterm-addon-fit": {
       "version": "0.8.0",
-      "resolved": "https://mirrors.cloud.tencent.com/npm/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz",
+      "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.8.0.tgz",
       "integrity": "sha512-yj3Np7XlvxxhYF/EJ7p3KHaMt6OdwQ+HDu573Vx1lRXsVxOcnVJs51RgjZOouIZOczTsskaS+CpXspK81/DLqw==",
       "deprecated": "This package is now deprecated. Move to @xterm/addon-fit instead.",
       "peerDependencies": {
         "xterm": "^5.0.0"
       }
+    },
+    "node_modules/xterm-addon-web-links": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/xterm-addon-web-links/-/xterm-addon-web-links-0.9.0.tgz",
+      "integrity": "sha512-LIzi4jBbPlrKMZF3ihoyqayWyTXAwGfu4yprz1aK2p71e9UKXN6RRzVONR0L+Zd+Ik5tPVI9bwp9e8fDTQh49Q==",
+      "deprecated": "This package is now deprecated. Move to @xterm/addon-web-links instead.",
+      "peerDependencies": {
+        "xterm": "^5.0.0"
+      }
     }
   }
 }

+ 3 - 1
package.json

@@ -34,7 +34,9 @@
     "vue-codemirror": "^6.1.1",
     "vue-i18n": "^11.0.0-rc.1",
     "vue-router": "^4.2.5",
-    "xterm-addon-fit": "^0.8.0"
+    "xterm": "^5.3.0",
+    "xterm-addon-fit": "^0.8.0",
+    "xterm-addon-web-links": "^0.9.0"
   },
   "devDependencies": {
     "monaco-editor-webpack-plugin": "^6.0.0"

+ 1010 - 138
src/blockly/blocklyXml.js

@@ -1,7 +1,7 @@
 
 export default {
   xml: `<xml  style="height: 100%">
-    <category id="catLogic" name="Logic" colour="#4c97ff">
+<category id="catLogic" name="Logic" colour="#4c97ff">
          <block type="controls_if"></block>
          <block type="logic_compare"></block>
          <block type="logic_operation"></block>
@@ -45,7 +45,6 @@ export default {
             </block> 
             <block type="controls_forEach"></block> 
             <block type="controls_flow_statements"></block> 
-
       </category>
       <category id="catMath" name="Math" colour="#5472ea"> 
         <block type="math_number" gap="32"></block> 
@@ -220,8 +219,8 @@ export default {
         <block type="text"><field name="TEXT"></field></block>
         <block type="text_join"><mutation items="1"></mutation></block>
         <block type="text_join"></block>
-        <block type="text_split_string_by_delimiter">
-        </block>
+        <block type="text_split_string_by_delimiter"></block>
+  
         <block type="text_format">
           <value name="FORMAT">
             <shadow type="text"><field name="TEXT">Value: %.2f</field></shadow>
@@ -244,174 +243,190 @@ export default {
           <value name="CONTENT">
             <block type="tuple_create_with_items_insert">
               <mutation items="1"></mutation>
-                <value name="ADD0">
-                  <block type="math_number">
-                    <field name="NUM">3.1415926</field>
-                  </block>
-                </value>
+              <value name="ADD0">
+                <block type="math_number">
+                  <field name="NUM">3.1415926</field>
+                </block>
+              </value>
             </block>
           </value>
         </block>
         <block type="CocoRobo_text_ESC"></block>
         <block type="text_append_text">
-          <value name="text_abc"><shadow type="text"><field name="TEXT">abc</field></shadow></value>
-          <value name="append_text"><shadow type="text"><field name="TEXT">def</field></shadow></value>
+          <value name="text_abc">
+            <shadow type="text"><field name="TEXT">abc</field></shadow>
+          </value>
+          <value name="append_text">
+            <shadow type="text"><field name="TEXT">def</field></shadow>
+          </value>
         </block>
         <block type="text_is_number">
           <value name="TEXT">
             <shadow type="text">
-              <field name="TEXT"></field>
+            <field name="TEXT"></field>
             </shadow>
           </value>
         </block>
         <block type="text_length">
-          <value name="VALUE">
-            <shadow type="text">
-              <field name="TEXT"></field>
+          <value name="VALUE"> 
+            <shadow type="text"> 
+              <field name="TEXT"></field> 
             </shadow>
           </value>
         </block>
         <block type="text_isEmpty">
           <value name="VALUE">
             <shadow type="text">
-              <field name="TEXT"></field>
+            <field name="TEXT"></field>
             </shadow>
           </value>
         </block>
         <block type="text_indexOf">
-        <value name="VALUE">
-         <shadow type="text">
-        <field name="TEXT">abc</field>
-        </shadow>
-        </value>
-        <value name="FIND">
-         <shadow type="text">
-        <field name="TEXT">b</field>
-         </shadow>
-        </value>
+          <value name="VALUE">
+            <shadow type="text">
+              <field name="TEXT">abc</field>
+            </shadow>
+          </value>
+          <value name="FIND">
+            <shadow type="text">
+              <field name="TEXT">b</field>
+            </shadow>
+          </value>
         </block>
         <block type="text_charAt">
-        <value name="VALUE">
-        <shadow type="text">
-        <field name="TEXT">abc</field>
-         </shadow>
-        </value>
-         </block>
-         <block type="text_getSubstring">
-        <value name="STRING">
-         <shadow type="text">
-        <field name="TEXT">abc</field>
-         </shadow>
-        </value>
-         </block>
-           <block type="text_changeCase">
-        <value name="TEXT">
-          <shadow type="text">
-            <field name="TEXT"></field>
-             </shadow>
-           </value>
-             </block>
-              <block type="text_trim">
-           <value name="TEXT">
-          <shadow type="text">
-            <field name="TEXT"></field>
-             </shadow>
-           </value>
-              </block>
-             <block type="text_to_byte">
-          <value name="TEXT">
-              <shadow type="text">
-                  <field name="TEXT">abc</field>
-              </shadow>
+          <value name="VALUE">
+            <shadow type="text">
+              <field name="TEXT">abc</field>
+            </shadow>
           </value>
-           </block>
-           <block type="CocoRobo_bytes_decode">
-           <value name="bytes_decode"></value>
-        </block>
-        <block type="CocoRobo_ujson_dumps">
-         <value name="data"><shadow type="text_dict"><field name="TEXT">"Age":8</field></shadow></value>
         </block>
-        <block type="CocoRobo_ujson_loads">
-        <value name="data"><shadow type="text"><field name="TEXT">{"Age":8}</field></shadow></value>
-        </block>
-        <block type="CocoRobo_code_annotation">
-        <value name="data"><shadow type="text"><field name="TEXT"></field></shadow></value>
-        </block>
-      </category>
-      <category id="catLists" name="Lists" colour="#40bfe4">
-        <block type="lists_create_with"><mutation items="0"></mutation></block>
-        <block type="lists_create_with"></block>
-        <block type="text_list"><field name="TEXT">0, 0, 0</field></block>
-        <block type="CocoRobo_return_list">
-          <value name="list_name"><block type="variables_get"><field name="VAR">my_list</field></block></value>
-          <value name="list_items"><shadow type="text_list"><field name="TEXT">0, 0, 0</field></shadow></value>
-        </block>
-        <block type="list_order_item">
-          <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-          <value name="list_order_item"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
-        </block>
-        <block type="lists_append">
-          <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-        </block>
-        <block type="list_item_exist">
-         <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-         <value name="list_item"><shadow type="text"><field name="TEXT">cocorobo</field></shadow></value>
-        </block>
-        <block type="lists_extend">
-          <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-          <value name="extend_list"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-        </block>
-        <block type="lists_clear">
-          <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-        </block>
-        <block type="lists_repeat">
-          <value name="NUM">
-            <shadow type="math_number">
-              <field name="NUM">5</field>
+        <block type="text_getSubstring">
+          <value name="STRING">
+            <shadow type="text">
+              <field name="TEXT">abc</field>
             </shadow>
           </value>
         </block>
-        <block type="lists_length"></block>
-        <block type="lists_isEmpty"></block>
-        <block type="list_first_index">
-          <value name="elem"><shadow type="text"><field name="TEXT">cocorobo</field></shadow></value>
-          <value name="my_list"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+        <block type="text_changeCase">
+          <value name="TEXT">
+            <shadow type="text">
+              <field name="TEXT"></field>
+            </shadow>
+          </value>
         </block>
-        <block type="set_list_order_item">
-          <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-          <value name="list_order_item"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
-          <value name="set_value"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
+        <block type="text_trim">
+          <value name="TEXT">
+            <shadow type="text">
+              <field name="TEXT"></field>
+            </shadow>
+          </value>
         </block>
-        <block type="insert_list_order_item">
-          <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-          <value name="list_order_item"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
-          <value name="set_value"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
+        <block type="text_to_byte">
+          <value name="TEXT">
+            <shadow type="text">
+              <field name="TEXT">abc</field>
+            </shadow>
+          </value>
         </block>
-        <block type="parts_of_list">
-          <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
-          <value name="start_item"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
-          <value name="end_item"><shadow type="math_number"><field name="NUM">2</field></shadow></value>
+        <block type="CocoRobo_bytes_decode">
+          <value name="bytes_decode"></value>
         </block>
-        <block type="lists_getIndex">
-          <mutation statement="true" at="true"></mutation>
-          <field name="MODE">REMOVE</field>
-          <field name="WHERE">FROM_START</field>
-          <value name="VALUE">
-            <shadow type="text_list"><field name="TEXT"></field></shadow>
+        <block type="CocoRobo_ujson_dumps">
+          <value name="data">
+            <shadow type="text_dict">
+              <field name="TEXT">"Age":8</field>
+            </shadow>
           </value>
         </block>
-        <block type="lists_getIndex">
-          <mutation statement="false" at="true"></mutation>
-          <field name="MODE">GET_REMOVE</field>
-          <field name="WHERE">FROM_START</field>
-          <value name="VALUE">
-            <shadow type="text_list"><field name="TEXT"></field></shadow>
-          </value>
+        <block type="CocoRobo_ujson_loads">
+          <value name="data">
+            <shadow type="text">
+              <field name="TEXT">{"Age":8}</field>
+            </shadow>
+          </value>  
         </block>
-        <block type="lists_split">
-          <value name="DELIM"><shadow type="text"><field name="TEXT">,</field></shadow></value>
+        <block type="CocoRobo_code_annotation">
+          <value name="data">
+            <shadow type="text">
+              <field name="TEXT"></field>
+            </shadow>
+          </value>
         </block>
-        <block type="lists_sort"></block>
+      </category>
+      <category id="catLists" name="Lists" colour="#40bfe4">
+        <block type="lists_create_with"><mutation items="0"></mutation></block>
+          <block type="lists_create_with"></block>
+          <block type="text_list"><field name="TEXT">0, 0, 0</field></block>
+          <block type="CocoRobo_return_list">
+            <value name="list_name"><block type="variables_get"><field name="VAR">my_list</field></block></value>
+            <value name="list_items"><shadow type="text_list"><field name="TEXT">0, 0, 0</field></shadow></value>
+          </block>
+          <block type="list_order_item">
+            <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+            <value name="list_order_item"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
+          </block>
+          <block type="lists_append">
+            <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+          </block>
+          <block type="list_item_exist">
+          <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+          <value name="list_item"><shadow type="text"><field name="TEXT">cocorobo</field></shadow></value>
+          </block>
+          <block type="lists_extend">
+            <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+            <value name="extend_list"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+          </block>
+          <block type="lists_clear">
+            <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+          </block>
+          <block type="lists_repeat">
+            <value name="NUM">
+              <shadow type="math_number">
+                <field name="NUM">5</field>
+              </shadow>
+            </value>
+          </block>
+          <block type="lists_length"></block>
+          <block type="lists_isEmpty"></block>
+          <block type="list_first_index">
+            <value name="elem"><shadow type="text"><field name="TEXT">cocorobo</field></shadow></value>
+            <value name="my_list"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+          </block>
+          <block type="set_list_order_item">
+            <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+            <value name="list_order_item"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
+            <value name="set_value"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
+          </block>
+          <block type="insert_list_order_item">
+            <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+            <value name="list_order_item"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
+            <value name="set_value"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
+          </block>
+          <block type="parts_of_list">
+            <value name="list_name"><shadow type="text_list"><field name="TEXT"></field></shadow></value>
+            <value name="start_item"><shadow type="math_number"><field name="NUM">0</field></shadow></value>
+            <value name="end_item"><shadow type="math_number"><field name="NUM">2</field></shadow></value>
+          </block>
+          <block type="lists_getIndex">
+            <mutation statement="true" at="true"></mutation>
+            <field name="MODE">REMOVE</field>
+            <field name="WHERE">FROM_START</field>
+            <value name="VALUE">
+              <shadow type="text_list"><field name="TEXT"></field></shadow>
+            </value>
+          </block>
+          <block type="lists_getIndex">
+            <mutation statement="false" at="true"></mutation>
+            <field name="MODE">GET_REMOVE</field>
+            <field name="WHERE">FROM_START</field>
+            <value name="VALUE">
+              <shadow type="text_list"><field name="TEXT"></field></shadow>
+            </value>
+          </block>
+          <block type="lists_split">
+            <value name="DELIM"><shadow type="text"><field name="TEXT">,</field></shadow></value>
+          </block>
+          <block type="lists_sort"></block>
         </category>
         <category id="catDictionary" name="Dictionary" colour="32">
           <block type="text_dict"><field name="TEXT">"Age":8</field></block>
@@ -582,13 +597,870 @@ export default {
             </value>
           </block>
         </category>
-        <category id="catMainBoard" name="Main Board" colour="#3163ed">
-          <category id="time" name="Basics" colour="#d42b03">
+        <category id="catTime" name="Time" colour="#fabe23">
+          <block type="time_delay">
+            <value name="DELAY_TIME_MILI">
+              <block type="math_number">
+                <field name="NUM">1000</field>
+              </block>
+            </value>
+          </block>
+          <block type="time_delayseconds">
+            <value name="DELAY_TIME_MICRO">
+              <block type="math_number">
+                <field name="NUM">1</field>
+              </block>
+            </value>
+          </block>
+          <block type="esp32_get_current_date"></block>
+          <block type="esp32_main_controller_time_timer_init"></block>
+          <block type="esp32_main_controller_time_timer_get_current"></block>
+          <block type="esp32_main_controller_time_timer_clear"></block>
+          <block type="esp32_main_controller_time_period_timer"></block>
+          <block type="esp32_main_controller_time_period_timer_clear"></block>
+        </category>
+        <category id="catSerial" name="SerialComm" colour="#22b845">
+          <block type="serial_comm_print">
+            <value name="serial_comm_input">
+              <shadow type="text">
+                <field name="TEXT">Hello World!</field>
+              </shadow>
+            </value>
+          </block>
+          <block type="serial_write_data_coco">
+            <value name="ADD0">
+              <shadow type="text">
+                <field name="TEXT">Data</field>
+              </shadow>
+            </value>
+          </block>
+          <block type="serial_write_data">
+            <value name="ADD1">
+              <shadow type="text">
+                <field name="TEXT">Data</field>
+              </shadow>
+            </value>
+          </block>
+          <block type="serial_read_data_setup"></block>
+          <block type="serial_read_data_all"></block>
+          <block type="serial_read_data"></block>
+          <block type="serial_read_data_clear"></block>
+          <block type="serial_send_data_to_microbit">
+            <value name="NAME">
+              <shadow type="text">
+                <field name="TEXT">Data</field>
+              </shadow>
+            </value>
+          </block>
+          <block type="serial_send_data_to_control_panel">
+            <value name="NAME">
+              <shadow type="text">
+                <field name="TEXT">Data</field>
+              </shadow>
+            </value>
+          </block>
+        </category>
+        <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="image_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>`
+</xml>`
 }
 
 

+ 1 - 1
src/blockly/blocks/BlocklyFunction.js

@@ -1,4 +1,4 @@
-import Blockly from "blockly";
+import * as Blockly from 'blockly';
 // import googObject from "../goog/googObject";
 const goog = Blockly || {}
 goog.array = {};

+ 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;

+ 1376 - 628
src/blockly/blocks/basic.js

@@ -1,710 +1,1458 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
-import CategoryColors from './define_color'
+/* eslint-disable no-unused-expressions */
+import * as Blockly from 'blockly';
+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.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.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("");
     }
 };
-Blockly.Blocks.CocoRobo_eval = {
+
+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: '计算表达式 %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_off)
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour("#d42b03");
+        this.setTooltip(Blockly.Msg.ai_basic_rgb_set_off);
+        this.setHelpUrl("");
     }
 };
 
-Blockly.controls = {
-    HUE: "#9d64fd"
-}
-Blockly.Blocks.controls_repeat_forever = {
-    init: function () {
-        this.jsonInit({
-            message0: Blockly.Msg.CONTROLS_REPEAT_FOREVER,
-            previousStatement: null,
-            nextStatement: null,
-            colour: Blockly.controls.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: Blockly.controls.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: Blockly.controls.HUE,
-            tooltip: Blockly.Msg.CONTROLS_REPEAT_TOOLTIP,
-            helpUrl: Blockly.Msg.CONTROLS_REPEAT_HELPURL
-        });
-        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)
+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 () {
+        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.Blocks.controls_whileUntil = {
+
+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 () {
-        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(Blockly.controls.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.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: Blockly.controls.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: Blockly.controls.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(Blockly.controls.HUE);
-        this.appendDummyInput().appendField(new Blockly.FieldDropdown(a), "FLOW");
-        this.setPreviousStatement(!0);
-        var b = this;
+        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];
+};
+
+Blockly.Blocks['esp32_main_controller_motion_rotation_measurement'] = {
+    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_rotation_measurement);
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour(SensorsColor);
+        var thisBlock = 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(" ")
+            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.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.controls_if = {
+Blockly.Blocks['esp32_main_controller_motion_tilt_angle'] = {
     init: function () {
-        this.setHelpUrl(Blockly.Msg.CONTROLS_IF_HELPURL);
-        this.setColour(CategoryColors.Logic);
-        this.appendValueInput("IF0").setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);
-        this.appendStatementInput("DO0").appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
-        this.setPreviousStatement(!0);
-        this.setNextStatement(!0);
-        this.setMutator(new Blockly.icons.MutatorIcon(["controls_if_elseif", "controls_if_else"], this));
-        var a = this;
+        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 () {
-            if (a.elseifCount_ || a.elseCount_) {
-                if (!a.elseifCount_ && a.elseCount_)
-                    return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;
-                if (a.elseifCount_ && !a.elseCount_)
-                    return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;
-                if (a.elseifCount_ && a.elseCount_)
-                    return Blockly.Msg.CONTROLS_IF_TOOLTIP_4
-            } else
-                return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;
-            return ""
+            var mode = thisBlock.getFieldValue('tilt_angle_type');
+            var TOOLTIPS = {
+                '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[mode];
         });
-        this.elseCount_ = this.elseifCount_ = 0
-    },
-    mutationToDom: function () {
-        if (!this.elseifCount_ && !this.elseCount_)
-            return null;
-        var a = document.createElement("mutation");
-        this.elseifCount_ && a.setAttribute("elseif", this.elseifCount_);
-        this.elseCount_ && a.setAttribute("else", 1);
-        return a
-    },
-    domToMutation: function (a) {
-        this.elseifCount_ = parseInt(a.getAttribute("elseif"), 10) || 0;
-        this.elseCount_ = parseInt(a.getAttribute("else"), 10) || 0;
-        this.updateShape_()
-    },
-    decompose: function (a) {
-        var b = a.newBlock("controls_if_if");
-        b.initSvg();
-        for (var c = b.nextConnection, e = 1; e <= this.elseifCount_; e++) {
-            var d = a.newBlock("controls_if_elseif");
-            d.initSvg();
-            c.connect(d.previousConnection);
-            c = d.nextConnection
-        }
-        this.elseCount_ && (a = a.newBlock("controls_if_else"),
-            a.initSvg(),
-            c.connect(a.previousConnection));
-        return b
-    },
-    compose: function (a) {
-        var b = a.nextConnection.targetBlock();
-        this.elseCount_ = this.elseifCount_ = 0;
-        a = [null];
-        for (var c = [null], e = null; b;) {
-            switch (b.type) {
-                case "controls_if_elseif":
-                    this.elseifCount_++;
-                    a.push(b.valueConnection_);
-                    c.push(b.statementConnection_);
-                    break;
-                case "controls_if_else":
-                    this.elseCount_++;
-                    e = b.statementConnection_;
+        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;
-                default:
-                    throw "Unknown block type.";
+                }
             }
-            b = b.nextConnection && b.nextConnection.targetBlock()
+            Blockly.Python.definitions_["servo_initS1"] = `S1= multiFuncGpio(0,1)
+S1.servoCtrl(${isNaN(Number(degree)) ? 90 : degree})`
         }
-        this.updateShape_();
-        for (b = 1; b <= this.elseifCount_; b++)
-            Blockly.icons.MutatorIcon.reconnect(a[b], this, "IF" + b),
-                Blockly.icons.MutatorIcon.reconnect(c[b], this, "DO" + b);
-        Blockly.icons.MutatorIcon.reconnect(e, this, "ELSE")
-    },
-    saveConnections: function (a) {
-        a = a.nextConnection.targetBlock();
-        for (var b = 1; a;) {
-            switch (a.type) {
-                case "controls_if_elseif":
-                    var c = this.getInput("IF" + b)
-                        , e = this.getInput("DO" + b);
-                    a.valueConnection_ = c && c.connection.targetConnection;
-                    a.statementConnection_ = e && e.connection.targetConnection;
-                    b++;
+        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;
-                case "controls_if_else":
-                    e = this.getInput("ELSE");
-                    a.statementConnection_ = e && e.connection.targetConnection;
-                    break;
-                default:
-                    throw "Unknown block type.";
+                }
             }
-            a = a.nextConnection && a.nextConnection.targetBlock()
+            Blockly.Python.definitions_["servo_initS2"] = `S2= multiFuncGpio(1,1)
+S2.servoCtrl(${isNaN(Number(degree1)) ? 90 : degree1})`
         }
-    },
-    updateShape_: function () {
-        this.getInput("ELSE") && this.removeInput("ELSE");
-        for (var a = 1; this.getInput("IF" + a);)
-            this.removeInput("IF" + a),
-                this.removeInput("DO" + a),
-                a++;
-        for (a = 1; a <= this.elseifCount_; a++)
-            this.appendValueInput("IF" + a).setCheck("Boolean").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF),
-                this.appendStatementInput("DO" + a).appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
-        this.elseCount_ && this.appendStatementInput("ELSE").appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE)
-    }
-};
-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');
+    } 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);
-        // 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.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`
         }
-        this.prevBlocks_[0] = blockA;
-        this.prevBlocks_[1] = blockB;
+        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`
+        }
+    }
+    return code;
+};
+
+// 屏幕
+
+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 () {
+        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.Blocks['logic_operation'] = {
-    /**
-     * Block for logical operations: 'and', 'or'.
-     * @this Blockly.Block
-     */
+
+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 OPERATORS =
-            [[Blockly.Msg.LOGIC_OPERATION_AND, 'AND'],
-            [Blockly.Msg.LOGIC_OPERATION_OR, 'OR']];
+        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);
-        // Assign 'this' to a variable for use in the tooltip closure below.
+        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);
+        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(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("None");
-        this.setColour(CategoryColors.Logic);
-        this.setOutput(true);
+            .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;

+ 75 - 0
src/blockly/blocks/customblocks.js

@@ -0,0 +1,75 @@
+/**
+ * @license
+ *
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview Define custom blocks.
+ * @author samelh@google.com (Sam El-Husseini)
+ */
+
+// More on defining blocks:
+// https://developers.google.com/blockly/guides/create-custom-blocks/define-blocks
+
+import * as Blockly from 'blockly/core';
+
+// Since we're using json to initialize the field, we'll need to import it.
+import '../fields/BlocklyReactField';
+import '../fields/DateField';
+
+import '@blockly/field-date';
+
+const reactDateField = {
+  type: 'test_react_date_field',
+  message0: 'date field: %1',
+  args0: [
+    {
+      type: 'field_date',
+      name: 'DATE',
+      date: '2020-02-20',
+    },
+  ],
+  previousStatement: null,
+  nextStatement: null,
+};
+
+Blockly.Blocks['test_react_date_field'] = {
+  init: function () {
+    this.jsonInit(reactDateField);
+    this.setStyle('loop_blocks');
+  },
+};
+
+const testReactField = {
+  type: 'test_react_field',
+  message0: 'custom field %1',
+  args0: [
+    {
+      type: 'field_react_component',
+      name: 'FIELD',
+      text: 'Click me',
+    },
+  ],
+  previousStatement: null,
+  nextStatement: null,
+};
+
+Blockly.Blocks['test_react_field'] = {
+  init: function () {
+    this.jsonInit(testReactField);
+    this.setStyle('loop_blocks');
+  },
+};

+ 3 - 9
src/blockly/blocks/dictionary.js

@@ -1,13 +1,7 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
+/* eslint-disable no-unused-expressions */
+import * as Blockly from 'blockly';
 import CategoryColors from './define_color'
 
-Blockly.Python = pythonGenerator
-
-Blockly.dictionary = {
-    HUE: CategoryColors['Dictionary'],
-};
-
 // Blockly.FieldDropdown.prototype.setText = function (a) {
 //     this.sourceBlock_ && this.arrow_ && (this.arrow_.style.fill = this.sourceBlock_.getColour());
 //     null !== a && a !== this.text_ && (this.text_ = a,
@@ -111,7 +105,7 @@ Blockly.Blocks.dict_create_with_items_insert = {
         for (var a = [], b = 0; this.getInput("ADD" + b); b++)
             a.push(this.getFieldValue("KEY" + b)),
                 this.removeInput("ADD" + b);
-        if (0 == this.itemCount_)
+        if (0 === this.itemCount_)
             this.getField("TIP").setText(Blockly.Msg.DICT_CREATE_EMPTY_TITLE);
         else
             for (this.getField("TIP").setText(Blockly.Msg.DICT_CREATE_WITH_INPUT_WITH),

+ 1 - 3
src/blockly/blocks/file.js

@@ -1,8 +1,6 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
+import * as Blockly from 'blockly';
 import CategoryColors from './define_color'
 
-Blockly.Python = pythonGenerator
 Blockly.Blocks['iot_system_run'] = {
     init: function () {
         this.appendDummyInput()

+ 27 - 15
src/blockly/blocks/index.js

@@ -1,18 +1,30 @@
-import basic from './basic';
-import logic from './logic';
-import math from './math';
-import variable from './variables';
-import text from './text';
-import list from './list';
-import dictionary from './dictionary';
-import tuples from './tuples';
-import set from './set';
-import procedures from './procedures';
-import output from './output';
-import file from './file';
+"use strict";
 
-const Blockly = { ...basic, ...logic, ...math, ...variable, ...text, ...list
-    , ...dictionary, ...tuples,...set, ...procedures, ...output, ...file
- };
+import basic from "./basic";
+import logic from "./logic";
+import math from "./math";
+import variable from "./variables";
+import text from "./text";
+import list from "./list";
+import dictionary from "./dictionary";
+import tuples from "./tuples";
+import set from "./set";
+import procedures from "./procedures";
+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, ...MediaProcessing, ...Camera,
+    ...Mircrohone, ...System, ...AI, ...IOT
+};
 
 export default Blockly;

+ 3 - 8
src/blockly/blocks/list.js

@@ -1,13 +1,8 @@
-import Blockly from 'blockly';
+import * as Blockly from 'blockly';
 import { pythonGenerator } from "blockly/python";
 import CategoryColors from './define_color'
 
 Blockly.Python = pythonGenerator
-
-Blockly.lists = {
-    HUE: CategoryColors['List'],
-};
-
 Blockly.Blocks['lists_create_with'] = {
     /**
      * Block for creating a list with any number of elements of any type.
@@ -147,7 +142,7 @@ Blockly.Blocks['lists_create_with_container'] = {
      * @this Blockly.Block
      */
     init: function () {
-        this.setColour(Blockly.lists.HUE);
+        this.setColour(CategoryColors['List']);
         this.appendDummyInput()
             .appendField(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD);
         this.appendStatementInput('STACK');
@@ -162,7 +157,7 @@ Blockly.Blocks['lists_create_with_item'] = {
      * @this Blockly.Block
      */
     init: function () {
-        this.setColour(Blockly.lists.HUE);
+        this.setColour(CategoryColors['List']);
         this.appendDummyInput()
             .appendField(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE);
         this.setPreviousStatement(true);

+ 609 - 10
src/blockly/blocks/logic.js

@@ -1,9 +1,20 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
-import CategoryColors from './define_color'
+import * as Blockly from "blockly";
 
-Blockly.Python = pythonGenerator
-Blockly.Blocks.CocoRobo_return = {
+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,
@@ -18,6 +29,594 @@ Blockly.Blocks.CocoRobo_return = {
             }]
         })
     }
+}
+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({
+            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 = {
@@ -48,7 +647,7 @@ Blockly.Blocks.CocoRobo_try_except_finally = {
         });
         this.appendStatementInput("TRY").appendField("try");
         this.appendStatementInput("EXCEPT").appendField("except");
-        this.appendStatementInput("FINALLY").appendField("finally")
+        this.appendStatementInput("FINALLY").appendField("finally");
     }
 };
 
@@ -65,7 +664,7 @@ Blockly.Blocks.CocoRobo_type = {
             colour: CategoryColors.Logic,
             tooltip: Blockly.Msg.CocoRobo_TYPE_TOOLTIP,
             helpUrl: Blockly.Msg.CocoRobo_TYPE_HELPURL
-        })
+        });
     }
 };
 
@@ -101,8 +700,8 @@ Blockly.Blocks.CocoRobo_type_is = {
         });
         var thisBlock = this;
         this.setTooltip(function () {
-            return Blockly.Msg.CocoRobo_TYPE_IS_TOOLTIP.replace('%2',
-                thisBlock.getFieldValue('TYPE'));
+            return Blockly.Msg.CocoRobo_TYPE_IS_TOOLTIP.replace("%2",
+                thisBlock.getFieldValue("TYPE"));
         });
     }
 };
@@ -119,7 +718,7 @@ Blockly.Blocks.CocoRobo_eval = {
             colour: CategoryColors.Logic,
             tooltip: Blockly.Msg.CocoRobo_EVAL_TOOLTIP,
             helpUrl: Blockly.Msg.CocoRobo_EVAL_HELPURL
-        })
+        });
     }
 };
 export default Blockly;

+ 157 - 164
src/blockly/blocks/math.js

@@ -1,15 +1,8 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
-import CategoryColors from './define_color'
+import * as Blockly from "blockly";
+import CategoryColors from "./define_color";
 
-Blockly.Python = pythonGenerator
 
-// math
-Blockly.math = {
-    HUE: "#5472ea"
-}
-/* additional math */
-Blockly.Blocks['math_degrad'] = {
+Blockly.Blocks["math_degrad"] = {
     init: function () {
         this.appendValueInput("convert")
             .setCheck(null)
@@ -24,10 +17,10 @@ Blockly.Blocks['math_degrad'] = {
 
         var thisBlock = this;
         this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('rad_deg');
+            var mode = thisBlock.getFieldValue("rad_deg");
             var TOOLTIPS = {
-                'radians': Blockly.Msg.Math_Degrad_RAD_TOOLTIP,
-                'degrees': Blockly.Msg.Math_Degrad_DEG_TOOLTIP
+                "radians": Blockly.Msg.Math_Degrad_RAD_TOOLTIP,
+                "degrees": Blockly.Msg.Math_Degrad_DEG_TOOLTIP
             };
             return TOOLTIPS[mode];
         });
@@ -47,7 +40,7 @@ Blockly.Blocks.math_angle = {
                 name: "angle",
                 type: "field_angle"
             }]
-        })
+        });
     }
 };
 
@@ -70,7 +63,7 @@ Blockly.Blocks.math_keep_decimal = {
                 type: "input_value",
                 name: "PLACE"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.math_division_consult = {
@@ -88,10 +81,10 @@ Blockly.Blocks.math_division_consult = {
             }],
             inputsInline: !0,
             output: "Number",
-            colour: Blockly.math.HUE,
+            colour: "#5472ea",
             tooltip: Blockly.Msg.MATH_DIVISION_CONSULT_TOOLTIP,
             helpUrl: Blockly.Msg.MATH_DIVISION_CONSULT_HELPURL
-        })
+        });
     }
 };
 Blockly.Blocks.labplus_mapping = {
@@ -123,7 +116,7 @@ Blockly.Blocks.labplus_mapping = {
             message0: Blockly.Msg.labplus_mapping_MESSAGE0,
             tooltip: Blockly.Msg.labplus_mapping_TOOLTIP,
             helpUrl: Blockly.Msg.labplus_mapping_HELPURL
-        })
+        });
     }
 };
 
@@ -149,10 +142,10 @@ Blockly.Blocks.math_random_randrange = {
                 type: "input_value",
                 name: "step"
             }]
-        })
+        });
     }
 };
-Blockly.Blocks['math_random_float'] = {
+Blockly.Blocks["math_random_float"] = {
   /**
    * Block for random fraction between 0 and 1.
    * @this Blockly.Block
@@ -184,7 +177,7 @@ Blockly.Blocks.math_convert = {
             colour: CategoryColors.Math,
             tooltip: Blockly.Msg.MATH_CONVERT_TOOLTIP,
             helpUrl: Blockly.Msg.MATH_CONVERT_HELPURL
-        })
+        });
     }
 };
 Blockly.Blocks.math_number_bits_ops = {
@@ -209,7 +202,7 @@ Blockly.Blocks.math_number_bits_ops = {
             colour: CategoryColors.Math,
             tooltip: Blockly.Msg.MATH_NUMBER_BITS_OPS_TOOLTIP,
             helpUrl: Blockly.Msg.MATH_NUMBER_BITS_OPS_HELPURL
-        })
+        });
     }
 };
 Blockly.Blocks.bit_inversion = {
@@ -225,7 +218,7 @@ Blockly.Blocks.bit_inversion = {
                 type: "input_value",
                 name: "data"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_ten_convert_to = {
@@ -253,8 +246,8 @@ Blockly.Blocks.CocoRobo_ten_convert_to = {
         });
         var thisBlock = this;
         this.setTooltip(function () {
-            return Blockly.Msg.CocoRobo_TEN_CONVERT_TO_TOOLTIP.replace('%2',
-                thisBlock.getFieldValue('ten_convert_to'));
+            return Blockly.Msg.CocoRobo_TEN_CONVERT_TO_TOOLTIP.replace("%2",
+                thisBlock.getFieldValue("ten_convert_to"));
         });
     }
 };
@@ -283,11 +276,11 @@ Blockly.Blocks.CocoRobo_convert_to_ten = {
         });
         var thisBlock = this;
         this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('convert_choice');
+            var mode = thisBlock.getFieldValue("convert_choice");
             var TOOLTIPS = {
-                '2': Blockly.Msg.CocoRobo_CONVERT_TO_TEN_TOOLTIP.replace('%2', "bin"),
-                '8': Blockly.Msg.CocoRobo_CONVERT_TO_TEN_TOOLTIP.replace('%2', "oct"),
-                '16': Blockly.Msg.CocoRobo_CONVERT_TO_TEN_TOOLTIP.replace('%2', "hex")
+                "2": Blockly.Msg.CocoRobo_CONVERT_TO_TEN_TOOLTIP.replace("%2", "bin"),
+                "8": Blockly.Msg.CocoRobo_CONVERT_TO_TEN_TOOLTIP.replace("%2", "oct"),
+                "16": Blockly.Msg.CocoRobo_CONVERT_TO_TEN_TOOLTIP.replace("%2", "hex")
             };
             return TOOLTIPS[mode];
         });
@@ -310,7 +303,7 @@ Blockly.Blocks.CocoRobo_high_low = {
                 type: "field_dropdown",
                 name: "high_low"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_start_new_thread = {
@@ -334,7 +327,7 @@ Blockly.Blocks.CocoRobo_start_new_thread = {
                 name: "thread_name"
             }]
         });
-        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO)
+        this.appendStatementInput("DO").appendField(Blockly.Msg.CONTROLS_REPEAT_INPUT_DO);
     }
 };
 Blockly.Blocks.CocoRobo_lock_object_acquire_lock = {
@@ -352,7 +345,7 @@ Blockly.Blocks.CocoRobo_lock_object_acquire_lock = {
                 name: "thread_lock_object",
                 text: "lock"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_ten_converted_to_bytes = {
@@ -379,10 +372,10 @@ Blockly.Blocks.CocoRobo_ten_converted_to_bytes = {
         });
         var thisBlock = this;
         this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('convert_choice');
+            var mode = thisBlock.getFieldValue("convert_choice");
             var TOOLTIPS = {
-                "'\x3cHH'": Blockly.Msg.CocoRobo_TEN_CONVERTED_TO_BYTES_TOOLTIP.replace('%1', "2"),
-                "'\x3cLL'": Blockly.Msg.CocoRobo_TEN_CONVERTED_TO_BYTES_TOOLTIP.replace('%1', "4")
+                "'\x3cHH'": Blockly.Msg.CocoRobo_TEN_CONVERTED_TO_BYTES_TOOLTIP.replace("%1", "2"),
+                "'\x3cLL'": Blockly.Msg.CocoRobo_TEN_CONVERTED_TO_BYTES_TOOLTIP.replace("%1", "4")
             };
             return TOOLTIPS[mode];
         });
@@ -402,7 +395,7 @@ Blockly.Blocks.CocoRobo_int_to_chr = {
                 type: "input_value",
                 name: "convert_num"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_hcsr04_obj = {
@@ -428,7 +421,7 @@ Blockly.Blocks.CocoRobo_hcsr04_obj = {
                 type: "input_value",
                 name: "echo"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_hcsr04_distance = {
@@ -452,7 +445,7 @@ Blockly.Blocks.CocoRobo_hcsr04_distance = {
                 type: "field_dropdown",
                 name: "unit"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_hcsr04_distance_mm = {
@@ -469,7 +462,7 @@ Blockly.Blocks.CocoRobo_hcsr04_distance_mm = {
                 type: "field_input",
                 name: "hcsr04_name"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_pm2_5_MIC = {
@@ -494,7 +487,7 @@ Blockly.Blocks.CocoRobo_pm2_5_MIC = {
                 type: "field_dropdown",
                 name: "unit"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_pm2_5_LitresAir = {
@@ -522,7 +515,7 @@ Blockly.Blocks.CocoRobo_pm2_5_LitresAir = {
                 type: "field_dropdown",
                 name: "unit"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_mac_address = {
@@ -530,11 +523,11 @@ Blockly.Blocks.CocoRobo_mac_address = {
         this.jsonInit({
             inputsInline: !0,
             output: "String",
-            colour: "X" == SOFTWARE_KEY ? CategoryColors.System : CategoryColors.Wifi,
+            colour: CategoryColors.System,
             helpUrl: Blockly.Msg.CocoRobo_MAC_ADDRESS_HELPURL,
             tooltip: Blockly.Msg.CocoRobo_MAC_ADDRESS_TOOLTIP,
             message0: Blockly.Msg.CocoRobo_MAC_ADDRESS_MESSAGE0
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_ujson_loads = {
@@ -551,7 +544,7 @@ Blockly.Blocks.CocoRobo_ujson_loads = {
                 type: "input_value",
                 name: "data"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_code_annotation = {
@@ -570,7 +563,7 @@ Blockly.Blocks.CocoRobo_code_annotation = {
                 type: "input_value",
                 name: "data"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_ujson_dumps = {
@@ -586,7 +579,7 @@ Blockly.Blocks.CocoRobo_ujson_dumps = {
                 type: "input_value",
                 name: "data"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_base64_to_data = {
@@ -602,7 +595,7 @@ Blockly.Blocks.CocoRobo_base64_to_data = {
                 type: "input_value",
                 name: "data"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_data_to_base64 = {
@@ -618,7 +611,7 @@ Blockly.Blocks.CocoRobo_data_to_base64 = {
                 type: "input_value",
                 name: "data"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_hex_to_bin_str = {
@@ -635,7 +628,7 @@ Blockly.Blocks.CocoRobo_hex_to_bin_str = {
                 type: "input_value",
                 name: "convert_chr"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_str_to_hex = {
@@ -652,7 +645,7 @@ Blockly.Blocks.CocoRobo_str_to_hex = {
                 type: "input_value",
                 name: "convert_chr"
             }]
-        })
+        });
     }
 };
 Blockly.Blocks.CocoRobo_chr_to_int = {
@@ -669,10 +662,10 @@ Blockly.Blocks.CocoRobo_chr_to_int = {
                 type: "input_value",
                 name: "convert_chr"
             }]
-        })
+        });
     }
 };
-Blockly.Blocks['math_single'] = {
+Blockly.Blocks["math_single"] = {
     /**
      * Block for advanced math operators with single operand.
      * @this Blockly.Block
@@ -685,15 +678,15 @@ Blockly.Blocks['math_single'] = {
                     "type": "field_dropdown",
                     "name": "OP",
                     "options": [
-                        [Blockly.Msg.MATH_SINGLE_OP_ROOT, 'ROOT'],
-                        [Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE, 'ABS'],
+                        [Blockly.Msg.MATH_SINGLE_OP_ROOT, "ROOT"],
+                        [Blockly.Msg.MATH_SINGLE_OP_ABSOLUTE, "ABS"],
                         // ['degrees', 'DEGRAD_DEG'],
                         // ['radians', 'DEGRAD_RAD'],
-                        ['-', 'NEG'],
-                        ['ln', 'LN'],
-                        ['log10', 'LOG10'],
-                        ['e^', 'EXP'],
-                        ['10^', 'POW10']
+                        ["-", "NEG"],
+                        ["ln", "LN"],
+                        ["log10", "LOG10"],
+                        ["e^", "EXP"],
+                        ["10^", "POW10"]
                     ]
                 },
                 {
@@ -709,22 +702,22 @@ Blockly.Blocks['math_single'] = {
         // Assign 'this' to a variable for use in the tooltip closure below.
         var thisBlock = this;
         this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('OP');
+            var mode = thisBlock.getFieldValue("OP");
             var TOOLTIPS = {
-                'ROOT': Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT,
-                'ABS': Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS,
-                'NEG': Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG,
-                'LN': Blockly.Msg.MATH_SINGLE_TOOLTIP_LN,
-                'LOG10': Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10,
-                'EXP': Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP,
-                'POW10': Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10
+                "ROOT": Blockly.Msg.MATH_SINGLE_TOOLTIP_ROOT,
+                "ABS": Blockly.Msg.MATH_SINGLE_TOOLTIP_ABS,
+                "NEG": Blockly.Msg.MATH_SINGLE_TOOLTIP_NEG,
+                "LN": Blockly.Msg.MATH_SINGLE_TOOLTIP_LN,
+                "LOG10": Blockly.Msg.MATH_SINGLE_TOOLTIP_LOG10,
+                "EXP": Blockly.Msg.MATH_SINGLE_TOOLTIP_EXP,
+                "POW10": Blockly.Msg.MATH_SINGLE_TOOLTIP_POW10
             };
             return TOOLTIPS[mode];
         });
     }
 };
 
-Blockly.Blocks['math_number'] = {
+Blockly.Blocks["math_number"] = {
     /**
      * Block for numeric value.
      * @this Blockly.Block
@@ -733,8 +726,8 @@ Blockly.Blocks['math_number'] = {
         this.setHelpUrl(Blockly.Msg.MATH_NUMBER_HELPURL);
         this.setColour(CategoryColors.Math);
         this.appendDummyInput()
-            .appendField(new Blockly.FieldNumber('0'), 'NUM');
-        this.setOutput(true, 'Number');
+            .appendField(new Blockly.FieldNumber("0"), "NUM");
+        this.setOutput(true, "Number");
         // Assign 'this' to a variable for use in the tooltip closure below.
         var thisBlock = this;
         // Number block is trivial.  Use tooltip of parent block if it exists.
@@ -746,7 +739,7 @@ Blockly.Blocks['math_number'] = {
     }
 };
 
-Blockly.Blocks['math_arithmetic'] = {
+Blockly.Blocks["math_arithmetic"] = {
     /**
      * Block for basic arithmetic operator.
      * @this Blockly.Block
@@ -764,11 +757,11 @@ Blockly.Blocks['math_arithmetic'] = {
                     "type": "field_dropdown",
                     "name": "OP",
                     "options":
-                        [[Blockly.Msg.MATH_ADDITION_SYMBOL, 'ADD'],
-                        [Blockly.Msg.MATH_SUBTRACTION_SYMBOL, 'MINUS'],
-                        [Blockly.Msg.MATH_MULTIPLICATION_SYMBOL, 'MULTIPLY'],
-                        [Blockly.Msg.MATH_DIVISION_SYMBOL, 'DIVIDE'],
-                        [Blockly.Msg.MATH_POWER_SYMBOL, 'POWER'],
+                        [[Blockly.Msg.MATH_ADDITION_SYMBOL, "ADD"],
+                        [Blockly.Msg.MATH_SUBTRACTION_SYMBOL, "MINUS"],
+                        [Blockly.Msg.MATH_MULTIPLICATION_SYMBOL, "MULTIPLY"],
+                        [Blockly.Msg.MATH_DIVISION_SYMBOL, "DIVIDE"],
+                        [Blockly.Msg.MATH_POWER_SYMBOL, "POWER"],
                             // ['%', 'MODULO']
                         ]
                 },
@@ -786,21 +779,21 @@ Blockly.Blocks['math_arithmetic'] = {
         // Assign 'this' to a variable for use in the tooltip closure below.
         var thisBlock = this;
         this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('OP');
+            var mode = thisBlock.getFieldValue("OP");
             var TOOLTIPS = {
-                'ADD': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
-                'MINUS': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
-                'MULTIPLY': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
-                'DIVIDE': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
-                'POWER': Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER,
-                'MODULO': 'Computes the remainder of division.'
+                "ADD": Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_ADD,
+                "MINUS": Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MINUS,
+                "MULTIPLY": Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_MULTIPLY,
+                "DIVIDE": Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_DIVIDE,
+                "POWER": Blockly.Msg.MATH_ARITHMETIC_TOOLTIP_POWER,
+                "MODULO": "Computes the remainder of division."
             };
             return TOOLTIPS[mode];
         });
     }
 };
 
-Blockly.Blocks['math_trig'] = {
+Blockly.Blocks["math_trig"] = {
     /**
      * Block for trigonometry operators.
      * @this Blockly.Block
@@ -813,12 +806,12 @@ Blockly.Blocks['math_trig'] = {
                     "type": "field_dropdown",
                     "name": "OP",
                     "options": [
-                        [Blockly.Msg.MATH_TRIG_SIN, 'SIN'],
-                        [Blockly.Msg.MATH_TRIG_COS, 'COS'],
-                        [Blockly.Msg.MATH_TRIG_TAN, 'TAN'],
-                        [Blockly.Msg.MATH_TRIG_ASIN, 'ASIN'],
-                        [Blockly.Msg.MATH_TRIG_ACOS, 'ACOS'],
-                        [Blockly.Msg.MATH_TRIG_ATAN, 'ATAN']
+                        [Blockly.Msg.MATH_TRIG_SIN, "SIN"],
+                        [Blockly.Msg.MATH_TRIG_COS, "COS"],
+                        [Blockly.Msg.MATH_TRIG_TAN, "TAN"],
+                        [Blockly.Msg.MATH_TRIG_ASIN, "ASIN"],
+                        [Blockly.Msg.MATH_TRIG_ACOS, "ACOS"],
+                        [Blockly.Msg.MATH_TRIG_ATAN, "ATAN"]
                     ]
                 },
                 {
@@ -834,21 +827,21 @@ Blockly.Blocks['math_trig'] = {
         // Assign 'this' to a variable for use in the tooltip closure below.
         var thisBlock = this;
         this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('OP');
+            var mode = thisBlock.getFieldValue("OP");
             var TOOLTIPS = {
-                'SIN': Blockly.Msg.MATH_TRIG_TOOLTIP_SIN,
-                'COS': Blockly.Msg.MATH_TRIG_TOOLTIP_COS,
-                'TAN': Blockly.Msg.MATH_TRIG_TOOLTIP_TAN,
-                'ASIN': Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN,
-                'ACOS': Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS,
-                'ATAN': Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN
+                "SIN": Blockly.Msg.MATH_TRIG_TOOLTIP_SIN,
+                "COS": Blockly.Msg.MATH_TRIG_TOOLTIP_COS,
+                "TAN": Blockly.Msg.MATH_TRIG_TOOLTIP_TAN,
+                "ASIN": Blockly.Msg.MATH_TRIG_TOOLTIP_ASIN,
+                "ACOS": Blockly.Msg.MATH_TRIG_TOOLTIP_ACOS,
+                "ATAN": Blockly.Msg.MATH_TRIG_TOOLTIP_ATAN
             };
             return TOOLTIPS[mode];
         });
     }
 };
 
-Blockly.Blocks['math_constant'] = {
+Blockly.Blocks["math_constant"] = {
     /**
      * Block for constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY.
      * @this Blockly.Block
@@ -861,12 +854,12 @@ Blockly.Blocks['math_constant'] = {
                     "type": "field_dropdown",
                     "name": "CONSTANT",
                     "options": [
-                        ['\u03c0', 'PI'],
-                        ['e', 'E'],
-                        ['\u03c6', 'GOLDEN_RATIO'],
-                        ['sqrt(2)', 'SQRT2'],
-                        ['sqrt(\u00bd)', 'SQRT1_2'],
-                        ['\u221e', 'INFINITY']
+                        ["\u03c0", "PI"],
+                        ["e", "E"],
+                        ["\u03c6", "GOLDEN_RATIO"],
+                        ["sqrt(2)", "SQRT2"],
+                        ["sqrt(\u00bd)", "SQRT1_2"],
+                        ["\u221e", "INFINITY"]
                     ]
                 }
             ],
@@ -878,7 +871,7 @@ Blockly.Blocks['math_constant'] = {
     }
 };
 
-Blockly.Blocks['math_number_property'] = {
+Blockly.Blocks["math_number_property"] = {
     /**
      * Block for checking if a number is even, odd, prime, whole, positive,
      * negative or if it is divisible by certain number.
@@ -886,24 +879,24 @@ Blockly.Blocks['math_number_property'] = {
      */
     init: function () {
         var PROPERTIES =
-            [[Blockly.Msg.MATH_IS_EVEN, 'EVEN'],
-            [Blockly.Msg.MATH_IS_ODD, 'ODD'],
-            [Blockly.Msg.MATH_IS_PRIME, 'PRIME'],
-            [Blockly.Msg.MATH_IS_WHOLE, 'WHOLE'],
-            [Blockly.Msg.MATH_IS_POSITIVE, 'POSITIVE'],
-            [Blockly.Msg.MATH_IS_NEGATIVE, 'NEGATIVE'],
-            [Blockly.Msg.MATH_IS_DIVISIBLE_BY, 'DIVISIBLE_BY']];
+            [[Blockly.Msg.MATH_IS_EVEN, "EVEN"],
+            [Blockly.Msg.MATH_IS_ODD, "ODD"],
+            [Blockly.Msg.MATH_IS_PRIME, "PRIME"],
+            [Blockly.Msg.MATH_IS_WHOLE, "WHOLE"],
+            [Blockly.Msg.MATH_IS_POSITIVE, "POSITIVE"],
+            [Blockly.Msg.MATH_IS_NEGATIVE, "NEGATIVE"],
+            [Blockly.Msg.MATH_IS_DIVISIBLE_BY, "DIVISIBLE_BY"]];
         this.setColour(CategoryColors.Math);
-        this.appendValueInput('NUMBER_TO_CHECK')
-            .setCheck('Number');
+        this.appendValueInput("NUMBER_TO_CHECK")
+            .setCheck("Number");
         var dropdown = new Blockly.FieldDropdown(PROPERTIES, function (option) {
-            var divisorInput = (option == 'DIVISIBLE_BY');
+            var divisorInput = (option == "DIVISIBLE_BY");
             this.sourceBlock_.updateShape_(divisorInput);
         });
         this.appendDummyInput()
-            .appendField(dropdown, 'PROPERTY');
+            .appendField(dropdown, "PROPERTY");
         this.setInputsInline(true);
-        this.setOutput(true, 'Boolean');
+        this.setOutput(true, "Boolean");
         this.setTooltip(Blockly.Msg.MATH_IS_TOOLTIP);
     },
     /**
@@ -912,9 +905,9 @@ Blockly.Blocks['math_number_property'] = {
      * @this Blockly.Block
      */
     mutationToDom: function () {
-        var container = document.createElement('mutation');
-        var divisorInput = (this.getFieldValue('PROPERTY') == 'DIVISIBLE_BY');
-        container.setAttribute('divisor_input', divisorInput);
+        var container = document.createElement("mutation");
+        var divisorInput = (this.getFieldValue("PROPERTY") == "DIVISIBLE_BY");
+        container.setAttribute("divisor_input", divisorInput);
         return container;
     },
     /**
@@ -923,7 +916,7 @@ Blockly.Blocks['math_number_property'] = {
      * @this Blockly.Block
      */
     domToMutation: function (xmlElement) {
-        var divisorInput = (xmlElement.getAttribute('divisor_input') == 'true');
+        var divisorInput = (xmlElement.getAttribute("divisor_input") == "true");
         this.updateShape_(divisorInput);
     },
     /**
@@ -934,19 +927,19 @@ Blockly.Blocks['math_number_property'] = {
      */
     updateShape_: function (divisorInput) {
         // Add or remove a Value Input.
-        var inputExists = this.getInput('DIVISOR');
+        var inputExists = this.getInput("DIVISOR");
         if (divisorInput) {
             if (!inputExists) {
-                this.appendValueInput('DIVISOR')
-                    .setCheck('Number');
+                this.appendValueInput("DIVISOR")
+                    .setCheck("Number");
             }
         } else if (inputExists) {
-            this.removeInput('DIVISOR');
+            this.removeInput("DIVISOR");
         }
     }
 };
 
-Blockly.Blocks['math_round'] = {
+Blockly.Blocks["math_round"] = {
     /**
      * Block for rounding functions.
      * @this Blockly.Block
@@ -959,9 +952,9 @@ Blockly.Blocks['math_round'] = {
                     "type": "field_dropdown",
                     "name": "OP",
                     "options": [
-                        [Blockly.Msg.MATH_ROUND_OPERATOR_ROUND, 'ROUND'],
-                        [Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP, 'ROUNDUP'],
-                        [Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN, 'ROUNDDOWN']
+                        [Blockly.Msg.MATH_ROUND_OPERATOR_ROUND, "ROUND"],
+                        [Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDUP, "ROUNDUP"],
+                        [Blockly.Msg.MATH_ROUND_OPERATOR_ROUNDDOWN, "ROUNDDOWN"]
                     ]
                 },
                 {
@@ -978,7 +971,7 @@ Blockly.Blocks['math_round'] = {
     }
 };
 
-Blockly.Blocks['math_on_list'] = {
+Blockly.Blocks["math_on_list"] = {
     /**
      * Block for evaluating a list of numbers to return sum, average, min, max,
      * etc.  Some functions also work on text (min, max, mode, median).
@@ -986,36 +979,36 @@ Blockly.Blocks['math_on_list'] = {
      */
     init: function () {
         var OPERATORS =
-            [[Blockly.Msg.MATH_ONLIST_OPERATOR_SUM, 'SUM'],
-            [Blockly.Msg.MATH_ONLIST_OPERATOR_MIN, 'MIN'],
-            [Blockly.Msg.MATH_ONLIST_OPERATOR_MAX, 'MAX'],
-            [Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE, 'AVERAGE'],
-            [Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN, 'MEDIAN'],
-            [Blockly.Msg.MATH_ONLIST_OPERATOR_MODE, 'MODE'],
-            [Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV, 'STD_DEV'],
-            [Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM, 'RANDOM']];
+            [[Blockly.Msg.MATH_ONLIST_OPERATOR_SUM, "SUM"],
+            [Blockly.Msg.MATH_ONLIST_OPERATOR_MIN, "MIN"],
+            [Blockly.Msg.MATH_ONLIST_OPERATOR_MAX, "MAX"],
+            [Blockly.Msg.MATH_ONLIST_OPERATOR_AVERAGE, "AVERAGE"],
+            [Blockly.Msg.MATH_ONLIST_OPERATOR_MEDIAN, "MEDIAN"],
+            [Blockly.Msg.MATH_ONLIST_OPERATOR_MODE, "MODE"],
+            [Blockly.Msg.MATH_ONLIST_OPERATOR_STD_DEV, "STD_DEV"],
+            [Blockly.Msg.MATH_ONLIST_OPERATOR_RANDOM, "RANDOM"]];
         // Assign 'this' to a variable for use in the closures below.
         var thisBlock = this;
         this.setHelpUrl(Blockly.Msg.MATH_ONLIST_HELPURL);
         this.setColour(CategoryColors.Math);
-        this.setOutput(true, 'Number');
+        this.setOutput(true, "Number");
         var dropdown = new Blockly.FieldDropdown(OPERATORS, function (newOp) {
             thisBlock.updateType_(newOp);
         });
-        this.appendValueInput('LIST')
-            .setCheck('Array')
-            .appendField(dropdown, 'OP');
+        this.appendValueInput("LIST")
+            .setCheck("Array")
+            .appendField(dropdown, "OP");
         this.setTooltip(function () {
-            var mode = thisBlock.getFieldValue('OP');
+            var mode = thisBlock.getFieldValue("OP");
             var TOOLTIPS = {
-                'SUM': Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM,
-                'MIN': Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN,
-                'MAX': Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX,
-                'AVERAGE': Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE,
-                'MEDIAN': Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN,
-                'MODE': Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE,
-                'STD_DEV': Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV,
-                'RANDOM': Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM
+                "SUM": Blockly.Msg.MATH_ONLIST_TOOLTIP_SUM,
+                "MIN": Blockly.Msg.MATH_ONLIST_TOOLTIP_MIN,
+                "MAX": Blockly.Msg.MATH_ONLIST_TOOLTIP_MAX,
+                "AVERAGE": Blockly.Msg.MATH_ONLIST_TOOLTIP_AVERAGE,
+                "MEDIAN": Blockly.Msg.MATH_ONLIST_TOOLTIP_MEDIAN,
+                "MODE": Blockly.Msg.MATH_ONLIST_TOOLTIP_MODE,
+                "STD_DEV": Blockly.Msg.MATH_ONLIST_TOOLTIP_STD_DEV,
+                "RANDOM": Blockly.Msg.MATH_ONLIST_TOOLTIP_RANDOM
             };
             return TOOLTIPS[mode];
         });
@@ -1027,10 +1020,10 @@ Blockly.Blocks['math_on_list'] = {
      * @this Blockly.Block
      */
     updateType_: function (newOp) {
-        if (newOp == 'MODE') {
-            this.outputConnection.setCheck('Array');
+        if (newOp == "MODE") {
+            this.outputConnection.setCheck("Array");
         } else {
-            this.outputConnection.setCheck('Number');
+            this.outputConnection.setCheck("Number");
         }
     },
     /**
@@ -1039,8 +1032,8 @@ Blockly.Blocks['math_on_list'] = {
      * @this Blockly.Block
      */
     mutationToDom: function () {
-        var container = document.createElement('mutation');
-        container.setAttribute('op', this.getFieldValue('OP'));
+        var container = document.createElement("mutation");
+        container.setAttribute("op", this.getFieldValue("OP"));
         return container;
     },
     /**
@@ -1049,10 +1042,10 @@ Blockly.Blocks['math_on_list'] = {
      * @this Blockly.Block
      */
     domToMutation: function (xmlElement) {
-        this.updateType_(xmlElement.getAttribute('op'));
+        this.updateType_(xmlElement.getAttribute("op"));
     }
 };
-Blockly.Blocks['math_modulo'] = {
+Blockly.Blocks["math_modulo"] = {
     /**
      * Block for remainder of a division.
      * @this Blockly.Block
@@ -1080,7 +1073,7 @@ Blockly.Blocks['math_modulo'] = {
         });
     }
 };
-Blockly.Blocks['math_constrain'] = {
+Blockly.Blocks["math_constrain"] = {
     /**
      * Block for constraining a number between two limits.
      * @this Blockly.Block
@@ -1114,7 +1107,7 @@ Blockly.Blocks['math_constrain'] = {
     }
 };
 
-Blockly.Blocks['labplus_mapping'] = {
+Blockly.Blocks["labplus_mapping"] = {
     init: function () {
         this.jsonInit({
             inputsInline: !0,
@@ -1144,11 +1137,11 @@ Blockly.Blocks['labplus_mapping'] = {
             message0: Blockly.Msg.labplus_mapping_MESSAGE0,
             tooltip: Blockly.Msg.labplus_mapping_TOOLTIP,
             helpUrl: Blockly.Msg.labplus_mapping_HELPURL
-        })
+        });
     }
 };
 
-Blockly.Blocks['math_random_int'] = {
+Blockly.Blocks["math_random_int"] = {
     /**
      * Block for random integer between [X] and [Y].
      * @this Blockly.Block
@@ -1194,7 +1187,7 @@ Blockly.Blocks.math_convert = {
             colour: CategoryColors.Math,
             tooltip: Blockly.Msg.MATH_CONVERT_TOOLTIP,
             helpUrl: Blockly.Msg.MATH_CONVERT_HELPURL
-        })
+        });
     }
 };
-export default Blockly
+export default Blockly;

+ 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;

+ 1 - 3
src/blockly/blocks/output.js

@@ -1,8 +1,6 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
+import * as Blockly from 'blockly';
 import CategoryColors from './define_color'
 
-Blockly.Python = pythonGenerator
 const ESP32_IO_COLOR = "#ff8027";
 Blockly.Blocks['esp32_main_controller_io_from_digital_pin'] = {
     init: function () {

+ 1 - 4
src/blockly/blocks/procedures.js

@@ -1,11 +1,8 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
+import * as Blockly from 'blockly';
 import CategoryColors from './define_color'
 import goog from './BlocklyFunction';
 
-Blockly.Python = pythonGenerator;
 
-// console.log('blocklyFunctions',Blockly)
 Blockly.Blocks.procedures_defnoreturn = {
     init: function () {
         var a = new Blockly.FieldTextInput(Blockly.Msg.PROCEDURES_DEFNORETURN_PROCEDURE, Blockly.Procedures.rename);

+ 282 - 0
src/blockly/blocks/serial.js

@@ -0,0 +1,282 @@
+import * as Blockly from "blockly";
+
+const serialColor = "#22b845";
+Blockly.Blocks['serial_print'] = {
+    init: function () {
+        this.appendValueInput("serial_comm_input")
+            .setCheck("String")
+            .appendField(Blockly.Msg.serialcomm_print);
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(serialColor);
+        this.setTooltip(Blockly.Msg.serial_Comm_Print_TOOLTIP);
+        this.setHelpUrl("");
+    }
+}
+
+Blockly.Blocks['serial_comm_print'] = {
+    init: function () {
+        this.appendValueInput("serial_comm_input")
+            .setCheck("String")
+            .appendField(Blockly.Msg.serialcomm_print);
+        this.setInputsInline(false);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(serialColor);
+        this.setTooltip(Blockly.Msg.serial_Comm_Print_TOOLTIP);
+        this.setHelpUrl("");
+    }
+};  
+
+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_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.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);
+        this.setTooltip(Blockly.Msg.Serial_Write_Data_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('serial_write_data_create_with_container');
+        containerBlock.initSvg();
+        var connection = containerBlock.getInput('STACK').connection;
+        for (var i = 0; i < this.itemCount_; i++) {
+            var itemBlock = workspace.newBlock('serial_write_data_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(Blockly.Msg.serialcomm_write_item_first + i + Blockly.Msg.serialcomm_write_item_last);
+                //input.appendField("資料 " + (i + 1) + ":");
+                //input.appendField(new Blockly.FieldLabelSerializable("field" + (i + 1)), 'FIELD' + i);
+                // input.appendField(new Blockly.FieldTextInput("資料" + (i + 1)), 'FIELD' + i)
+            }
+        }
+        while (this.getInput('ADD' + i)) {
+            this.removeInput('ADD' + i);
+            i++;
+        }
+    },
+};
+
+Blockly.Blocks['serial_write_data_create_with_item'] = {
+    init: function () {
+        this.setColour(serialColor);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serialcomm_write_data);
+        this.setPreviousStatement(true);
+        this.setNextStatement(true);
+        this.setTooltip('');
+        this.contextMenu = false;
+    }
+};
+
+Blockly.Blocks['serial_write_data_create_with_container'] = {
+    init: function () {
+        this.setColour(serialColor);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serialcomm_write_item);
+        this.appendStatementInput('STACK');
+        this.setTooltip('');
+        this.contextMenu = false;
+    }
+};
+Blockly.Blocks['serial_write_data'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(new Blockly.FieldImage("./media/uart_serial_send_header.png", 110, 35, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serialcomm_write_title_text);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serialcomm_write_data_bps_title)
+            .appendField(new Blockly.FieldNumber(115200, 0, 500000, 1), "uart_bps")
+            .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(Blockly.Msg.Serial_Write_Data_TOOLTIP);
+        this.setHelpUrl("");
+    },
+};
+
+Blockly.Blocks['serial_read_data_setup'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(new Blockly.FieldImage("./media/uart_serial_read_header.png", 110, 35, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serialcomm_read_setup_title_text + Blockly.Msg.serialcomm_read_setup_title_text_1);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serialcomm_write_data_bps_title)
+            .appendField(new Blockly.FieldNumber(115200, 0, 500000, 1), "uart_bps")
+            .appendField(Blockly.Msg.serialcomm_write_data_bps_attrib);
+        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_Read_Data_Setup_TOOLTIP.replace('%1', Blockly.Msg.serialcomm_write_on_iot),
+                'ai': Blockly.Msg.Serial_Read_Data_Setup_TOOLTIP.replace('%1', Blockly.Msg.serialcomm_write_on_ai)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Blocks['serial_read_data_all'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.Serial_Read_Data_all)
+        // .appendField(new Blockly.FieldDropdown([
+        //     ["serial_data", "serial_data"]
+        // ]), "TYPE");
+        this.setOutput(true, null);
+        this.setColour("#22b845");
+        this.setTooltip(Blockly.Msg.Serial_Read_Data_all);
+        this.setHelpUrl("");
+    }
+}
+Blockly.Blocks['serial_read_data'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ARD_SERIAL_RECEIVE_DATASET_GET_TEXT)
+            .appendField(new Blockly.FieldDropdown([
+                ["0", "0"],
+                ["1", "1"],
+                ["2", "2"],
+                ["3", "3"],
+                ["4", "4"],
+                ["5", "5"],
+                ["6", "6"],
+                ["7", "7"],
+                ["8", "8"],
+                ["9", "9"],
+                ["10", "10"],
+                ["11", "11"],
+            ]), "INDEX")
+            .appendField(Blockly.Msg.ARD_SERIAL_RECEIVE_DATASET_TYPE_TEXT)
+        this.setOutput(true, null);
+        this.setColour(serialColor);
+        this.setTooltip(Blockly.Msg.Serial_Read_Data_TOOLTIP);
+        this.setHelpUrl("");
+    }
+}
+
+Blockly.Blocks['serial_send_data_to_microbit'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(new Blockly.FieldImage("./media/microbit_data_send_header.png", 90, 70, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serialcomm_write_data_bps_title)
+            .appendField("115200")
+            .appendField(Blockly.Msg.serialcomm_write_data_bps_attrib);
+        this.appendValueInput("NAME")
+            .appendField(Blockly.Msg.serial_send_data_on_send_data);
+        this.setInputsInline(false);
+        this.setColour(serialColor);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setHelpUrl("");
+        this.setTooltip(Blockly.Msg.serial_send_data_on_send_data);
+    }
+};
+Blockly.Blocks['serial_send_data_to_control_panel'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(new Blockly.FieldImage("./media/control.png", 90, 70, { alt: "*", flipRtl: "FALSE" }));
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serialcomm_write_data_bps_title)
+            .appendField("9600")
+            .appendField(Blockly.Msg.serialcomm_write_data_bps_attrib);
+        this.appendValueInput("NAME")
+            .appendField(Blockly.Msg.serial_send_data_on_send_data_control_panel);
+        this.setInputsInline(false);
+        this.setColour("#22b845");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setHelpUrl("");
+        this.setTooltip(Blockly.Msg.serial_send_data_on_send_data_control_panel);
+    }
+};
+
+Blockly.Blocks['serial_read_data_clear'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.serial_clear_data);
+        this.setColour("#22b845");
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setTooltip(Blockly.Msg.serial_clear_data);
+        this.setHelpUrl("");
+    }
+};
+export default Blockly;

+ 2 - 7
src/blockly/blocks/set.js

@@ -1,12 +1,7 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
+/* eslint-disable no-unused-expressions */
+import * as Blockly from 'blockly';
 import CategoryColors from './define_color'
 
-Blockly.Python = pythonGenerator
-
-Blockly.set= {
-    HUE: CategoryColors['Set'],
-};
 Blockly.Blocks.set_create_with_items_insert = {
     init: function () {
         this.setHelpUrl(Blockly.Msg.SET_CREATE_WITH_ITEMS_INSERT_HELPURL);

+ 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;

+ 34 - 22
src/blockly/blocks/text.js

@@ -1,14 +1,6 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
+import * as Blockly from 'blockly';
 import CategoryColors from './define_color'
 
-Blockly.Python = pythonGenerator
-
-// variables
-Blockly.texts = {
-    HUE: "#33cc99"
-}
-
 Blockly.Blocks['text'] = {
     /**
      * Block for text value.
@@ -16,7 +8,7 @@ Blockly.Blocks['text'] = {
      */
     init: function () {
         this.setHelpUrl(Blockly.Msg.TEXT_TEXT_HELPURL);
-        this.setColour(Blockly.texts.HUE);
+        this.setColour(CategoryColors.Text);
         this.appendDummyInput()
             .appendField(this.newQuote_(true))
             .appendField(new Blockly.FieldTextInput(''), 'TEXT')
@@ -55,7 +47,7 @@ Blockly.Blocks['text_join'] = {
      */
     init: function () {
         this.setHelpUrl(Blockly.Msg.TEXT_JOIN_HELPURL);
-        this.setColour(Blockly.texts.HUE);
+        this.setColour(CategoryColors.Text);
         this.itemCount_ = 2;
         this.updateShape_();
         this.setOutput(true, 'String');
@@ -68,7 +60,7 @@ Blockly.Blocks['text_join'] = {
      * @this Blockly.Block
      */
     mutationToDom: function () {
-        var container = document.createElement('mutation');
+        var container = Blockly.utils.xml.createElement('mutation');
         container.setAttribute('items', this.itemCount_);
         return container;
     },
@@ -108,7 +100,7 @@ Blockly.Blocks['text_join'] = {
         var itemBlock = containerBlock.getInputTargetBlock('STACK');
         // Count number of inputs.
         var connections = [];
-        while (itemBlock) {
+        while (itemBlock && !itemBlock.isInsertionMarker()) {
             connections.push(itemBlock.valueConnection_);
             itemBlock = itemBlock.nextConnection &&
                 itemBlock.nextConnection.targetBlock();
@@ -124,7 +116,8 @@ Blockly.Blocks['text_join'] = {
         this.updateShape_();
         // Reconnect any child blocks.
         for (var i = 0; i < this.itemCount_; i++) {
-            Blockly.icons.MutatorIcon.reconnect(connections[i], this, 'ADD' + i);
+            console.log("connections[i]---", Blockly, this)
+            Blockly.icons.MutatorIcon.reconnect(connections[i],this, 'ADD' + i);
         }
     },
     /**
@@ -173,6 +166,25 @@ Blockly.Blocks['text_join'] = {
     },
     newQuote_: Blockly.Blocks['text'].newQuote_
 };
+Blockly.Blocks['text_create_join_item'] = {
+    init: function () {
+        this.appendDummyInput().appendField(Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TITLE_ITEM);
+        this.setPreviousStatement(!0);
+        this.setNextStatement(!0);
+        this.setTooltip(Blockly.Msg.TEXT_CREATE_JOIN_ITEM_TOOLTIP);
+        this.contextMenu = !1
+        this.setColour(CategoryColors.Text);
+    }
+}
+Blockly.Blocks['text_create_join_container'] = {
+    init: function () {
+        this.appendDummyInput().appendField(Blockly.Msg.TEXT_CREATE_JOIN_TITLE_JOIN);
+        this.appendStatementInput("STACK");
+        this.setTooltip(Blockly.Msg.TEXT_CREATE_JOIN_TOOLTIP);
+        this.contextMenu = !1
+        this.setColour(CategoryColors.Text);
+    }
+}
 Blockly.Blocks['text_split_string_by_delimiter'] = {
     init: function () {
         this.appendValueInput("string_input")
@@ -184,7 +196,7 @@ Blockly.Blocks['text_split_string_by_delimiter'] = {
             .appendField(Blockly.Msg.text_additional_delimiter_end);
         this.setInputsInline(true);
         this.setOutput(true, null);
-        this.setColour(Blockly.texts.HUE);
+        this.setColour(CategoryColors.Text);
         this.setTooltip(Blockly.Msg.Text_Split_String_By_Delimiter_TOOLTIP);
         this.setHelpUrl("");
     }
@@ -194,7 +206,7 @@ Blockly.Blocks.text_format = {
         this.jsonInit({
             inputsInline: !1,
             output: "String",
-            colour: Blockly.texts.HUE,
+            colour: CategoryColors.Text,
             helpUrl: Blockly.Msg.TEXT_FORMAT_HELPURL,
             tooltip: Blockly.Msg.TEXT_FORMAT_TOOLTIP,
             message0: Blockly.Msg.TEXT_FORMAT_MESSAGE0,
@@ -214,7 +226,7 @@ Blockly.Blocks.text_format2 = {
         this.jsonInit({
             inputsInline: !1,
             output: "String",
-            colour: Blockly.texts.HUE,
+            colour: CategoryColors.Text,
             helpUrl: Blockly.Msg.TEXT_FORMAT2_HELPURL,
             tooltip: Blockly.Msg.TEXT_FORMAT2_TOOLTIP,
             message0: Blockly.Msg.TEXT_FORMAT2_MESSAGE0,
@@ -232,7 +244,7 @@ Blockly.Blocks.text_format2 = {
 Blockly.Blocks.tuple_create_with_items_insert = {
     init: function () {
         this.setHelpUrl(Blockly.Msg.TUPLE_CREATE_WITH_ITEMS_INSERT_HELPURL);
-        this.setColour(Blockly.texts.HUE);
+        this.setColour(CategoryColors.Text);
         this.itemCount_ = 3;
         this.updateShape_();
         this.setOutput(!0);
@@ -296,7 +308,7 @@ Blockly.Blocks.tuple_create_with_items_insert = {
 };
 Blockly.Blocks.tuple_create_with_item = {
     init: function () {
-        this.setColour(Blockly.texts.HUE);
+        this.setColour(CategoryColors.Text);
         this.appendDummyInput().appendField(Blockly.Msg.TUPLE_CREATE_WITH_ITEM_TITLE);
         this.setPreviousStatement(!0);
         this.setNextStatement(!0);
@@ -306,7 +318,7 @@ Blockly.Blocks.tuple_create_with_item = {
 };
 Blockly.Blocks.tuple_create_with_container = {
     init: function () {
-        this.setColour(Blockly.texts.HUE);
+        this.setColour(CategoryColors.Text);
         this.appendDummyInput().appendField(Blockly.Msg.TUPLE_CREATE_WITH_CONTAINER_TITLE_ADD);
         this.appendStatementInput("STACK");
         this.setTooltip(Blockly.Msg.TUPLE_CREATE_WITH_CONTAINER_TOOLTIP);
@@ -316,7 +328,7 @@ Blockly.Blocks.tuple_create_with_container = {
 Blockly.Blocks.tuple_create_with = {
     init: function () {
         this.jsonInit({
-            colour: Blockly.texts.HUE,
+            colour: CategoryColors.Text,
             args0: [{
                 type: "input_value",
                 name: "tuple_name"
@@ -338,7 +350,7 @@ Blockly.Blocks.CocoRobo_text_ESC = {
         this.jsonInit({
             inputsInline: !0,
             output: null,
-            colour: Blockly.texts.HUE,
+            colour: CategoryColors.Text,
             helpUrl: Blockly.Msg.CocoRobo_TEXT_ESC_HELPURL,
             tooltip: Blockly.Msg.CocoRobo_TEXT_ESC_TOOLTIP,
             message0: Blockly.Msg.CocoRobo_TEXT_ESC_MESSAGE0,

+ 155 - 0
src/blockly/blocks/time.js

@@ -0,0 +1,155 @@
+import * as Blockly from 'blockly';
+
+const timeColor = '#fabe23';
+Blockly.Blocks['time_delay'] = {
+    init: function () {
+        this.appendValueInput('DELAY_TIME_MILI')
+            .setCheck('Number')
+            .appendField(Blockly.Msg.ARD_TIME_DELAY);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ARD_TIME_MS);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_TIP);
+        this.setColour(timeColor);
+    }
+}
+
+Blockly.Blocks['time_delayseconds'] = {
+    /**
+     * delayMicroseconds block definition
+     * @this Blockly.Block
+     */
+    init: function () {
+        this.setHelpUrl('');
+        this.setColour(timeColor);
+        this.appendValueInput('DELAY_TIME_MICRO')
+            //.setCheck(Blockly.Types.NUMBER.checkList)
+            .appendField(Blockly.Msg.ARD_TIME_DELAY);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.ARD_TIME_DELAY_seconds);
+        this.setInputsInline(true);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setTooltip(Blockly.Msg.ARD_TIME_DELAY_seconds_TIP);
+    }
+};
+Blockly.Blocks['esp32_get_current_date'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.time_get_current_date_title)
+            .appendField(new Blockly.FieldDropdown([
+                [Blockly.Msg.time_get_current_date_y, "Y"],
+                [Blockly.Msg.time_get_current_date_m, "m"],
+                [Blockly.Msg.time_get_current_date_d, "d"],
+                [Blockly.Msg.time_get_current_date_hour, "H"],
+                [Blockly.Msg.time_get_current_date_min, "M"],
+                [Blockly.Msg.time_get_current_date_sec, "S"]
+            ]), "type");
+        this.setInputsInline(false);
+        this.setOutput(true, null);
+        this.setColour(timeColor);
+        this.setHelpUrl("");
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('type');
+            var TOOLTIPS = {
+                '0': Blockly.Msg.Esp32_Get_Current_Date_TOOLTIP.replace('%1', Blockly.Msg.time_get_current_date_y),
+                '1': Blockly.Msg.Esp32_Get_Current_Date_TOOLTIP.replace('%1', Blockly.Msg.time_get_current_date_m),
+                '2': Blockly.Msg.Esp32_Get_Current_Date_TOOLTIP.replace('%1', Blockly.Msg.time_get_current_date_d),
+                '3': Blockly.Msg.Esp32_Get_Current_Date_TOOLTIP.replace('%1', Blockly.Msg.time_get_current_date_hour),
+                '4': Blockly.Msg.Esp32_Get_Current_Date_TOOLTIP.replace('%1', Blockly.Msg.time_get_current_date_min),
+                '5': Blockly.Msg.Esp32_Get_Current_Date_TOOLTIP.replace('%1', Blockly.Msg.time_get_current_date_sec)
+            };
+            return TOOLTIPS[mode];
+        });
+    }
+};
+
+Blockly.Blocks['esp32_main_controller_time_timer_init'] = {
+    init: function () {
+        this.appendDummyInput().appendField(Blockly.Msg.time_init_timer);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(timeColor);
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('type');
+            var TOOLTIPS = {
+                'on_esp32': Blockly.Msg.Esp32_Main_Controller_Time_Timer_Init_TOOLTIP.replace('%1', Blockly.Msg.time_iot_module),
+                'on_ai': Blockly.Msg.Esp32_Main_Controller_Time_Timer_Init_TOOLTIP.replace('%1', Blockly.Msg.time_ai_module)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
+};
+
+Blockly.Blocks['esp32_main_controller_time_timer_get_current'] = {
+    init: function () {
+        this.appendDummyInput().appendField(Blockly.Msg.time_timer_get_time);
+        this.setOutput(true, null);
+        this.setColour(timeColor);
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('type');
+            var TOOLTIPS = {
+                'on_esp32': Blockly.Msg.Esp32_Main_Controller_Time_Timer_Get_Current_TOOLTIP.replace('%1', Blockly.Msg.time_iot_module),
+                'on_ai': Blockly.Msg.Esp32_Main_Controller_Time_Timer_Get_Current_TOOLTIP.replace('%1', Blockly.Msg.time_ai_module)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
+};
+Blockly.Blocks['esp32_main_controller_time_timer_clear'] = {
+    init: function () {
+        this.appendDummyInput().appendField(Blockly.Msg.time_timer_clear);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(timeColor);
+        var thisBlock = this;
+        this.setTooltip(function () {
+            var mode = thisBlock.getFieldValue('type');
+            var TOOLTIPS = {
+                'on_esp32': Blockly.Msg.Esp32_Main_Controller_Time_Timer_Clear_TOOLTIP.replace('%1', Blockly.Msg.time_iot_module),
+                'on_ai': Blockly.Msg.Esp32_Main_Controller_Time_Timer_Clear_TOOLTIP.replace('%1', Blockly.Msg.time_ai_module)
+            };
+            return TOOLTIPS[mode];
+        });
+        this.setHelpUrl("");
+    }
+};
+Blockly.Blocks['esp32_main_controller_time_period_timer'] = {
+    init: function () {
+
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.time_timer_periodically);
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.time_timer_every)
+            .appendField(new Blockly.FieldTextInput("500"), "period_timer_count")
+            .appendField(Blockly.Msg.time_timer_ms);
+        this.appendStatementInput("exec_period_timer")
+            .setCheck(null)
+            .appendField(Blockly.Msg.time_execution);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(timeColor);
+        this.setTooltip(Blockly.Msg.Esp32_Main_Controller_Time_Period_Timer_TOOLTIP.replace('%1', "CocoPi"));
+        this.setHelpUrl("");
+    }
+};
+Blockly.Blocks['esp32_main_controller_time_period_timer_clear'] = {
+    init: function () {
+        this.appendDummyInput()
+            .appendField(Blockly.Msg.time_timer_periodically_clear);
+        this.setPreviousStatement(true, null);
+        this.setNextStatement(true, null);
+        this.setColour(timeColor);
+        this.setTooltip(Blockly.Msg.Esp32_Main_Controller_Time_Period_Timer_Clear_TOOLTIP.replace('%1', "CocoPi"));
+        this.setHelpUrl("");
+    }
+};
+
+export default Blockly;

+ 1 - 7
src/blockly/blocks/tuples.js

@@ -1,12 +1,6 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
+import * as Blockly from 'blockly';
 import CategoryColors from './define_color'
 
-Blockly.Python = pythonGenerator
-
-Blockly.tuples = {
-    HUE: CategoryColors['Tuples'],
-};
 Blockly.Blocks.tuple_create_with_items_insert = {
     init: function () {
         this.setHelpUrl(Blockly.Msg.TUPLE_CREATE_WITH_ITEMS_INSERT_HELPURL);

+ 18 - 54
src/blockly/blocks/variables.js

@@ -1,58 +1,22 @@
-import Blockly from 'blockly';
-import { pythonGenerator } from "blockly/python";
 
-Blockly.Python = pythonGenerator
+import * as Blockly from 'blockly';
 
 // variables
-Blockly.variables = {
-    HUE: "#ffab2f"
-}
+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);
-        this.setColour(Blockly.variables.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 = goog.dom.createDom("field", null, c);
-        c.setAttribute("name", "VAR");
-        c = goog.dom.createDom("block", null, c);
-        c.setAttribute("type", this.contextMenuType_);
-        b.callback = Blockly.ContextMenu.callbackFactory(this, c);
-        a.push(b)
+        VariableGet.init.call(this);
+        this.setColour(HUE);
     }
 };
 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: Blockly.variables.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);
+    }
 };
 
 
@@ -61,23 +25,23 @@ Blockly.Blocks.math_change = {
         this.jsonInit({
             message0: Blockly.Msg.MATH_CHANGE_TITLE,
             args0: [{
-                type: "field_variable",
-                name: "VAR",
+                type: 'field_variable',
+                name: 'VAR',
                 variable: Blockly.Msg.MATH_CHANGE_TITLE_ITEM
             }, {
-                type: "input_value",
-                name: "DELTA",
-                check: "Number"
+                type: 'input_value',
+                name: 'DELTA',
+                check: 'Number'
             }],
             previousStatement: null,
             nextStatement: null,
-            colour: Blockly.variables.HUE,
+            colour: HUE,
             helpUrl: Blockly.Msg.MATH_CHANGE_HELPURL
         });
         var a = this;
         this.setTooltip(function () {
-            return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace("%1", a.getField("VAR").variable.name)
-        })
+            return Blockly.Msg.MATH_CHANGE_TOOLTIP.replace('%1', a.getField('VAR').variable.name);
+        });
     }
 };
 

+ 374 - 17
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"] = "逻辑";
@@ -15,6 +17,27 @@ Blockly.Msg["catSet"] = "集合";
 Blockly.Msg["catFunctions"] = "函数";
 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"] = "获取天气";
+
 
 
 
@@ -1164,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 = "设置引脚 #";
@@ -1181,22 +1203,6 @@ Blockly.Msg.analog_get_value = "的模拟信号数值 (PWM)";
 Blockly.Msg.set_pin = "(范围:0 ~ 1023)";
 Blockly.Msg.Esp32_Main_Controller_Io_From_Analog_Pin_TOOLTIP = "模块获取特定引脚的模拟信号数值";
 
-Blockly.Msg.time_init_timer = "初始化计时器";
-Blockly.Msg.time_timer_get_time = "获取计时器已过时间(毫秒)";
-Blockly.Msg.time_timer_clear = "清除计时器";
-Blockly.Msg.time_timer_periodically = "启用周期重复计时器";
-Blockly.Msg.time_timer_every = "每隔";
-Blockly.Msg.time_timer_ms = "毫秒";
-Blockly.Msg.time_execution = "运行";
-Blockly.Msg.time_timer_periodically_clear = "清除周期重复计时器";
-
-Blockly.Msg.time_get_current_date_title = "获取本地时间:";
-Blockly.Msg.time_get_current_date_y = "年";
-Blockly.Msg.time_get_current_date_m = "月";
-Blockly.Msg.time_get_current_date_d = "日";
-Blockly.Msg.time_get_current_date_hour = "时";
-Blockly.Msg.time_get_current_date_min = "分";
-Blockly.Msg.time_get_current_date_sec = "秒";
 
 
 /*
@@ -1224,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 模块";
@@ -1241,6 +1248,7 @@ Blockly.Msg.serial_new_get_data_2 = "串口读取一行数据";
 Blockly.Msg.serial_new_get_data_3 = "串口读取数据";
 Blockly.Msg.serial_new_get_data_4 = "串口读取数据长度为";
 Blockly.Msg.serial_close = "关闭串口";
+Blockly.Msg.serial_clear_data = "清除串口数据";
 
 // 文件
 Blockly.Msg.SYSTEM = "重启系统";
@@ -1268,5 +1276,354 @@ Blockly.Msg.SYSTEM_WRITE_S_SE = "分号";
 Blockly.Msg.SYSTEM_INPUT = "读取文本文件为列表";
 Blockly.Msg.SYSTEM_INPUT_FILE = "读取文件为列表";
 
+// 时间
+Blockly.Msg.ARD_TIME_DELAY = "等待";
+Blockly.Msg.ARD_TIME_MS = "毫秒";
+Blockly.Msg.ARD_TIME_SECOND = "秒";
+Blockly.Msg.ARD_TIME_DELAY_TIP = "等待一定的时间(以毫秒为单位)";
+Blockly.Msg.ARD_TIME_DELAY_seconds_TIP = "等待一定的时间(以秒为单位)";
+Blockly.Msg.ARD_TIME_DELAY_seconds = "秒";
+Blockly.Msg.ARD_TIME_DO = "执行";
+Blockly.Msg.ARD_TIME_DO_MS = "执行";
+Blockly.Msg.ARD_TIME_EVERY = "每隔";
+
+Blockly.Msg.time_init_timer = "初始化计时器";
+Blockly.Msg.time_timer_get_time = "获取计时器已过时间(毫秒)";
+Blockly.Msg.time_timer_clear = "清除计时器";
+Blockly.Msg.time_timer_periodically = "启用周期重复计时器";
+Blockly.Msg.time_timer_every = "每隔";
+Blockly.Msg.time_timer_ms = "毫秒";
+Blockly.Msg.time_execution = "运行";
+Blockly.Msg.time_timer_periodically_clear = "清除周期重复计时器";
+Blockly.Msg.time_get_current_date_title = "获取本地时间:";
+Blockly.Msg.Esp32_Get_Current_Date_TOOLTIP = "获取本地时间的%1";
+Blockly.Msg.time_get_current_date_y = "年";
+Blockly.Msg.time_get_current_date_m = "月";
+Blockly.Msg.time_get_current_date_d = "日";
+Blockly.Msg.time_get_current_date_hour = "时";
+Blockly.Msg.time_get_current_date_min = "分";
+Blockly.Msg.time_get_current_date_sec = "秒";
+Blockly.Msg.Esp32_Main_Controller_Time_Timer_Init_TOOLTIP = "%1初始化计时器";
+Blockly.Msg.Esp32_Main_Controller_Time_Timer_Get_Current_TOOLTIP = "%1获取计时器已过时间";
+Blockly.Msg.Esp32_Main_Controller_Time_Timer_Clear_TOOLTIP = "%1清除计时器";
+Blockly.Msg.Esp32_Main_Controller_Time_Period_Timer_TOOLTIP = "%1启用周期重复计时器,并隔一定的时间运行指定的条件";
+Blockly.Msg.Esp32_Main_Controller_Time_Period_Timer_Clear_TOOLTIP = "%1清除周期重复计时器";
+
+
+// 串口
+Blockly.Msg.serial_Comm_Print_TOOLTIP = "串口打印";
+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

+ 73 - 72
src/blockly/pythonCode/basicCode.js

@@ -3,34 +3,34 @@ import { pythonGenerator } from "blockly/python";
 const Blockly = {
     Python: pythonGenerator || { Msg: Object.create(null) }
 };
-Blockly.Python['math_degrad'] = function (block) {
-    var dropdown_rad_deg = block.getFieldValue('rad_deg');
-    var value_convert = Blockly.Python.valueToCode(block, 'convert', Blockly.Python.ORDER_ATOMIC);
+Blockly.Python.forBlock["math_degrad"] = function (block) {
+    var dropdown_rad_deg = block.getFieldValue("rad_deg");
+    var value_convert = Blockly.Python.valueToCode(block, "convert", Blockly.Python.ORDER_ATOMIC);
     // TODO: Assemble Python into code variable.
-    Blockly.Python.definitions_['import_math'] = 'import math\n';
+    Blockly.Python.definitions_["import_math"] = "import math\n";
 
-    var code = 'math.' + dropdown_rad_deg + '(' + value_convert + ')';
+    var code = "math." + dropdown_rad_deg + "(" + value_convert + ")";
     // TODO: Change ORDER_NONE to the correct strength.
     return [code, Blockly.Python.ORDER_NONE];
 };
 
-Blockly.Python.math_angle = function (a) {
-    return [a.getFieldValue("angle"), Blockly.Python.ORDER_ATOMIC]
+Blockly.Python.forBlock.math_angle = function (a) {
+    return [a.getFieldValue("angle"), Blockly.Python.ORDER_ATOMIC];
 };
 
-Blockly.Python.math_keep_decimal = function (a) {
+Blockly.Python.forBlock.math_keep_decimal = function (a) {
     var b = Blockly.Python.valueToCode(a, "NUM", Blockly.Python.ORDER_ATOMIC);
     a = Blockly.Python.valueToCode(a, "PLACE", Blockly.Python.ORDER_ATOMIC);
-    return ["round(" + b + ", " + a + ")", Blockly.Python.ORDER_ATOMIC]
+    return ["round(" + b + ", " + a + ")", Blockly.Python.ORDER_ATOMIC];
 };
 
-Blockly.Python.math_division_consult = function (a) {
+Blockly.Python.forBlock.math_division_consult = function (a) {
     var b = Blockly.Python.valueToCode(a, "DIVIDEND", Blockly.Python.ORDER_MULTIPLICATIVE) || "0";
     a = Blockly.Python.valueToCode(a, "DIVISOR", Blockly.Python.ORDER_MULTIPLICATIVE) || "0";
-    return [b + " // " + a, Blockly.Python.ORDER_MULTIPLICATIVE]
-}
+    return [b + " // " + a, Blockly.Python.ORDER_MULTIPLICATIVE];
+};
 
-Blockly.Python.labplus_mapping = function (a) {
+Blockly.Python.forBlock.labplus_mapping = function (a) {
     Blockly.Python.definitions_.import_microbit = "from microbit import *";
     var b = Blockly.Python.valueToCode(a, "inputNum", Blockly.Python.ORDER_ATOMIC);
     Blockly.Python.valueToCode(a, "outputNum", Blockly.Python.ORDER_ATOMIC);
@@ -39,133 +39,134 @@ Blockly.Python.labplus_mapping = function (a) {
         , e = Blockly.Python.valueToCode(a, "cMin", Blockly.Python.ORDER_ATOMIC);
     a = Blockly.Python.valueToCode(a, "cMax", Blockly.Python.ORDER_ATOMIC);
     Blockly.Python.definitions_.labplus_mapping = "def numberMap(inputNum,bMin,bMax,cMin,cMax):\n  outputNum \x3d 0\n  outputNum \x3d((cMax - cMin) / (bMax - bMin))*(inputNum - bMin)+cMin\n  return outputNum\n";
-    return ["numberMap(" + b + "," + c + "," + d + "," + e + "," + a + ")", Blockly.Python.ORDER_ATOMIC]
-}
+    return ["numberMap(" + b + "," + c + "," + d + "," + e + "," + a + ")", Blockly.Python.ORDER_ATOMIC];
+};
 
-Blockly.Python.math_random_randrange = function (a) {
+Blockly.Python.forBlock.math_random_randrange = function (a) {
     Blockly.Python.definitions_.import_time = "import time";
     // Blockly.Python.codeFunctions_.random_seed = "random.seed(time.ticks_cpu())";
     Blockly.Python.definitions_.import_random = "import random";
     var b = Blockly.Python.valueToCode(a, "start", Blockly.Python.ORDER_ATOMIC),
         c = Blockly.Python.valueToCode(a, "stop", Blockly.Python.ORDER_ATOMIC);
     a = Blockly.Python.valueToCode(a, "step", Blockly.Python.ORDER_ATOMIC);
-    return ["random.randrange(" + b + ", " + c + ", " + a + ")", Blockly.Python.ORDER_ATOMIC]
+    return ["random.randrange(" + b + ", " + c + ", " + a + ")", Blockly.Python.ORDER_ATOMIC];
 };
 
-Blockly.Python.bit_inversion = function (a) {
-    return ["~" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC), Blockly.Python.ORDER_ATOMIC]
+Blockly.Python.forBlock.bit_inversion = function (a) {
+    return ["~" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC), Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_ten_convert_to = function (a) {
+Blockly.Python.forBlock.CocoRobo_ten_convert_to = function (a) {
     var b = Blockly.Python.valueToCode(a, "int_num", Blockly.Python.ORDER_ATOMIC);
-    return [a.getFieldValue("ten_convert_to") + "(" + b + ")", Blockly.Python.ORDER_ATOMIC]
+    return [a.getFieldValue("ten_convert_to") + "(" + b + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_convert_to_ten = function (a) {
+Blockly.Python.forBlock.CocoRobo_convert_to_ten = function (a) {
     var b = Blockly.Python.valueToCode(a, "convert_str", Blockly.Python.ORDER_ATOMIC);
     a = a.getFieldValue("convert_choice");
-    return ["int(" + b + ", " + a + ")", Blockly.Python.ORDER_ATOMIC]
+    return ["int(" + b + ", " + a + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_ten_convert_to = function (a) {
+Blockly.Python.forBlock.CocoRobo_ten_convert_to = function (a) {
     var b = Blockly.Python.valueToCode(a, "int_num", Blockly.Python.ORDER_ATOMIC);
-    return [a.getFieldValue("ten_convert_to") + "(" + b + ")", Blockly.Python.ORDER_ATOMIC]
+    return [a.getFieldValue("ten_convert_to") + "(" + b + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_high_low = function (a) {
-    return [a.getFieldValue("high_low"), Blockly.Python.ORDER_ATOMIC]
+Blockly.Python.forBlock.CocoRobo_high_low = function (a) {
+    return [a.getFieldValue("high_low"), Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_baudrate = function (a) {
-    return [a.getFieldValue("baudrate"), Blockly.Python.ORDER_ATOMIC]
+Blockly.Python.forBlock.CocoRobo_baudrate = function (a) {
+    return [a.getFieldValue("baudrate"), Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_start_new_thread = function (a) {
+Blockly.Python.forBlock.CocoRobo_start_new_thread = function (a) {
     Blockly.Python.definitions_.import_thread = "import _thread";
     var b = a.getFieldValue("thread_name"),
         c = Blockly.Python.statementToCode(a, "DO"),
+        // eslint-disable-next-line no-redeclare
         c = Blockly.Python.addLoopTrap(c, a.id) || Blockly.Python.PASS;
     Blockly.Python.codeFunctions_["thread_" + b] = "def thread_" + b + "():\n" + c;
-    return "_thread.start_new_thread(thread_" + b + ", ())\n"
+    return "_thread.start_new_thread(thread_" + b + ", ())\n";
 };
 
-Blockly.Python.CocoRobo_ten_converted_to_bytes = function (a) {
+Blockly.Python.forBlock.CocoRobo_ten_converted_to_bytes = function (a) {
     Blockly.Python.definitions_.import_struct = "import struct";
     var b = Blockly.Python.valueToCode(a, "convert_num", Blockly.Python.ORDER_ATOMIC);
-    return ["struct.pack(" + a.getFieldValue("convert_choice") + ", " + b + ")", Blockly.Python.ORDER_ATOMIC]
+    return ["struct.pack(" + a.getFieldValue("convert_choice") + ", " + b + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_int_to_chr = function (a) {
-    return ["chr(" + Blockly.Python.valueToCode(a, "convert_num", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC]
+Blockly.Python.forBlock.CocoRobo_int_to_chr = function (a) {
+    return ["chr(" + Blockly.Python.valueToCode(a, "convert_num", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_hcsr04_obj = function (a) {
+Blockly.Python.forBlock.CocoRobo_hcsr04_obj = function (a) {
     Blockly.Python.definitions_.from_hcsr04_import_HCSR04 = "from hcsr04 import HCSR04";
     //Blockly.Python.definitions_.import_CocoRobo = "from CocoRobo import *";
     var b = a.getFieldValue("hcsr04_name"),
         c = Blockly.Python.valueToCode(a, "trigger", Blockly.Python.ORDER_ATOMIC);
     a = Blockly.Python.valueToCode(a, "echo", Blockly.Python.ORDER_ATOMIC);
     Blockly.Python.definitions_["CocoRobo_hcsr04_object" + b] = b + " \x3d HCSR04(trigger_pin\x3dPin.P" + c + ", echo_pin\x3dPin.P" + a + ")";
-    return "\n"
+    return "\n";
 };
-Blockly.Python.CocoRobo_hcsr04_distance = function (a) {
+Blockly.Python.forBlock.CocoRobo_hcsr04_distance = function (a) {
     Blockly.Python.definitions_.from_hcsr04_import_HCSR04 = "from hcsr04 import HCSR04";
     //Blockly.Python.definitions_.import_CocoRobo = "from CocoRobo import *";
     var b = a.getFieldValue("hcsr04_name");
     a = a.getFieldValue("unit");
-    return [b + ".distance_" + a + "()", Blockly.Python.ORDER_ATOMIC]
+    return [b + ".distance_" + a + "()", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_hcsr04_distance_mm = function (a) {
+Blockly.Python.forBlock.CocoRobo_hcsr04_distance_mm = function (a) {
     Blockly.Python.definitions_.from_hcsr04_import_HCSR04 = "from hcsr04 import HCSR04";
     //Blockly.Python.definitions_.import_CocoRobo = "from CocoRobo import *";
-    return [a.getFieldValue("hcsr04_name") + ".distance_mm()", Blockly.Python.ORDER_ATOMIC]
+    return [a.getFieldValue("hcsr04_name") + ".distance_mm()", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_pm2_5_MIC = function (a) {
+Blockly.Python.forBlock.CocoRobo_pm2_5_MIC = function (a) {
     //Blockly.Python.definitions_.import_CocoRobo = "from CocoRobo import *";
     Blockly.Python.definitions_.machine_Timer = "from machine import Timer";
     var b = Blockly.Python.valueToCode(a, "rx", Blockly.Python.ORDER_ATOMIC);
     Blockly.Python.codeFunctions_.CocoRobo_pm2_5 = "uart\x3dUART(1, baudrate\x3d9600, rx\x3dPin.P" + b + ", timeout\x3d200)\n_pm_data \x3d [None, None, None, None, None, None, None, None, None]\ndef timer13_tick(_):\n  global _pm_data\n  try:\n      if uart.any():\n          d \x3d uart.read(0x42)\n          if d[0] \x3d\x3d 0x42 and d[1] \x3d\x3d 0x4d:\n              _pm_data \x3d [d[5], d[7], d[9], d[17], d[19], d[21], d[23], d[25], d[27]]\n  except: pass\n\ntim13 \x3d Timer(13)\ntim13.init(period\x3d1000, mode\x3dTimer.PERIODIC, callback\x3dtimer13_tick)";
-    return [a.getFieldValue("unit"), Blockly.Python.ORDER_ATOMIC]
+    return [a.getFieldValue("unit"), Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_pm2_5_LitresAir = function (a) {
+Blockly.Python.forBlock.CocoRobo_pm2_5_LitresAir = function (a) {
     //Blockly.Python.definitions_.import_CocoRobo = "from CocoRobo import *";
     Blockly.Python.definitions_.machine_Timer = "from machine import Timer";
     var b = Blockly.Python.valueToCode(a, "rx", Blockly.Python.ORDER_ATOMIC);
     Blockly.Python.codeFunctions_.CocoRobo_pm2_5 = "uart\x3dUART(1, baudrate\x3d9600, rx\x3dPin.P" + b + ", timeout\x3d200)\n_pm_data \x3d [None, None, None, None, None, None, None, None, None]\ndef timer13_tick(_):\n  global _pm_data\n  try:\n      if uart.any():\n          d \x3d uart.read(0x42)\n          if d[0] \x3d\x3d 0x42 and d[1] \x3d\x3d 0x4d:\n              _pm_data \x3d [d[5], d[7], d[9], d[17], d[19], d[21], d[23], d[25], d[27]]\n  except: pass\n\ntim13 \x3d Timer(13)\ntim13.init(period\x3d1000, mode\x3dTimer.PERIODIC, callback\x3dtimer13_tick)";
-    return [a.getFieldValue("unit"), Blockly.Python.ORDER_ATOMIC]
+    return [a.getFieldValue("unit"), Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_mac_address = function (a) {
+Blockly.Python.forBlock.CocoRobo_mac_address = function (a) {
     Blockly.Python.definitions_.import_machine = "import machine";
     Blockly.Python.definitions_.import_ubinascii = "import ubinascii";
-    return ["ubinascii.hexlify(machine.unique_id()).decode().upper()", Blockly.Python.ORDER_ATOMIC]
+    return ["ubinascii.hexlify(machine.unique_id()).decode().upper()", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_ujson_loads = function (a) {
+Blockly.Python.forBlock.CocoRobo_ujson_loads = function (a) {
     Blockly.Python.definitions_.import_ujson = "import json";
-    return ["json.loads(" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC]
+    return ["json.loads(" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_code_annotation = function (a) {
+Blockly.Python.forBlock.CocoRobo_code_annotation = function (a) {
     var code = Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC);
-    return "# " + code.replace('"', '').replace('"', '') + "\n";
+    return "# " + code.replace("\"", "").replace("\"", "") + "\n";
 };
-Blockly.Python.CocoRobo_ujson_dumps = function (a) {
+Blockly.Python.forBlock.CocoRobo_ujson_dumps = function (a) {
     Blockly.Python.definitions_.import_ujson = "import json";
-    return ["json.dumps(" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC]
+    return ["json.dumps(" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_base64_to_data = function (a) {
+Blockly.Python.forBlock.CocoRobo_base64_to_data = function (a) {
     Blockly.Python.definitions_.v831_import_base64 = "import base64";
-    return ["base64.b64decode(" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC]
+    return ["base64.b64decode(" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_data_to_base64 = function (a) {
+Blockly.Python.forBlock.CocoRobo_data_to_base64 = function (a) {
     Blockly.Python.definitions_.v831_import_base64 = "import base64";
-    return ["base64.b64encode(" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC) + ".encode('utf-8'))", Blockly.Python.ORDER_ATOMIC]
+    return ["base64.b64encode(" + Blockly.Python.valueToCode(a, "data", Blockly.Python.ORDER_ATOMIC) + ".encode('utf-8'))", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_hex_to_bin_str = function (a) {
-    return ["bytes.fromhex(" + Blockly.Python.valueToCode(a, "convert_chr", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC]
+Blockly.Python.forBlock.CocoRobo_hex_to_bin_str = function (a) {
+    return ["bytes.fromhex(" + Blockly.Python.valueToCode(a, "convert_chr", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_str_to_hex = function (a) {
-    return [Blockly.Python.valueToCode(a, "convert_chr", Blockly.Python.ORDER_ATOMIC) + ".encode().hex()", Blockly.Python.ORDER_ATOMIC]
+Blockly.Python.forBlock.CocoRobo_str_to_hex = function (a) {
+    return [Blockly.Python.valueToCode(a, "convert_chr", Blockly.Python.ORDER_ATOMIC) + ".encode().hex()", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.CocoRobo_chr_to_int = function (a) {
-    return ["ord(" + Blockly.Python.valueToCode(a, "convert_chr", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC]
+Blockly.Python.forBlock.CocoRobo_chr_to_int = function (a) {
+    return ["ord(" + Blockly.Python.valueToCode(a, "convert_chr", Blockly.Python.ORDER_ATOMIC) + ")", Blockly.Python.ORDER_ATOMIC];
 };
-Blockly.Python.math_convert = function (a) {
+Blockly.Python.forBlock.math_convert = function (a) {
     var b = a.getFieldValue("TYPE0");
     a = Blockly.Python.valueToCode(a, "INPUT0", Blockly.Python.ORDER_ATOMIC);
-    return [b + "(" + a + ")", Blockly.Python.ORDER_FUNCTION_CALL]
+    return [b + "(" + a + ")", Blockly.Python.ORDER_FUNCTION_CALL];
 };
-Blockly.Python.math_number_bits_ops = function (a) {
+Blockly.Python.forBlock.math_number_bits_ops = function (a) {
     var b = {
         " | ": [" | ", Blockly.Python.ORDER_BITWISE_OR],
         " & ": [" & ", Blockly.Python.ORDER_BITWISE_AND],
@@ -177,12 +178,12 @@ Blockly.Python.math_number_bits_ops = function (a) {
     b = b[1];
     var d = Blockly.Python.valueToCode(a, "A", b) || "0";
     a = Blockly.Python.valueToCode(a, "B", b) || "0";
-    return [d + c + a, b]
-}
+    return [d + c + a, b];
+};
 
-Blockly.Python.controls_repeat_forever = function (a) {
+Blockly.Python.forBlock.controls_repeat_forever = function (a) {
     var b = Blockly.Python.statementToCode(a, "DO");
     b = Blockly.Python.addLoopTrap(b, a.id) || Blockly.Python.PASS;
-    return "while True:\n" + b
-}
-export default Blockly
+    return "while True:\n" + b;
+};
+export default Blockly;

+ 1 - 1
src/blockly/pythonCode/file.js

@@ -1,6 +1,6 @@
 import { pythonGenerator } from "blockly/python";
 // import Blockly from "./python";
-Blockly.Python = pythonGenerator || { Msg: Object.create(null) }
+const Blockly = { Python: pythonGenerator || { Msg: Object.create(null) } }
 
 Blockly.Python.iot_system_run = function (block) {
     var _path = Blockly.Python.valueToCode(block, 'PATH', Blockly.Python.ORDER_ATOMIC);

+ 35 - 0
src/blockly/pythonCode/generator.js

@@ -0,0 +1,35 @@
+/**
+ * @license
+ *
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview Define generation methods for custom blocks.
+ * @author samelh@google.com (Sam El-Husseini)
+ */
+
+// More on generating code:
+// https://developers.google.com/blockly/guides/create-custom-blocks/generating-code
+
+import {javascriptGenerator} from 'blockly/javascript';
+
+javascriptGenerator.forBlock['test_react_field'] = function (block) {
+  return "console.log('custom block');\n";
+};
+
+javascriptGenerator.forBlock['test_react_date_field'] = function (block) {
+  return 'console.log(' + block.getField('DATE').getText() + ');\n';
+};

+ 15 - 13
src/blockly/pythonCode/index.js

@@ -1,16 +1,18 @@
-import basicCode from './basicCode'
-import logic from './logic'
-import text from './text'
-import list from './list'
-import dictionary from './dictionary'
-import tuples from './tuples'
-import set from './set'
-import output from './output'
-import file from './file'
+import basicCode from './basicCode';
+import logic from './logic';
+import text from "./text";
+import list from "./list";
+import dictionary from "./dictionary";
+import tuples from "./tuples";
+import set from "./set";
+import output from "./output";
+import file from "./file";
+import time from "./time";
+import serial from "./serial";
 
 const python = {
-    ...basicCode,...logic,...text,...list
-    ,...dictionary, ...tuples,...set,...output,...file
-}
+    ...basicCode,...logic,...text,...list,...dictionary,...tuples,...set,...output,...file,
+    ...time,...serial
+};
 
-export default python
+export default python;

+ 1 - 0
src/blockly/pythonCode/list.js

@@ -1,3 +1,4 @@
+/* eslint-disable no-unused-expressions */
 import { pythonGenerator } from "blockly/python";
 
 const Blockly = {

+ 15 - 15
src/blockly/pythonCode/logic.js

@@ -1,31 +1,31 @@
-import { pythonGenerator } from "blockly/python";
+import { pythonGenerator } from 'blockly/python';
 
 const Blockly = {
     Python: pythonGenerator || { Msg: Object.create(null) }
 };
 Blockly.Python.CocoRobo_type = function(a) {
-    return ["type(" + (Blockly.Python.valueToCode(a, "VAR", Blockly.Python.ORDER_ATOMIC) || "None") + ")", Blockly.Python.ORDER_ATOMIC]
+    return ['type(' + (Blockly.Python.valueToCode(a, 'VAR', Blockly.Python.ORDER_ATOMIC) || 'None') + ')', Blockly.Python.ORDER_ATOMIC];
 };
 Blockly.Python.CocoRobo_type_is = function(a) {
-    var b = Blockly.Python.valueToCode(a, "VAR", Blockly.Python.ORDER_ATOMIC) || "None";
-    a = a.getFieldValue("TYPE");
-    return ["type(" + b + ") \x3d\x3d " + a, Blockly.Python.ORDER_ATOMIC]
+    var b = Blockly.Python.valueToCode(a, 'VAR', Blockly.Python.ORDER_ATOMIC) || 'None';
+    a = a.getFieldValue('TYPE');
+    return ['type(' + b + ') \x3d\x3d ' + a, Blockly.Python.ORDER_ATOMIC];
 };
 Blockly.Python.CocoRobo_eval = function(a) {
-    return ["eval(" + (Blockly.Python.valueToCode(a, "VAR", Blockly.Python.ORDER_ATOMIC) || "None") + ")", Blockly.Python.ORDER_ATOMIC]
+    return ['eval(' + (Blockly.Python.valueToCode(a, 'VAR', Blockly.Python.ORDER_ATOMIC) || 'None') + ')', Blockly.Python.ORDER_ATOMIC];
 };
 Blockly.Python.CocoRobo_return = function(a) {
-    return "return " + (Blockly.Python.valueToCode(a, "VAR", Blockly.Python.ORDER_ATOMIC) || "None") + "\n"
+    return 'return ' + (Blockly.Python.valueToCode(a, 'VAR', Blockly.Python.ORDER_ATOMIC) || 'None') + '\n';
 };
 Blockly.Python.CocoRobo_try_except = function(a) {
-    var b = Blockly.Python.statementToCode(a, "TRY") || Blockly.Python.PASS;
-    a = Blockly.Python.statementToCode(a, "EXCEPT") || Blockly.Python.PASS;
-    return "try:\n" + b + "except:\n" + a
+    var b = Blockly.Python.statementToCode(a, 'TRY') || Blockly.Python.PASS;
+    a = Blockly.Python.statementToCode(a, 'EXCEPT') || Blockly.Python.PASS;
+    return 'try:\n' + b + 'except:\n' + a;
 };
 Blockly.Python.CocoRobo_try_except_finally = function(a) {
-    var b = Blockly.Python.statementToCode(a, "TRY") || Blockly.Python.PASS,
-        c = Blockly.Python.statementToCode(a, "EXCEPT") || Blockly.Python.PASS;
-    a = Blockly.Python.statementToCode(a, "FINALLY") || Blockly.Python.PASS;
-    return "try:\n" + b + "except:\n" + c + "finally:\n" + a
+    var b = Blockly.Python.statementToCode(a, 'TRY') || Blockly.Python.PASS,
+        c = Blockly.Python.statementToCode(a, 'EXCEPT') || Blockly.Python.PASS;
+    a = Blockly.Python.statementToCode(a, 'FINALLY') || Blockly.Python.PASS;
+    return 'try:\n' + b + 'except:\n' + c + 'finally:\n' + a;
 };
-export default Blockly
+export default Blockly;

+ 1 - 1
src/blockly/pythonCode/output.js

@@ -1,6 +1,6 @@
 import { pythonGenerator } from "blockly/python";
 // import Blockly from "./python";
-Blockly.Python = pythonGenerator || { Msg: Object.create(null) }
+const Blockly = { Python: pythonGenerator || { Msg: Object.create(null) } }
 
 Blockly.Python['esp32_main_controller_io_from_digital_pin'] = function (block) {
     var value_name = Blockly.Python.valueToCode(block, 'digital_pin_input', Blockly.Python.ORDER_ATOMIC);

+ 1 - 2
src/blockly/pythonCode/python.js

@@ -1,7 +1,6 @@
-import Blockly from 'blockly';
 import { pythonGenerator } from "blockly/python";
 
-Blockly.Python = pythonGenerator || { Msg: Object.create(null) }
+const Blockly = { Python: pythonGenerator || { Msg: Object.create(null) } }
 
 Blockly.Variables = {};
 

+ 129 - 0
src/blockly/pythonCode/serial.js

@@ -0,0 +1,129 @@
+import * as Blockly from 'blockly';
+import { pythonGenerator } from "blockly/python";
+
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) }
+
+
+Blockly.Python['serial_comm_print'] = function (block) {
+    var value_name = Blockly.Python.valueToCode(block, 'serial_comm_input', Blockly.Python.ORDER_ATOMIC);
+    // TODO: Assemble Python into code variable.
+    var code = 'print(' + value_name + ')\n';
+    return code;
+};
+
+Blockly.Python['serial_write_data'] = function (block) {
+    // var api = block.getFieldValue('t_api');
+    var number_uart_bps = block.getFieldValue('uart_bps');
+    var ai_uart_data = Blockly.Python.valueToCode(this, "ADD1", Blockly.Python.ORDER_NONE);
+    Blockly.Python.definitions_['v831_import_serial'] = `import serial
+SERIAL = serial.Serial("/dev/ttyS1",${number_uart_bps})
+    `
+    var code = `uart_data = bytes(str(${ai_uart_data})+"\\n","utf-8")
+SERIAL.write(uart_data)
+`
+    return code;
+};
+Blockly.Python['serial_write_data_coco'] = function (block) {
+    // var api = block.getFieldValue('t_api');
+    var number_uart_bps = block.getFieldValue('uart_bps');
+    var item_value = '';
+    var ai_uart_data = "";
+    for (var n = 0; n < this.itemCount_; n++) {
+        item_value = Blockly.Python.valueToCode(this, 'ADD' + n, Blockly.Python.ORDER_NONE) || '';
+        ai_uart_data += 'str(' + item_value + ') + \"|\" + ';
+    }
+    var ai_uart_data_final = ai_uart_data + "";
+    Blockly.Python.definitions_['v831_import_serial'] = `import serial
+SERIAL = serial.Serial("/dev/ttyS1",${number_uart_bps})
+    `
+
+    var code = `uart_data = bytes("SOF|"+${ai_uart_data_final.slice(0, -8)}+"|\\r\\n","utf-8")
+SERIAL.write(uart_data)
+`
+    return code;
+};
+Blockly.Python['serial_read_data_setup'] = function (block) {
+    var number_uart_bps = block.getFieldValue('uart_bps');
+    // TODO: Assemble Python into code variable.
+    Blockly.Python.definitions_['v831_import_serial'] = `import serial
+SERIAL = serial.Serial("/dev/ttyS1",${number_uart_bps})
+`;
+    Blockly.Python.definitions_['_read_serial_data'] = `def _read_serial_data(read_data,split, index):
+    if read_data != None:
+        read_str = ""
+        try:
+            read_str = str(read_data.decode("utf-8")).split(split)[index]
+        except:
+            read_str = str(read_data).split(split)[index]
+        return read_str
+`
+    var code = "";
+    return code;
+};
+
+Blockly.Python['serial_read_data_all'] = function (block) {
+    var code = `SERIAL.readline().decode("UTF-8","ignore").strip()`;
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+
+Blockly.Python['serial_read_data'] = function (block) {
+    var index = parseInt(block.getFieldValue("INDEX")) + 1;
+    // var type = block.getFieldValue("TYPE")
+    // var type_1 = block.getFieldValue("TYPE_1")
+    Blockly.Python.definitions_['_read_serial_data'] = `def _read_serial_data(read_data,split, index):
+    if read_data != None:
+        read_str = ""
+        try:
+            read_str = str(read_data.decode("utf-8")).split(split)[index]
+        except:
+            read_str = str(read_data).split(split)[index]
+        return read_str
+`
+    var code = `_read_serial_data(SERIAL.readline().decode("UTF-8","ignore").strip(),"|",${index})`;
+
+    return [code, Blockly.Python.ORDER_NONE];
+};
+Blockly.Python['serial_send_data_to_microbit'] = function (block) {
+    var value_name = Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_ATOMIC) || "";
+    // TODO: Assemble Python into code variable.
+
+    Blockly.Python.definitions_["831_import_serial"] = `import serial
+SERIAL = serial.Serial("/dev/ttyS1",115200)`
+    var code = `uart_data = bytes(${value_name}+"\\n","utf-8")
+SERIAL.write(uart_data)
+`;
+    return code
+
+};
+Blockly.Python['serial_send_data_to_arduino'] = function (block) {
+    var number_uart_bps = block.getFieldValue('uart_bps');
+    var value_name = Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_ATOMIC) || "";
+    // TODO: Assemble Python into code variable.
+    Blockly.Python.definitions_["v831_import_os"] = `import os`
+    Blockly.Python.definitions_["v831_import_serial_ardino_read"] = `import serial
+SERIALPATH = "/dev/ttyUSB0" if os.path.exists("/dev/ttyUSB0") else "/dev/ttyACM0"
+SERIAL = serial.Serial(SERIALPATH,${number_uart_bps})`
+    var code = `uart_data = bytes(${value_name}+"\\n","utf-8")
+SERIAL.write(uart_data)
+`;
+    return code
+};
+
+Blockly.Python['serial_send_data_to_control_panel'] = function (block) {
+    var value_name = Blockly.Python.valueToCode(block, 'NAME', Blockly.Python.ORDER_ATOMIC) || "";
+    // TODO: Assemble Python into code variable.
+    Blockly.Python.definitions_["831_import_serial"] = `import serial
+SERIAL = serial.Serial("/dev/ttyS1",9600)`
+    var code = `uart_data = bytes(${value_name}+"\\n","utf-8")
+SERIAL.write(uart_data)
+`;
+    return code;
+};
+
+Blockly.Python['serial_read_data_clear'] = function (block) {
+    // TODO: Assemble Python into code variable.
+    var code = "SERIAL.flushInput()\n";
+    return code;
+};
+export default Blockly;

+ 0 - 1
src/blockly/pythonCode/text.js

@@ -49,7 +49,6 @@ Blockly.Python.text_format2 = function (a) {
     return [b + ".format" + a, Blockly.Python.ORDER_ATOMIC]
 };
 Blockly.Python.CocoRobo_text_ESC = function (a) {
-    // Blockly.Python.definitions_.import_usocket = "import usocket";
     return ['"' + a.getFieldValue("mode") + '"', Blockly.Python.ORDER_ATOMIC]
 };
 Blockly.Python.text_append_text = function (a) {

+ 127 - 0
src/blockly/pythonCode/time.js

@@ -0,0 +1,127 @@
+import * as Blockly from 'blockly';
+import { pythonGenerator } from "blockly/python";
+
+Blockly.Python = pythonGenerator || { Msg: Object.create(null) }
+
+
+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 + '/1000);\n';
+    return code;
+};
+
+
+Blockly.Python['time_delayseconds'] = function(block) {
+    // var time_type = block.getFieldValue('type');
+
+    Blockly.Python.definitions_['import_time'] = 'import time';
+    var delayTimeMs = Blockly.Python.valueToCode(
+        block, 'DELAY_TIME_MICRO', Blockly.Python.ORDER_ATOMIC) || '0';
+    var code = 'time.sleep(' + delayTimeMs + ')\n';
+
+    return code;
+};
+
+Blockly.Python['esp32_get_current_date'] = function (block) {
+    var dropdown_type = block.getFieldValue('type');
+
+    // Blockly.Python.definitions_['v831_import_time'] = `from datetime import date`
+    Blockly.Python.definitions_['import_datetime_datetime'] = `from datetime import datetime`
+    Blockly.Python.definitions_['get_current_date'] = `def getCurrent_data(type):
+    now = datetime.now()
+    return now.strftime("%"+type+"")
+`
+    // TODO: Assemble Python into code variable.
+    var code = `getCurrent_data("${dropdown_type}")`
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_NONE];
+};
+
+Blockly.Python['esp32_main_controller_time_timer_init'] = function (block) {
+    var timer_type = block.getFieldValue('type');
+
+    Blockly.Python.definitions_['import_time'] = `import time`
+    Blockly.Python.definitions_['counter_start_variable'] = `counter_start = 0 
+def counter_start_fun():
+    global counter_start
+    counter_start = time.perf_counter()
+`;
+    var code = `counter_start_fun() \n`;
+    return code;
+};
+
+Blockly.Python['esp32_main_controller_time_timer_get_current'] = function (block) {
+    Blockly.Python.definitions_['counter_end'] = `def getcounterEndStart(newDate):
+    global counter_start
+    return newDate - counter_start
+`
+    var code = `getcounterEndStart(time.perf_counter())`;
+    // TODO: Change ORDER_NONE to the correct strength.
+    return [code, Blockly.Python.ORDER_CONDITIONAL];
+};
+
+Blockly.Python['esp32_main_controller_time_timer_clear'] = function (block) {
+    var code = `del counter_start
+`;
+    return code;
+};
+
+Blockly.Python['esp32_main_controller_time_period_timer'] = function (block) {
+    var text_period_timer_count = block.getFieldValue('period_timer_count') * 0.001;
+    var statements_name = Blockly.Python.statementToCode(block, 'exec_period_timer');
+    Blockly.Python.addVariable("STOPTHREAD", "STOPTHREAD = False", true)
+    Blockly.Python.definitions_['import_threading'] = `import threading`
+    Blockly.Python.definitions_['import_time'] = `import time`
+    
+    let global = ""
+    try {
+        let allBlocks = Blockly.getMainWorkspace().variableMap.getAllVariableNames()
+        global = allBlocks.join()
+    }
+    catch (e) {
+        console.log(e)
+    }
+    Blockly.Python.definitions_['v831_import_thread_calsss'] = `def period_timer_count(n: int):
+    global STOPTHREAD
+    while True:
+        if STOPTHREAD:
+            break
+        time.sleep(${text_period_timer_count})
+        thread_calsss_fun_timer()
+`
+    Blockly.Python.definitions_['v831_import_thread_calsss_fun'] = `def thread_calsss_fun_timer():
+    global ${global}
+${statements_name}
+`
+    var code = `CocoPiThread = threading.Thread(target=period_timer_count, args=(1,))
+CocoPiThread.start()
+`
+    return code;
+};
+
+Blockly.Python['esp32_main_controller_time_period_timer_clear'] = function (block) {
+    var code = `STOPTHREAD = True
+`
+    return code;
+};
+
+Blockly.Python.addVariable = function (varName, code, overwrite) {
+  var overwritten = false;
+  if (overwrite || (Blockly.Python.variableDB_.dbReverse_[varName] === undefined)) {
+    Blockly.Python.definitions_[varName] = code;
+    // 创建变量并生成对应的变量积木
+    if (Blockly && Blockly.Variables && Blockly.getMainWorkspace) {
+      const workspace = Blockly.getMainWorkspace();
+      if (workspace && !workspace.getVariable(varName)) {
+        // Blockly.Python.variables_[varName] = code;
+        workspace.createVariable(varName);
+      }
+    }
+    overwritten = true;
+  }
+  return overwritten;
+};
+
+export default Blockly;

+ 66 - 0
src/components/BlocklyComponent.css

@@ -0,0 +1,66 @@
+#blocklyDiv {
+  height: 100%;
+  width: 100%;
+}
+
+.blocklyTreeIconOpen,
+.blocklyTreeIconClosed {
+  opacity: 0;
+}
+
+.blocklyTreeRow {
+  height: 40px;
+  line-height: 40px;
+  padding: 0px 16px 0px 0px;
+  text-align: left;
+  margin-bottom: 1px;
+}
+
+.blocklyToolboxDiv {
+  border-color: #fcfcfc !important;
+  border-width: 0px 1px 0px 0px !important;
+  -webkit-border-radius: 0px 4px 4px 0px !important;
+  -moz-border-radius: 4px 4px 0px 0px !important;
+  border-radius: 0px 4px 4px 0px !important;
+  border: none !important;
+  margin: 0px !important;
+  padding: 0px 0px 0px 0px !important;
+  background: rgba(236, 241, 247, 0.8) !important;
+}
+
+.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;
+}

+ 4 - 2
src/components/BlocklyComponent.vue

@@ -1,10 +1,10 @@
 <template>
   <div style="height: 100%;">
     <el-row style="height: 100%;">
-      <el-col :span="16">
+      <el-col  :xl="16" :lg="16" :md="16" :xs="24"  >
         <div id="blocklyDiv" style="height: 100%; width: 100%;"></div>
       </el-col>
-      <el-col :span="8">
+      <el-col  :xl="8" :lg="8" :md="8" :xs="24" >
         <div style="height: 100%;">
           <div style="height: calc(100% - 230px);overflow-y: hidden;">
             <codeHeader @getSwitchs="getSwitch" @getCodemirror="getCodemirror" @getPythonCode="getChildrenPythonCode" />
@@ -23,6 +23,7 @@
 <script setup>
 import { ref, onMounted, shallowRef, watchEffect, onUpdated } from "vue"
 import Blockly from 'blockly';
+import './BlocklyComponent.css';
 // import { pythonGenerator } from "blockly/python";
 import hans from '../blockly/msg/zh-hans';
 import hant from '../blockly/msg/zh-hant';
@@ -56,6 +57,7 @@ onMounted(() => {
   }
   language.value = lang
   let blocklyXmls = Blockly.utils.xml.textToDom(blocklyXml.xml)
+  console.log('--------blockly xml-------',blocklyXmls);
   var categoryNodes = blocklyXmls.getElementsByTagName('category');
   for (var i = 0, cat; cat = categoryNodes[i]; i++) {
     var catId = cat.getAttribute('id');

+ 1 - 1
src/components/device/device.vue

@@ -59,7 +59,7 @@ const source = cancelToken.source();
 const code = Blocklys.useyPythonCodeStore()
 
 onMounted(() => {
-    wsconect()
+    // wsconect()
     deviceType.value = localStorage.getItem('deviceType')
 })
 const wsconect = () => {

+ 24 - 0
src/utils/blocklyFunction.tsx

@@ -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(",")
+}