# EDA_Info-Helper 文档:https://wiki.yang17.top/products/oshwhub/oshw-e523ea15d772451fb179cccf32009156/ 项目来源:https://oshwhub.com/course-examples/eda_info-helper 分类:硬件项目 更新时间:2025-11-19T01:50:53.145Z 本项目是基于嘉立创EDA API扩展开发的EDA信息助手,用于与嘉立创EDA交互的简单信息显示。 项目简介🪄 项目介绍 本项目基于ESP8266开发,借助嘉立创EDA API实现实时将嘉立创EDA信息显示至嵌入式设备上,本项目需要适当的C/C++、Html、CSS、JavaScript/TypeScript、Python语言基础,本项目偏软件及物联网方向。 在本项目中我们需要制作三个产物: 硬件设备(C/C++)。 中转转发服务上位机(Python)。 嘉立创EDA插件(Html、CSS、JavaScript/TypeScript) 项目功能 本项目得益于ESP8266的WIFI功能,其实现原理是先通过嘉立创EDA API通过定时器实时监听用户鼠标的点击操作,将点击操作返回的属性信息通过外部请求API发送至本地中转服务,再通过中转服务将数据POST请求至硬件设备IP地址,由ESP8266 WEB服务监听接收POST请求,最后通过显示至屏幕上。 当然,你可能会疑惑为什么不能直接通过外部请求API去POST到硬件设备,这是因为存在安全问题不允许跨IP请求,所以这里只能通过创建一个转发服务来完成跨IP数据转发。 硬件固件功能 ✅ WIFI局域网配网 ✅ 自动记录及联网 ✅ 获取数据并显示至屏幕 转发服务功能 ✅ 接收本地5012端口数据,转发至指定IP地址 嘉立创EDA插件功能 ✅ 监听鼠标点击事件,获取属性信息 ✅ 逻辑处理及信息解析 ✅ 数据发送至本地5012端口 项目参数🔮 采用ESP8266作为主控,ESP8266价格低廉且自带WIFI网络功能 屏幕采用ST7789驱动的2.4寸屏幕,240*320分辨率 电池采用单节14500锂电池,满电电压4.2V 充电方案采用TP4056芯片,最大1A充电电流 硬件设计 主控电路 主控选用ESP8266主控,成本低廉,IO接口刚好足够 查看数据手册 前往立创商城 屏幕电路 屏幕这里我们选用的是2.4寸240*320LCD屏,该尺寸的屏幕有两种驱动芯片,本项目使用的是ST7789驱动芯片,当然你也可以用ILI9341驱动芯片,需要修改TFT-espid的驱动定义即可。这里推荐购买IPS面板的屏幕,IPS面板相对于TFT面板能获得更好的视觉体验。 (选用屏幕时切记确保屏幕线序与PCB焊盘线序匹配) ST7789屏幕模组模组 原理图 (本项目未添加触控功能,无需购买带触控面板的屏幕,当然你可以自己拓展触控功能) 屏幕信息 引脚定义 电池供电电路 电池供电电路中选用TP4056锂电池充电芯片,电池选用14500单节满电电压4.2V锂电池。项目中通过TYPEC接口的5V进行充电。 (项目电路没有添加保护功能,选用电池时确认电池带保护电路板) (TP4056选用1A挡位充电时建议添加散热片) (为方便没有加热台和风枪的用户焊接TP4056,在焊盘背面做了开窗和插件焊盘孔,你可以在孔内插入锡丝并用烙铁融化即可) 焊盘正面 焊盘背面 查看数据手册 前往立创商城 稳压电路 稳压芯片选用ME6217C33M5G,将电池电压降至3.3V,提供稳定电压,及电流 查看数据手册 前往立创商城 电量检测电路 ESP8266的ADC引脚还没用上,所以这里我们再加一个ADC电量检测电路 其他外设电路 其他外设中有烧录接口、总开关及供电接口。 嵌入式软件开发 开发环境 软件环境:VSCode+PlatformIO 开发语言:C/C++ 依赖库 通过以下开源库协助本项目开发 TFT_eSPI:用于屏幕显示驱动 ArduinoJson:解析Json数据 ESPAsyncWebServer-esphome:构建异步WEB服务 main 主进程 本项目的嵌入式软件功能比较简单,只需要接收/api路径下数据并解析显示至ST7789屏幕,所以这里直接用裸机开发实现,而不使用OS,UI部分则是由TFT-eSPI实现,逻辑默认仅当数据变化下才更新,避免频繁刷屏导致频闪。 Markdown 语法解析会导致部分内容消失,完整源码建议查看附件 #include #include #include #include #include #include #include #include "image.cpp" AsyncWebServer server(80);// 设置服务器端口 TFT_eSPI tft = TFT_eSPI(); const char *ssidFile = "/ssid.json"; // 配置存储文件 String ipAddress = "Not Connected"; String lastMode = ""; String lastprimitiveType = ""; String lastIP = ""; String lastname1 = ""; String currentname1 = "--"; String lastdata1 = ""; String currentdata1 = "--"; String lastname2 = ""; String currentname2 = "--"; String lastdata2 = ""; String currentdata2 = "--"; String lastname3 = ""; String currentname3 = "--"; String lastdata3 = ""; String currentdata3 = "--"; String lastname4 = ""; String currentname4 = "--"; String lastdata4 = ""; String currentdata4 = "--"; // AP 默认热点配置 const char *ap_ssid = "EDA-InfoHelper"; const char *ap_password = ""; String currentMode = "--"; String currentprimitiveType = "--"; bool wifiBlink = true; int temp = 26; int humi = 45; // ================== UI 提示函数 ================== void showMessage(String msg, uint16_t color = TFT_WHITE) { tft.fillScreen(TFT_BLACK); tft.setTextColor(color, TFT_BLACK); tft.drawCentreString(msg, 160, 120, 4); } // ================== 原始 UI 元素 ================== void drawHeader() { tft.fillRect(0, 0, 320, 20, TFT_NAVY); tft.setTextColor(TFT_WHITE, TFT_NAVY); tft.drawString("EDA-InfoHelper", 5, 5, 2); if (WiFi.status() == WL_CONNECTED) { tft.setTextColor(TFT_GREEN, TFT_NAVY); tft.drawRightString(ipAddress, 230, 5, 2); } else { tft.setTextColor(TFT_GREEN, TFT_NAVY); tft.drawRightString(ipAddress, 230, 5, 2); if (wifiBlink) { tft.fillRect(290, 5, 5, 14, TFT_CYAN); tft.fillRect(300, 9, 5, 10, TFT_CYAN); tft.fillRect(310, 13, 5, 6, TFT_CYAN); } else { tft.fillRect(280, 0, 40, 20, TFT_NAVY); } } } void drawCard(int x, int y,uint16_t color,String mode) { tft.fillRoundRect(x, y, 80, 80, 8, color); if(mode == "PCB") { /* code */ tft.pushImage(x+3, y+3, 75, 75, pcb); } else if(mode == "SCH") { /* code */ tft.pushImage(x+3, y+3, 75, 75, sch); }else{ tft.pushImage(x+3, y+3, 75, 75, eda); } } void drawTextCard(int x, int y, String title, String value, uint16_t color) { tft.fillRoundRect(x, y, 210, 35, 8, color); tft.drawRoundRect(x, y, 210, 35, 8, TFT_WHITE); tft.setTextColor(TFT_WHITE, color); tft.drawString(title, x + 8, y + 6, 2); tft.setTextColor(TFT_YELLOW, color); tft.drawRightString(value, x + 200, y + 5, 4); } void drawTextCard2(int x, int y, String title, String value, uint16_t color) { tft.fillRoundRect(x, y, 145, 50, 8, color); tft.drawRoundRect(x, y, 145, 50, 8, TFT_WHITE); tft.setTextColor(TFT_WHITE, color); tft.drawString(title, x + 8, y + 6, 2); tft.setTextColor(TFT_YELLOW, color); tft.drawRightString(value, x + 130, y + 25, 2); } // ================== 保存 WiFi 配置 ================== void saveWiFiConfig(String ssid, String pass) { DynamicJsonDocument doc(256); doc["ssid"] = ssid; doc["pass"] = pass; fs::File file = SPIFFS.open(ssidFile, "w"); if (file) { serializeJson(doc, file); file.close(); } } // ================== 加载 WiFi 配置 ================== bool loadWiFiConfig(String &ssid, String &pass) { if (!SPIFFS.exists(ssidFile)) return false; fs::File file = SPIFFS.open(ssidFile, "r"); if (!file) return false; DynamicJsonDocument doc(256); if (deserializeJson(doc, file)) return false; ssid = doc["ssid"].as(); pass = doc["pass"].as(); return true; } // ================== WiFi STA 连接函数 ================== bool connectSTA(String ssid, String pass, int timeout = 10000) { WiFi.mode(WIFI_STA); WiFi.begin(ssid.c_str(), pass.c_str()); showMessage("Wait connect WIFI...", TFT_YELLOW); unsigned long start = millis(); while (WiFi.status() != WL_CONNECTED && millis() - start < timeout) { delay(3000); } if (WiFi.status() == WL_CONNECTED) { ipAddress = WiFi.localIP().toString(); return true; } else { return false; } } // ================== AP 模式启动 ================== void startAP() { WiFi.mode(WIFI_AP); WiFi.softAP(ap_ssid, ap_password); showMessage("Wait connect WIFI...", TFT_CYAN); } // ================== 路由配置 ================== void handleWiFiConfig() { server.on("/api", HTTP_POST, [](AsyncWebServerRequest *request) { if (request->hasParam("mode", true) && request->hasParam("primitiveType", true)) { currentMode = request->getParam("mode", true)->value(); currentprimitiveType = request->getParam("primitiveType", true)->value(); currentname1 = request->getParam("name1", true)->value(); currentdata1 = request->getParam("data1", true)->value(); currentname2= request->getParam("name2", true)->value(); currentdata2 = request->getParam("data2", true)->value(); currentname3 = request->getParam("name3", true)->value(); currentdata3 = request->getParam("data3", true)->value(); currentname4 = request->getParam("name4", true)->value(); currentdata4 = request->getParam("data4", true)->value(); request->send(200, "application/json", "{\"status\":\"ok\"}"); } else { request->send(400, "application/json", "{\"error\":\"missing parameters\"}"); } }); server.on("/connect", HTTP_POST, [](AsyncWebServerRequest *request) { // 获取POST参数:ssid、pass、city、api String ssid = request->getParam("ssid", true)->value(); String pass = request->getParam("pass", true)->value(); // 打印接收到的参数 Serial.println(ssid); Serial.println(pass); // 保存WiFi信息到JSON文件 DynamicJsonDocument doc(1024); doc["ssid"] = ssid; doc["pass"] = pass; fs::File file = SPIFFS.open(ssidFile, "w"); // 打开文件进行写入 if (file) { serializeJson(doc, file); // 将JSON内容写入文件 file.close(); // 关闭文件 Serial.println("WiFi信息保存成功,即将重启..."); } else { Serial.println("无法打开文件保存WiFi信息!"); request->send(500, "application/json", "{\"error\":\"无法保存WiFi信息\"}"); return; } // 发送响应告知用户即将重启 request->send(200, "text/html; charset=UTF-8", "" "" "" " " " 状态" "" "" "

