Skills Plugins MCP Prompt Model 博客 我的中心
Content Creation #design #ai

library-migration-guide

Complete guide for converting Arduino/ESP32 hardware libraries into Aily Blockly compatible format. Covers the full workflow: source analysis, block.json design, generator.js implementation, toolbox.json configuration, bus initialization (Serial/I2C/SPI), board adaptation, and packaging.

DeepseekModel Curated skill Quality Excellent · 90 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=ailyproject-aily-blockly-public-skills-library-migration-guide-skill-md&format=skill
Download .skill Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name library-migration-guide description Complete guide for converting Arduino/ESP32 hardware libraries into Aily Blockly compatible format. Covers the full workflow: source analysis, block.json design, generator.js implementation, toolbox.json configuration, bus initialization (Serial/I2C/SPI), board adaptation, and packaging. metadata {"version":"4.0.0","author":"aily-team","scope":"global","agents":"mainAgent","auto-activate":false,"tags":"library,migration,conversion,block-json,generator,serial,i2c,spi,board-config"} Blockly Library Conversion Guide A systematic guide for converting Arduino libraries into Aily Blockly libraries, based on real conversion cases (ArduinoJson, OneButton, MQTT/PubSubClient, DHT, INA219, VL53L0X, etc.). Conversion Workflow Prerequisites Use the existing environment/project context first to determine whether a project is already open. If no project exists, use project with action="create" to create one, then continue with the new project path. ⚠️ CRITICAL: Library Working Directory All library files MUST be created in <projectPath>/<library-name>/ , NOT in node_modules/ . ✅ Correct: <projectPath>/lib-grove_motor/block.json ❌ Wrong: <projectPath>/node_modules/@aily-project/lib-grove_motor/block.json The node_modules/ directory is managed by npm and is write-protected. After creating the library locally, install it with: npm install ./<library-name> If a file write operation returns a path/permission error, check your target path — you are likely writing to node_modules/ instead of <projectPath>/<library-name>/ . Fix the path and retry. Do NOT attempt to bypass by using terminal commands (mkdir, echo, Out-File, etc.) to write into protected directories. Step-by-step Process Source Analysis : Analyze the Arduino library header files to identify public APIs. Classify by operation type: initialization, connection, communication, status, maintenance, quick operations. Block Design : Design user-friendly blocks following block type mapping rules (see Section "Block Design Rules" below). Create Library Files in <projectPath>/<library-name>/ : block.json — Block definitions generator.js — Code generator toolbox.json — Toolbox configuration package.json — Library metadata Copy Source Files : Use run_terminal to copy the Arduino source: If src/ folder exists → copy to <projectPath>/<library-name>/src/<library-name>/ If no src/ folder → copy .c , .cpp , .h , .hpp files to <projectPath>/<library-name>/src/<library-name>/ Write README.md : First read Blockly_Library_README_Conventions.md (fetch from https://blockly.diandeng.tech/files/Blockly_Library_README_Conventions.md ), then follow its format. Post-conversion : Ask the user if they need help with: Installing: npm i <library-path> (must specify the local library path) Testing the converted library Opening the library folder location Library Directory Structure library-name/ ├─ block.json // Block definitions ├─ generator.js // Code generator ├─ toolbox.json // Toolbox configuration ├─ package.json // Library metadata ├─ README.md // Human-readable documentation ├─ README_AI.md // LLM-readable documentation └─ src/ └─ library-name/ // Copied Arduino source files Detailed Code Specification IMPORTANT: For complete code specification with detailed examples, read the companion file Blockly_Library_CODE_Conventions.md located in this skill's folder. It covers: Full block.json design rules with templates for every block type Complete generator.js implementation patterns with real-world examples toolbox.json shadow blocks and organization package.json configuration with board compatibility Board adaptation patterns and WiFi library selection The sections below summarize the critical rules that MUST be followed. Block Design Rules Block Type Mapping Arduino Pattern Block Type Connection Field Type Object creation/init Statement prev/next field_input (user enters new var name) Global object method Statement prev/next No variable field (direct call) Object method call Statement prev/next field_variable (select existing var) Global object query Value output No variable field Quick operation Statement/Value standard No variable field, direct params Event callback Hat block No prev/next field_variable + input_statement Conditional callback Hybrid prev/next input_value + input_statement Status query Value output field_variable field_input vs field_variable field_input : For initialization blocks — user enters a NEW variable name field_variable : For method call blocks — user selects an EXISTING variable (set variableTypes and defaultType ) Global objects (Serial, WiFi, Wire, SPI, httpUpdate, SPIFFS, ESP, EEPROM): No variable field needed Reading Variable Names in generator.js // field_input const varName = block. getFieldValue ( 'VAR' ) || 'defaultVar' ; // field_variable const varField = block. getField ( 'VAR' ); const varName = varField ? varField. getText () : 'defaultVar' ; // Global object — use directly const serialPort = block. getFieldValue ( 'SERIAL' ) || 'Serial' ; Board Config Template Variables (block.json) Use these in field_dropdown options — auto-populated at runtime: Variable Usage ${board.i2c} I2C interface list (Wire selector) ${board.digitalPins} Digital pin list ${board.analogPins} Analog pin list ${board.serialPort} Serial port list ${board.serialSpeed} Baud rate list ${board.interruptPins} Interrupt pin list ${board.interruptMode} Interrupt mode list Extensions Register dynamic extensions in generator.js. Always unregister before registering: if ( Blockly . Extensions . isRegistered ( 'ext_name' )) { Blockly . Extensions . unregister ( 'ext_name' ); } Blockly . Extensions . register ( 'ext_name' , function ( ) { /* ... */ }); Code Generation Rules Injection Methods & Execution Order All injection methods take (tag, code) and auto-deduplicate by tag. # include <Lib.h> // addLibrary(tag, code) # define MACRO val // addMacro(tag, code) Type globalVar; // addVariable(tag, code) MyClass obj; // addObject(tag, code) void helper () {} // addFunction(tag, code, isGlobal?) void setup () { Serial. begin ( 9600 ); // addSetupBegin — bus-level init ONLY sensor. begin (); // addSetup — device/sensor init attachCb (handler); // addSetupEnd — callbacks, depends on prior init } void loop () { btn. tick (); // addLoopBegin — polling/tick calls // [user blocks here] } Bus Initialization (MANDATORY) Serial — Always use ensureSerialBegin() , NEVER write Serial.begin() directly: // ✅ Correct ensureSerialBegin ( 'Serial' , generator); // default 9600 ensureSerialBegin ( 'Serial' , generator, 115200 ); // custom baud ensureSerialBegin (serialPort, generator, baud); // dynamic // ❌ FORBIDDEN generator. addSetupBegin ( 'serial_begin' , 'Serial.begin(9600);' ); I2C — Use wire_${wireName}_begin key for deduplication: const wire = block. getFieldValue ( 'WIRE' ) || 'Wire' ; generator. addLibrary ( 'Wire' , '#include <Wire.h>' ); const wireBeginKey = `wire_ ${wire} _begin` ; if (!generator. setupCodes_ || !generator. setupCodes_ [wireBeginKey]) { generator. addSetup (wireBeginKey, wire + '.begin();\n' ); } SPI — Use spi_${spiName}_begin key for deduplication: const spi = block. getFieldValue ( 'SPI' ) || 'SPI' ; generator. addLibrary ( 'SPI' , '#include <SPI.h>' ); generator. addSetup ( `spi_ ${spi} _begin` , spi + '.begin();\n' ); Variable Management Initialization blocks with field_input MUST implement a rename listener: if (!block. _varMonitorAttached ) { block. _varMonitorAttached = true ; block. _varLastName = block. getFieldValue ( 'VAR' ) || 'defaultVar' ; registerVariableToBlockly (block. _varLastName , 'VarType' ); const varField = block. getField ( 'VAR' ); if (varField) { const orig = varField. onFinishEditing_ ; varField. onFinishEditing_ = function ( newName ) { if ( typeof orig === 'function' ) orig. call ( this , newName); const ws = block. workspace || Blockly . getMainWorkspace ?.(); const oldName = block. _varLastName ; if (ws && newName && newName !== oldName) { renameVariableInBlockly (block, oldName, newName, 'VarType' ); block. _varLastName = newName; } }; } } Generator Return Values Statement blocks : return 'code;\n'; Value blocks : return [expr, generator.ORDER_ATOMIC]; Hat / event blocks : return ''; (empty string — event-driven, not in main flow) Hybrid blocks : return 'conditional_code;\n'; (returned code runs inside parent callback) valueToCode & ORDER Constants // Extract input value (most cases use ORDER_ATOMIC) const val = generator. valueToCode (block, 'INPUT' , generator. ORDER_ATOMIC ) || '0' ; // Return value block return [varName + '.read()' , generator. ORDER_FUNCTION_CALL ]; Board Adaptation Access runtime board config via window['boardConfig'] : const boardConfig = window [ 'boardConfig' ]; // boardConfig.core — e.g. 'esp32:esp32', 'arduino:avr' // boardConfig.name — board display name // boardConfig.i2c — I2C interface list // boardConfig.digitalPins — digital pin list NEVER modify window['boardConfig'] directly — use independent storage like window['customXxx'] . toolbox.json Rules All input_value slots MUST have shadow blocks : { "kind" : "block" , "type" : "sensor_read" , "inputs" : { "TIMEOUT" : { "shadow" : { "type" : "math_number" , "fields" : { "NUM" : 1000 } } } } } Organize blocks by user cognitive flow using label separators: { "kind" : "category" , "name" : "SensorLib" , "contents" : [ { "kind" : "label" , "text" : "Setup" } , { "kind" : "block" , "type" : "sensor_init" } , { "kind" : "label" , "text" : "Read Data" } , { "kind" : "block" , "type" : "sensor_read" } ] } package.json Configuration { "name" : "@aily-project/lib-libname" , "nickname" : "Display Name" , "description" : "Brief description (<50 chars)" , "version" : "1.0.0" , "compatibility" : { "core" : [ ] , "voltage" : [ 3.3 , 5 ] } , "keywords" : [ "aily" , "blockly" ] , "tested" : true , "url" : "original library URL" } Board compatibility shorthand: Universal: "core": [] (empty array = all boards) ESP32 only: "core": ["esp32:esp32"] Classic Arduino: "core": ["arduino:avr", "arduino:megaavr"] IoT boards: "core": ["esp32:esp32", "esp8266:esp8266", "renesas_uno:unor4wifi"] Common Anti-patterns ❌ Wrong ✅ Correct
Keywords that activate this skill. Click one to copy it.

This skill does not provide trigger words.

The downloaded .skill package contains the following fields.
Field Description
formatFormat tag (skill/v1)
skill_idUnique skill ID
nameSkill name
versionVersion
descriptionDescription
categoryCategories (array)
trigger_wordsTrigger words
tagsTags
sourceSource
source_urlSource URL (this page)
exported_atExported at (set per download)
system_promptSystem prompt body
model_configModel config: provider / model / temperature / max_tokens / top_p
examplesExamples
install_guideImport guide for Coze / Dify / Claude / custom frameworks
The same skill can be exported in different platform formats.
.skill Standard format with system_prompt and model_config, ready for any agent framework Download
.skillpro Enhanced format with scripts, tools, dependencies and hooks Download
.json Plain JSON export with system_prompt and model parameters only Download
Coze Markdown with frontmatter, for Coze platform import Download
Dify Dify DSL, import directly after creating an app Download

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

验证码 --

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。