WiFi配置已保存,设备正在重启...

" "" "" ); delay(500); // 确保响应发送出去 ESP.restart(); // 重启设备 }); server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { // 检查SPIFFS文件系统中是否存在index.html文件 if (SPIFFS.exists("/index.html")) { fs::File file = SPIFFS.open("/index.html", "r"); // 打开index.html文件 if (file) { size_t fileSize = file.size(); // 获取文件大小 String fileContent; // 逐字节读取文件内容 while (file.available()) { fileContent += (char)file.read(); } file.close(); // 关闭文件 // 返回HTML内容 request->send(200, "text/html", fileContent); return; } } // 如果文件不存在,返回404错误 request->send(404, "text/plain", "File Not Found"); }); server.on("/setting.html", HTTP_GET, [](AsyncWebServerRequest *request) { // 检查SPIFFS文件系统中是否存在index.html文件 if (SPIFFS.exists("/setting.html")) { fs::File file = SPIFFS.open("/setting.html", "r"); // 打开index.html文件 if (file) { size_t fileSize = file.size(); // 获取文件大小 String fileContent; // 逐字节读取文件内容 while (file.available()) { fileContent += (char)file.read(); } file.close(); // 关闭文件 // 返回HTML内容 request->send(200, "text/html", fileContent); return; } } // 如果文件不存在,返回404错误 request->send(404, "text/plain", "File Not Found"); }); // 启动服务器 server.begin(); } // ================== 主流程 ================== void setup() { tft.init(); tft.setRotation(1); tft.fillScreen(TFT_BLACK); Serial.begin(115200); SPIFFS.begin(); String ssid, pass; if (loadWiFiConfig(ssid, pass)) { if (!connectSTA(ssid, pass)) { startAP(); } } else { startAP(); } handleWiFiConfig(); if (WiFi.status() == WL_CONNECTED) { tft.fillScreen(TFT_BLACK); drawHeader(); drawCard(10, 30, TFT_WHITE,"EDA"); drawTextCard(100, 30, "mode", "JLC_EDA", TFT_GREEN); drawTextCard(100, 75, "primitiveType", "ABC", TFT_SKYBLUE); drawTextCard2(10, 120, "name1", "data1", TFT_ORANGE); drawTextCard2(165, 120, "name2", "data2", TFT_ORANGE); drawTextCard2(10, 180, "name3", "data3", TFT_MAGENTA); drawTextCard2(165, 180, "name4", "data4", TFT_MAGENTA); } } void loop() { // WiFi 状态刷新(顶部 header) static unsigned long lastBlink = 0; if (millis() - lastBlink > 500) { wifiBlink = !wifiBlink; String currentIP = WiFi.localIP().toString(); // 仅当IP发生变化或wifiBlink状态改变时才刷新header if (currentIP != lastIP) { ipAddress = currentIP; drawHeader(); lastIP = currentIP; } else if (wifiBlink) { drawHeader(); // 保持闪烁动画 } lastBlink = millis(); } // 实时更新 mode/data(仅当发生变化时) if (WiFi.status() == WL_CONNECTED) { if (currentMode != lastMode) { drawTextCard(100, 30, "mode", currentMode, TFT_GREEN); drawCard(10, 30, TFT_WHITE,currentMode); lastMode = currentMode; } if (currentprimitiveType != lastprimitiveType) { drawTextCard(100, 75, "primitiveType", currentprimitiveType, TFT_SKYBLUE); lastprimitiveType = currentprimitiveType; } if (currentdata1 != lastdata1) { if (currentdata1.length() > 16) { currentdata1 = currentdata1.substring(0, 16); } drawTextCard2(10, 120, currentname1, currentdata1, TFT_ORANGE); lastname1 = currentname1; lastdata1 = currentdata1; } if (currentdata2 != lastdata2) { if (currentdata2.length() > 16) { currentdata2 = currentdata2.substring(0, 16); } drawTextCard2(165, 120,currentname2,currentdata2, TFT_ORANGE); lastname2 = currentname2; lastdata2 = currentdata2; } if (currentdata3 != lastdata3) { if (currentdata3.length() > 16) { currentdata3 = currentdata3.substring(0, 16); } drawTextCard2(10, 180, currentname3, currentdata3, TFT_MAGENTA); lastname3 = currentname3; lastdata3 = currentdata3; } if (currentdata4 != lastdata4) { if (currentdata4.length() > 16) { currentdata4 = currentdata4.substring(0, 16); } drawTextCard2(165, 180, currentname4, currentdata4, TFT_MAGENTA); lastname4 = currentname4; lastdata4 = currentdata4; } } } 上位机客户端软件开发 开发环境 软件环境:VSCode 开发语言:Python 依赖库 通过以下开源库协助本项目开发 Flask:用来快速搭建 HTTP 接口或 Web 应用 requests:用来发送 GET/POST 等请求 flask_cors (CORS):用来处理跨域请求问题 Pillow (PIL):托盘图标绘制 pystray:用于在系统托盘创建图标和菜单 Python主进程 因为只是转发服务,所以不需要什么UI,就选择Python快速开发,应用会在后台运行,可在系统托盘中关闭中转转发服务,通过5012端口/proxy/api路径的数据监听,把数据转发给传入的IP地址/api路径下。 import threading from flask import Flask, request, jsonify import requests from flask_cors import CORS from PIL import Image, ImageDraw import pystray import sys import tkinter as tk from tkinter import messagebox app = Flask(__name__) CORS(app) # --- Flask 路由 --- @app.route("/proxy/api", methods=["POST"]) def proxy_api(): try: ip = request.form.get('ip', '127.0.0.1') mode = request.form.get('mode') primitiveType = request.form.get('primitiveType') name1 = request.form.get('name1') data1 = request.form.get('data1') name2 = request.form.get('name2') data2 = request.form.get('data2') name3 = request.form.get('name3') data3 = request.form.get('data3') name4 = request.form.get('name4') data4 = request.form.get('data4') if not all([ip, mode, primitiveType,name1,data1,name2,data2,name3,data3,name4,data4]): return {"success": False, "error": "缺少必要参数"}, 400 target_url = f"http://{ip}/api" resp = requests.post(target_url, data={"mode": mode, "primitiveType": primitiveType, "name1":name1,"data1":data1, "name2":name2,"data2":data2, "name3":name3,"data3":data3, "name4":name4,"data4":data4}, headers={"Content-Type": "application/x-www-form-urlencoded"}, timeout=5) resp.raise_for_status() return {"success": True, "esp_response": resp.text} except Exception as e: return {"success": False, "error": str(e)}, 500 # --- 托盘相关 --- def create_image(): img = Image.new('RGB', (64, 64), color='white') d = ImageDraw.Draw(img) d.rectangle([16, 16, 48, 48], fill='black') return img def on_quit(icon, item): icon.stop() sys.exit(0) def run_tray(): icon = pystray.Icon("EDA-InfoHelper") icon.icon = create_image() icon.title = "EDA-InfoHelper" icon.menu = pystray.Menu(pystray.MenuItem("EDA-InfoHelper正在运行",None),pystray.MenuItem("退出", on_quit)) icon.run() # --- 弹窗提示 --- def show_startup_message(): root = tk.Tk() root.withdraw() # 隐藏主窗口 messagebox.showinfo("提示", "EDA-InfoHelper 已启动并隐藏到托盘") root.destroy() # --- 启动 Flask 线程 --- def run_flask(): print("EDA-InfoHelper 转发服务已启动,端口号5012") app.run(host="0.0.0.0", port=5012, debug=False) if __name__ == "__main__": # 弹窗提示 show_startup_message() # 启动 Flask 后台线程 threading.Thread(target=run_flask, daemon=True).start() # 显示托盘图标 run_tray() 嘉立创EDA插件开发 开发环境 软件环境:VSCode 开发语言:Html/CSS/TypeScript 依赖库 通过以下开源库协助本项目开发 EDA-SDK:用于调用嘉立创EDA API 查看 API 开发文档 index.ts index.ts是功能入口,创建的状态栏列表下按键通过此文件入口进入,这里我们通过定时器实现实时检测,同时将定时器id记录并存储,方便结束定时器。 import * as extensionConfig from '../extension.json'; import * as func from './function'; // eslint-disable-next-line @typescript-eslint/no-unused-vars export function activate(status?: 'onStartupFinished', arg?: string): void {} export function about(): void { eda.sys_Dialog.showInformationMessage( eda.sys_I18n.text('EasyEDA extension SDK v', undefined, undefined, extensionConfig.version), eda.sys_I18n.text('About'), ); } let timerId: ReturnType | null = null; // 封装定时器函数 // 启动定时器 export async function start(): Promise { const configs = await eda.sys_Storage.getExtensionAllUserConfigs(); if (configs.timerId) { console.log('定时器已存在:', configs.timerId); return; } const id = func.createDocumentTimer(); // 保存到扩展配置 await eda.sys_Storage.setExtensionAllUserConfigs({ ...configs, timerId: id, }); console.log('start timerId =', id); } // 停止定时器 export async function stopa(): Promise { console.log('stop'); const configs = eda.sys_Storage.getExtensionAllUserConfigs(); const id = configs.timerId; console.log('stop timerId =', id); if (id !== undefined) { clearInterval(id); delete configs.timerId; await eda.sys_Storage.setExtensionAllUserConfigs(configs); console.log('循环已停止'); } } export async function setting(): Promise { eda.sys_IFrame.openIFrame('/iframe/index.html', 450, 500); } function.ts function.ts是存放的是功能实现,用于逻辑处理及在index.ts入门中调用实现的功能。 export function createDocumentTimer(): number { return setInterval(() => { eda.dmt_SelectControl .getCurrentDocumentInfo() .then(async (doc) => { if (doc) { console.log('用户当前在:' + doc.documentType); if (doc.documentType === 3) { // PCB const items = await eda.pcb_SelectControl.getSelectedPrimitives(); if (items && items.length > 0) { items.forEach((i) => { const dataValue = i.pcbItemPrimitiveType ?? 0; // 如果 undefined 就用 0 switch (dataValue) { case "Component": const name = i.device.name?? 0; const part = i.device.attrs["Supplier Part"]?? 0; const footprint = i.attrsMap["Footprint"] ?? 0; const globalIndex = i.globalIndex ?? 0; sendData("PCB", dataValue,"name",name,"part",part,"footprint",footprint,"globalIndex",globalIndex); break; case "Pad": const net = i.net ?? 0; const num = i.num ?? 0; const layerId = i.layerId ?? 0; const globalIndex2 = i.globalIndex ?? 0; sendData("PCB", dataValue,"net",net,"num",num,"layerId",layerId,"globalIndex",globalIndex2); break; case "Text": const formulaName = i.formulaName ?? 0; const fontSize = i.fontSize ?? 0; const key = i.key ?? 0; const globalIndex3 = i.globalIndex ?? 0; sendData("PCB", dataValue,"formulaName", formulaName,"fontSize",fontSize,"key",key,"globalIndex",globalIndex3); break; case "Rect": const height = i.height ?? 0; const width = i.width ?? 0; const type = i.type ?? 0; const globalIndex4 = i.globalIndex ?? 0; sendData("PCB", dataValue,"height",height,"width",width,"type",type,"globalIndex",globalIndex4); break; case "Via": const net2 = i.net ?? 0; const holeRadius = i.holeRadius ?? 0; const radius = i.radius ?? 0; const globalIndex5 = i.globalIndex ?? 0; sendData("PCB", dataValue,"net",net2,"holeRadius",holeRadius,"radius",radius,"globalIndex",globalIndex5); break; case "Polygon": const strokeWidth = i.strokeWidth ?? 0; const type2 = i.type ?? 0; const layerId2 = i.layerId ?? 0; const globalIndex6 = i.globalIndex ?? 0; sendData("PCB", dataValue,"strokeWidth",strokeWidth,"type",type2,"layerId",layerId2,"globalIndex",globalIndex6); break; default: break; } }); } } else if (doc.documentType === 1) { // SCH const items = await eda.sch_SelectControl.getSelectedPrimitives(); if (items && items.length > 0) { items.forEach((i) => { const dataValue = i.primitiveType ?? 0; // 防止 undefined switch (dataValue) { case "Component": const designator = i.param.designator?? 0; const uniqueId = i.param.uniqueIdt?? 0; const id = i.id ?? 0; sendData("SCH", dataValue,"designator",designator,"uniqueId",uniqueId,"id",id,"---","---"); break; case "Net Port": case "Wire": case "Net Flag": const net = i.param.net ?? 0; const id2 = i.id ?? 0; sendData("SCH", dataValue,"net",net,"id",id2,"---","---","---","---"); break; case "Property": case "Text": const id3 = i.id ?? 0; sendData("SCH", dataValue,"id",id3,"---","---","---","---","---","---"); break; case "Name": const id4 = i.id ?? 0; sendData("SCH", dataValue,"id",id4,"---","---","---","---","---","---"); break; default: break; } }); } } } else { console.log('当前没有选中文档'); } }) .catch((err) => { console.error('获取文档信息失败:', err); }); }, 1000); } function sendData(mode: String, primitiveType: String,name1:String,data1:String,name2:String,data2:String,name3:String,data3:String,name4:String,data4:String) { const params = new URLSearchParams(); // 获取已存储的IP地址 const configs = eda.sys_Storage.getExtensionAllUserConfigs(); const ip = configs.ip || '127.0.0.1'; params.append('ip', ip); // 新增IP参数 params.append('mode', mode.toString()); params.append('primitiveType', primitiveType.toString()); params.append('name1', name1.toString()); params.append('data1', data1.toString()); params.append('name2', name2.toString()); params.append('data2', data2.toString()); params.append('name3', name3.toString()); params.append('data3', data3.toString()); params.append('name4', name4.toString()); params.append('data4', data4.toString()); eda.sys_ClientUrl .request( 'http://127.0.0.1:5012/proxy/api', 'POST', params.toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }, (res) => { console.log('数据发送成功', res); }, ) .catch((err) => { console.error('请求失败:', err); }); } declare global { interface ExtensionConfigs { timerId?: number; ip?: string; // 新增IP字段 } } index.html index.html是设置页面的前端展示,用于用户下载中转服务及输入目标硬件设备的IP,IP会存储至插件内部存储,便于API请求,避免重复配置。

EDA-InfoHelperServer中转服务工具

在使用本插件的同时,您还需下载并启动 EDA-InfoHelperServer中转服务工具,通过本工具把POST数据传输至硬件设备。

下载中转服务工具

绑定EDA-InfoHelper的IP地址

中转服务工具启动后,还需在此填入您的EDA-InfoHelper设备IP地址,您的硬件联网后硬件设备IP地址会显示在硬件设备的顶部导航栏上。

保存设置
Markdown 语法解析会导致部分内容消失,详细内容建议看附件文件 3D外壳结构 前盖 正面 背面 内壁设置有限位槽,为按键预留空间。 屏幕部分设有隔离层,避免屏幕接触PCB焊盘导致短路 按键及TypeC开槽 后盖 正面 背面 后盖部分采用异形结构 同样圆角处理 为烧录接口开槽 安装结构 项目采用的是双外壳结构,由前盖、后盖构成 免费打样 嘉立创提供一站式产业互联智造平台,涵盖电子、机械产业一站式服务🛠️ 嘉立创免费PCB打样 嘉立创免费3D打样 实机数据流程演示 EDA插件配置IP 点击器件 EDA发送数据 中转服务接收及转发 硬件接收PCB数据显示 硬件接收原理图数据显示 PCB数据显示总流程 原理图数据显示总流程 拓展方向 本项目中提供了嘉立创EDA-API的一种扩展及交互方向,你可以基于本项目扩展一个结合嘉立创EDA的交互设备。硬件中还支持ADC电量检测和两个按键外设,可以按需进行功能扩展。 一键DRC报告 在EDA中显示硬件信息 天气、时钟显示 ...... 嘉立创EDA扩展广场 嘉立创EDA扩展广场已经上线,在扩展广场中可以发现各种实用好玩的扩展插件,当然如果你自己也开发了一些有趣的插件,欢迎上架至扩展广场,共建嘉立创EDA扩展插件生态,丰富EDA软件功能。 访问扩展广场 下载EDA-InfoHelper扩展 使用说明 附件"EDA-InfoHelper资源包"包含所有编译后产物、3D文件及硬件工程,源码文件则单独打包在附件中 硬件烧录请参考: EDA-Robot机器狗 烧录说明 插件安装请参考: 嘉立创EDA扩展广场_EDA-InfoHelper扩展插件 1.为硬件上电并连接“EDA-InfoHelp” 2.4G热点。 2.连接成功后进入192.168.4.1完成配网(配置2.4G频段网络) 3.设备联网后会在顶部状态栏显示IP地址,记录下这个IP 4.在EDA-设置-扩展-扩展管理器导入eda-info-helper.eext插件,并允许外部交互。 5.进入PCB或原理图页面,点击顶部状态栏InfoHelper-设置页面 6.填入记录的IP地址并下载中转服务工具。 7.打开中转服务工具即可 现在,点击任意器件即可显示信息了。