ESP32接入米家-小爱同学-IDF环境-巴法平台

0 引言

冬天床边没有开关,睡觉懒得关灯,想通过小爱同学控制灯的开关,但是不想换开关。

所以 想用ESP32接入米家,控制一个舵机实现开关控制。

文章目录

  • 0 引言
  • 1 MQTT协议
  • 2 ESP32 MQTT例程
    • 2.1 ESP-MQTT 库
    • 2.2.1 配置结构体 esp_mqtt_client_config_t
    • 2.2.2 事件
    • 2.2 例程调试
    • 2.3 例程分析
  • 3 连接巴法平台
    • 3.1 配置巴法平台
    • 3.2 修改例程代码
    • 3.3 设置小爱同学

1 MQTT协议

Message Queuing Telemetry Transport,消息队列传输探测

ISO 标准下的一种基于发布-订阅模式的消息协议,基于 TCP/IP 协议簇,用于 IoT 即物联网上。

相对于HTTP的优点:

  • 数据包开销小,易于传输。
  • MQTT客户端容易实现。

发布-订阅模式pub/sub
传统的 客户端-服务器架构:服务器与客户端直接通信。
发布-订阅模式:发布者publisher 与 订阅者 subscribers 分离,不会直接通信,由第三方组件broker代理。

publisher 与 subscriber 在 空间、时间和同步 三个维度解耦。

MQTT协议数据包结构
巴法支持支持 MQTT3.1.1 协议,支持Qos0 Qos1,支持retian保留消息,所以我也只看了一下MQTT3.1.1 协议
MQTT3.1.1 协议文档

  • Fixed header, present in all MQTT Control Packets
  • Variable header, present in some MQTT Control Packets
  • Payload, present in some MQTT Control Packets

broker过滤消息的选项
broker 使得 subscriber 只接收自己需要的消息。broker 可以基于以下选项过滤消息:

  1. 基于主题
  2. 基于内容
  3. 基于类型

服务质量级别

  1. QoS 0:最多传送一次
    反正 receiver 有没有响应我都之发送一次。
  2. QoS 1:要实施至少一次传送
    我要确保 receiver 至少收到了一次消息。
  3. QoS 2:正好一次传送
    我要确保消息不丢失且不重复。

有了这些基础知识,就可以基于ESP32 的官方例程来实现我们想要的功能了。

2 ESP32 MQTT例程

2.1 ESP-MQTT 库

2.2.1 配置结构体 esp_mqtt_client_config_t

通过 esp_mqtt_client_config_t 结构体配置,配置结构体有以下子结构来配置客户端操作的不同方面。

  • broker : 设置地址和安全验证。
    可以通过 uri 字段或 hostname 、transport 和 port 的组合来配置。
    uri组成:scheme://hostname:port/path,MQTT TCP例程uri为mqtt://mqtt.eclipseprojects.io,默认端口1883
  • credentials : 用于身份验证的客户端凭证。
    username:指向连接到broker的username的指针,也可以通过URI设置。
    client_id:指向客户端id的指针,默认为ESP32_%CHIPID%,其中%CHIPID%是MAC地址的最后3个字节,采用十六进制格式
  • session : MQTT会话方面的配置。
    topic: 指向 LWT(Last Will and Testament) message topic,LWT就是客户死(断开)前用来通知别人的信息。
    msg: 指向 LWT message
    msg_len: LWT message 长度
    qos: 指向 LWT message qos
    retain: LWT message 保留标志
  • network : 组网相关配置。
  • task : 配置FreeRTOS任务。
  • buffer : 输入和输出的缓冲区大小。

esp_mqtt_client_config_t 结构:

/*** MQTT client configuration structure*/
typedef struct {mqtt_event_callback_t event_handle;     /*!< handle for MQTT events as a callback in legacy mode */esp_event_loop_handle_t event_loop_handle; /*!< handle for MQTT event loop library */const char *host;                       /*!< MQTT server domain (ipv4 as string) */const char *uri;                        /*!< Complete MQTT broker URI */uint32_t port;                          /*!< MQTT server port */const char *client_id;                  /*!< default client id is ``ESP32_%CHIPID%`` where %CHIPID% are last 3 bytes of MAC address in hex format */const char *username;                   /*!< MQTT username */const char *password;                   /*!< MQTT password */const char *lwt_topic;                  /*!< LWT (Last Will and Testament) message topic (NULL by default) */const char *lwt_msg;                    /*!< LWT message (NULL by default) */int lwt_qos;                            /*!< LWT message qos */int lwt_retain;                         /*!< LWT retained message flag */int lwt_msg_len;                        /*!< LWT message length */int disable_clean_session;              /*!< mqtt clean session, default clean_session is true */int keepalive;                          /*!< mqtt keepalive, default is 120 seconds */bool disable_auto_reconnect;            /*!< this mqtt client will reconnect to server (when errors/disconnect). Set disable_auto_reconnect=true to disable */void *user_context;                     /*!< pass user context to this option, then can receive that context in ``event->user_context`` */int task_prio;                          /*!< MQTT task priority, default is 5, can be changed in ``make menuconfig`` */int task_stack;                         /*!< MQTT task stack size, default is 6144 bytes, can be changed in ``make menuconfig`` */int buffer_size;                        /*!< size of MQTT send/receive buffer, default is 1024 (only receive buffer size if ``out_buffer_size`` defined) */const char *cert_pem;                   /*!< Pointer to certificate data in PEM or DER format for server verify (with SSL), default is NULL, not required to verify the server. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in cert_len. */size_t cert_len;                        /*!< Length of the buffer pointed to by cert_pem. May be 0 for null-terminated pem */const char *client_cert_pem;            /*!< Pointer to certificate data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_key_pem` has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_cert_len. */size_t client_cert_len;                 /*!< Length of the buffer pointed to by client_cert_pem. May be 0 for null-terminated pem */const char *client_key_pem;             /*!< Pointer to private key data in PEM or DER format for SSL mutual authentication, default is NULL, not required if mutual authentication is not needed. If it is not NULL, also `client_cert_pem` has to be provided. PEM-format must have a terminating NULL-character. DER-format requires the length to be passed in client_key_len */size_t client_key_len;                  /*!< Length of the buffer pointed to by client_key_pem. May be 0 for null-terminated pem */esp_mqtt_transport_t transport;         /*!< overrides URI transport */int refresh_connection_after_ms;        /*!< Refresh connection after this value (in milliseconds) */const struct psk_key_hint *psk_hint_key;     /*!< Pointer to PSK struct defined in esp_tls.h to enable PSK authentication (as alternative to certificate verification). If not NULL and server/client certificates are NULL, PSK is enabled */bool          use_global_ca_store;      /*!< Use a global ca_store for all the connections in which this bool is set. */esp_err_t (*crt_bundle_attach)(void *conf); /*!< Pointer to ESP x509 Certificate Bundle attach function for the usage of certification bundles in mqtts */int reconnect_timeout_ms;               /*!< Reconnect to the broker after this value in miliseconds if auto reconnect is not disabled (defaults to 10s) */const char **alpn_protos;               /*!< NULL-terminated list of supported application protocols to be used for ALPN */const char *clientkey_password;         /*!< Client key decryption password string */int clientkey_password_len;             /*!< String length of the password pointed to by clientkey_password */esp_mqtt_protocol_ver_t protocol_ver;   /*!< MQTT protocol version used for connection, defaults to value from menuconfig*/int out_buffer_size;                    /*!< size of MQTT output buffer. If not defined, both output and input buffers have the same size defined as ``buffer_size`` */bool skip_cert_common_name_check;       /*!< Skip any validation of server certificate CN field, this reduces the security of TLS and makes the mqtt client susceptible to MITM attacks  */bool use_secure_element;                /*!< enable secure element for enabling SSL connection */void *ds_data;                          /*!< carrier of handle for digital signature parameters */int network_timeout_ms;                 /*!< Abort network operation if it is not completed after this value, in milliseconds (defaults to 10s) */bool disable_keepalive;                 /*!< Set disable_keepalive=true to turn off keep-alive mechanism, false by default (keepalive is active by default). Note: setting the config value `keepalive` to `0` doesn't disable keepalive feature, but uses a default keepalive period */const char *path;                       /*!< Path in the URI*/int message_retransmit_timeout;         /*!< timeout for retansmit of failded packet */
} esp_mqtt_client_config_t;

2.2.2 事件

MQTT客户端可以发布以下事件:

MQTT_EVENT_BEFORE_CONNECT:客户端已初始化,即将开始连接到代理。
MQTT_EVENT_CONNECTED:客户端已成功建立到代理的连接。客户机现在已经准备好发送和接收数据了。
MQTT_EVENT_DISCONNECTED:客户端由于无法读取或写入数据而终止了连接,例如由于服务器不可用。
MQTT_EVENT_SUBSCRIBED:代理已经确认客户机的订阅请求。事件数据将包含订阅消息的消息ID。
MQTT_EVENT_UNSUBSCRIBED:代理已经确认客户端的取消订阅请求。事件数据将包含取消订阅消息的消息ID。
MQTT_EVENT_PUBLISHED:代理已经确认客户机的发布消息。这将仅针对服务质量级别1和2发布,因为级别0不使用确认。事件数据将包含发布消息的消息ID。
MQTT_EVENT_DATA:客户端已收到发布消息。事件数据包含:消息ID、消息发布到的主题的名称、接收到的数据及其长度。对于超过内部缓冲区的数据,将发布多个MQTT_EVENT_DATA,并更新来自事件数据的current_data_offset和total_data_len,以跟踪碎片消息。
MQTT_EVENT_ERROR:客户端遇到错误。事件数据中的Esp_mqtt_error_type_t from error_handle可用于进一步确定错误的类型。错误的类型将决定error_handle结构体的哪些部分被填充。

2.2 例程调试

例程路径:[安装路径]\Espressif\frameworks\esp-idf-v4.4\examples\protocols\mqtt\tcp

在vscode 使用 menuconfig 配置WIFI名称和密码

在这里插入图片描述

调试打印输出:

在这里插入图片描述
可以看到,例程接入测试接口然后完成了一些消息的传输。

2.3 例程分析

  1. 首先通过 uri 字段 配置 broker 。URI字段为 mqtt://mqtt.eclipseprojects.io,主题mqtt,主机名 mqtt.eclipseprojects.io,默认端口1883

  2. esp_mqtt_client_init(&mqtt_cfg);根据配置创建MQTT客户端句柄。

  3. esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); 注册MQTT事件。回调函数为 mqtt_event_handler

  4. esp_mqtt_client_start(client);使用已经创建的客户句柄启动MQTT客户端。

下面分析回调函数 mqtt_event_handler 中 MQTT MQTT_EVENT_CONNECTED 事件处理:

MQTT_EVENT_CONNECTED:客户端已成功建立到代理的连接。客户机现在已经准备好发送和接收数据了。

esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0); 客户端向代理发送发布消息。client为例子初始化的client,topic为"/topic/qos1",数据为"data_3",长度设为0表示自己计算,1表示服务质量为Qos 1,LWT message 不保留。
sp_mqtt_client_subscribe(client, "/topic/qos0", 0);
esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
esp_mqtt_client_unsubscribe(client, "/topic/qos1");从已定义的主题取消订阅客户端。
可以看到,我们调试的输出与代码是吻合的:

I (9116) MQTT_EXAMPLE: sent publish successful, msg_id=14555
I (9116) MQTT_EXAMPLE: sent subscribe successful, msg_id=37860
I (9116) MQTT_EXAMPLE: sent subscribe successful, msg_id=49262
I (9126) MQTT_EXAMPLE: sent unsubscribe successful, msg_id=28076

3 连接巴法平台

3.1 配置巴法平台

巴法平台作为 broker ,配置起来非常方便,官方文档。

准备工作,注册巴法平台:

  1. 在官网注册一个账号。
  2. 新建一个MQTT设备云主题。具体可以查阅官方文档的 3、平台使用教程 章节。这里注意创建的是MQTT设备云而不是TCP设备云就行。新建好之后点击昵称可以修改昵称,我这里修改为“卧室灯”。
    设备命名是有讲究的,这里引用官方文档的内容:

11.1 接入介绍 巴法云物联网平台默认接入米家,仅支持以下类型的设备:插座、灯泡、风扇、传感器、空调、开关、窗帘。 用户可以自主选择是否接入米家,根据主题名字判定。 当主题名字后三位是001时为插座设备。 当主题名字后三位是002时为灯泡设备。
当主题名字后三位是003时为风扇设备。 当主题名字后三位是004时为传感器设备。 当主题名字后三位是005时为空调设备。
当主题名字后三位是006时为开关设备。 当主题名字后三位是009时为窗帘设备。

在这里插入图片描述

  1. 保存好 私钥,主题名称。

3.2 修改例程代码

修改例程代码:
app_main.c 加入ID_MQTT

const char* bemfa_uri = "mqtt://bemfa.com:9501/"; // uri, scheme://hostname:port/path
const char* ID_MQTT = "7fe8xxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // 私钥作为MQTT 的ID 
const char* topic = "light002" ; // 对应的topic。  

mqtt_app_start()函数中配置uri和ID,代码修改为:

static void mqtt_app_start(void)
{esp_mqtt_client_config_t mqtt_cfg = {.uri = bemfa_uri,.client_id = ID_MQTT};
#if CONFIG_BROKER_URL_FROM_STDINchar line[128];if (strcmp(mqtt_cfg.uri, "FROM_STDIN") == 0) {int count = 0;printf("Please enter url of mqtt broker\n");while (count < 128) {int c = fgetc(stdin);if (c == '\n') {line[count] = '\0';break;} else if (c > 0 && c < 127) {line[count] = c;++count;}vTaskDelay(10 / portTICK_PERIOD_MS);}mqtt_cfg.uri = line;printf("Broker url: %s\n", line);} else {ESP_LOGE(TAG, "Configuration mismatch: wrong broker url");abort();}
#endif /* CONFIG_BROKER_URL_FROM_STDIN */esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);esp_mqtt_client_start(client);
}

MQTT事件回调函数mqtt_event_handler() 修改订阅事件,修改订阅的topic为巴法中设置的light002,qos设为0或1都可以的;另外就不需要往broker发送测试数据了,全部注释掉:

static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);esp_mqtt_event_handle_t event = event_data;esp_mqtt_client_handle_t client = event->client;int msg_id;switch ((esp_mqtt_event_id_t)event_id) {case MQTT_EVENT_CONNECTED:ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");// msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0);// ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);// msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);// ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);// msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);// ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);// msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");// ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);msg_id = esp_mqtt_client_subscribe(client, topic, 1);ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);// msg_id = esp_mqtt_client_publish(client, topic, "off", 0, 1, 0);// ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);break;case MQTT_EVENT_DISCONNECTED:ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");break;case MQTT_EVENT_SUBSCRIBED:ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);// msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);// ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);break;case MQTT_EVENT_UNSUBSCRIBED:ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);break;case MQTT_EVENT_PUBLISHED:ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);break;case MQTT_EVENT_DATA:ESP_LOGI(TAG, "MQTT_EVENT_DATA");printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);printf("DATA=%.*s\r\n", event->data_len, event->data);break;case MQTT_EVENT_ERROR:ESP_LOGI(TAG, "MQTT_EVENT_ERROR");if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);log_error_if_nonzero("captured as transport's socket errno",  event->error_handle->esp_transport_sock_errno);ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));}break;default:ESP_LOGI(TAG, "Other event id:%d", event->event_id);break;}
}

3.3 设置小爱同学

  1. 米家添加设备,我的 -> 其他平台设备 -> 找到巴法,然后绑定
    在这里插入图片描述

  2. 小爱同学添加训练
    在这里插入图片描述

  3. 使用小爱同学控制
    这里我先后给了“打开卧室灯”与“关闭卧室灯”的指令。
    在这里插入图片描述

可以看到,ESP32已经收到控制指令啦,至于怎么响应指令,就可以随意开发了,我后续打算添加一个舵机控制,来实现传统开关的通断控制。

参考:
esp8266接入小爱同学,通过mqtt
ESP8266、ESP32实现小爱语音控制灯

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/53906.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI新势力 claude,国内支持访问,跟我一起用起来吧

ChatGPT已经火的没边了&#xff0c;但是最近出来了一个claude也不容小觑&#xff0c;而且只要注册过谷歌账户&#xff0c;就可以不用挂梯子&#xff0c;直接可以访问&#xff0c;是不是很好&#xff1f; 那我们来看一下效果吧 真是非常的给力&#xff0c;据说可以媲美chatGPT3…

OpenAI推出新业务模式:售卖Model instance

文&#xff5c;张向前源&#xff5c;分布式实验室 OpenAI的新业务模式&#xff0c;卖Model instance&#xff0c;起价26万4千美元一年。 这个Model instance的好处是它完全归属于你&#xff0c;你可以按照自己的要求&#xff0c;对它进行有针对的微调&#xff0c;使它具备你需要…

「Bug」解决办法:Could not switchto this profil,无法使用节点的解决方法,彻底解决

♥️作者&#xff1a;白日参商 &#x1f935;‍♂️个人主页&#xff1a;白日参商主页 ♥️坚持分析平时学习到的项目以及学习到的软件开发知识&#xff0c;和大家一起努力呀&#xff01;&#xff01;&#xff01; &#x1f388;&#x1f388;加油&#xff01; 加油&#xff01…

同花顺_代码解析_技术指标_L

本文通过对同花顺中现成代码进行解析&#xff0c;用以了解同花顺相关策略设计的思想 目录 LH_LYDG LH_猎鹰歼狐 LHBLX LHSJ LHTZ LHXJ LH猎狐雷达 LOF净值 LWR LH_LYDG 猎鹰渡关&#xff08;检测大盘顶部&#xff09; 指标用法&#xff1a; &#xff08;1&#xff…

chatgpt赋能python:Python自动发送信息:提高效率,解放双手

Python自动发送信息&#xff1a;提高效率&#xff0c;解放双手 作为一位有10年python编程经验的工程师&#xff0c;我深深体会到了Python带来的效率提升和工作上的便捷。Python的应用场景广泛&#xff0c;其中自动发送信息也是其优秀的应用之一。本文将介绍Python自动发送信息…

AD中画圆弧形板框的方法

在实际的板框设计中&#xff0c;有时为了生产需要&#xff0c;不得不需要将PCB板设计成四角需要倒角的形式&#xff0c;经过实际的摸索&#xff0c;现在得出一种画圆形板框的小技巧。 现在需要将板框设计成3.5mm半径样式。 &#xff08;1&#xff09;将板子原点定位至左下角。 …

Boxplot箱线图

方法1 http://www.ehbio.com/Cloud_Platform/front/#/ 网站直接做 方法2 Excel如何绘制箱线图 画箱线图首先需要计算5个数据&#xff1a;最小值&#xff08;min&#xff09;&#xff0c;第一四分位数&#xff08;Q1&#xff09;、中位数&#xff08;median&#xff09;、第三四…

什么是 Wireframe线框图

http://www.mobileui.cn/what-is-wireframe-wireframes.html 什么是 Wireframe线框图 ? 老实说我受够某客户和某设计公司老是把 Wireframe 喊做 Storyboard 了&#xff01;每次听到都要克制翻白眼的欲望。拜托不要开口闭口说“我们很重视 UI、我们很有经验”&#xff0c;却连…

给TableLayou绘制边框

效果如下&#xff1a; 思路&#xff1a;使用share作为背景显示边框 步骤&#xff1a; 1.在res/drawable文件夹下建立table_frame_gray.xml文件&#xff1a; <?xml version"1.0" encoding"utf-8"?> <shape xmlns:android"http://schemas.a…

软件工程导论E-R图、盒图(N-S图)、PAD图

1、E-R图 E-R图也是实体-联系图&#xff0c;E-R图属于需求分析的一部分&#xff0c;为了把用户的数据要求清楚、准确地描述出来&#xff0c;系统分析员通常建立一个概念性的数据模型。 下面介绍E-R图的画法 E-R图由数据对象&#xff08;实体&#xff09;、属性、联系三部分组…

产品设计--线框图

线框图是一个网站图形化的骨架&#xff0c;引导一个页面的内容及概念&#xff0c;能够帮助设计师和客户讨论具体的网站层次和导向。一个简单的线框图只需要使用线条、方框和灰阶色彩填充&#xff0c;黑白色的布局整体呈现为低保真设计图&#xff0c;主要呈现主体信息群&#xf…

网页版在线流程图绘制工具Diagram

网页地址&#xff1a;Diagram 可以将流程图保存为图片、网址等多种格式。 界面&#xff1a;

箱线图(箱型图) matlab boxplot

箱线图&#xff08;箱型图&#xff09;的主要作用是发现数据内部整体的分布分散情况&#xff0c;包括最小最大值、各分位数、中位数、异常值。 boxplot(x) creates a box plot of the data in x. If x is a vector, boxplot plots one box. If x is a matrix, boxplot plots on…

基于MFC框架的OpenGL绘图:画直线(详解版)

文章目录 前言一、前期准备1.成员变量2.鼠标响应事件 二、正式画图1. 调用Display()函数2. 画网格3. 画线4. DDA算法 总结 前言 这是上一篇文章的详解版本&#xff0c;容我和大家详细地分享一下画线思路 一、前期准备 1.成员变量 // 背景网格的间隔const float GRIDGAP 0.1…

Diagramme包画流程图

Diagramme包画流程图 library(DiagrammeR)# 1 -----------------------------------------------------------------------grViz("digraph flowchart {# node definitions with substituted label textnode [fontname Helvetica, shape rectangle] tab1 [label …

甘特图控件DHTMLX Gantt入门使用教程【引入】:dhtmlxGantt 与 ASP.NET MVC(下)

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的大部分开发需求&#xff0c;具备完善的甘特图图表库&#xff0c;功能强大&#xff0c;价格便宜&#xff0c;提供丰富而灵活的JavaScript API接口&#xff0c;与各种服务器端技术&am…

甘特图控件DHTMLX Gantt入门使用教程【引入】:dhtmlxGantt 与 ASP.NET MVC(上)

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的大部分开发需求&#xff0c;具备完善的甘特图图表库&#xff0c;功能强大&#xff0c;价格便宜&#xff0c;提供丰富而灵活的JavaScript API接口&#xff0c;与各种服务器端技术&am…

效果图底图 线框图_线框图初学者指南

效果图底图 线框图 线框图是任何屏幕设计过程中的重要一步。 它主要允许您定义设计的信息层次结构&#xff0c;从而使您可以轻松地根据希望用户处理信息的方式来规划布局。 如果您还没有使用线框图&#xff0c;是时候让您的脚湿了。 在开始之前&#xff0c;有一个简单的问题&a…

平面图,对偶图,

平面图定义&#xff1a; 图存在一种形式&#xff0c;所有的边只在顶点处相交&#xff0c;那么这个图就是平面图。 对偶图定义&#xff1a; 对于每一个平面图&#xff0c; 都有与其相对应的对偶图. 我们假设上面的例图是图G&#xff0c; 与其对应的对偶图G*&#xff0c; 那么对…

eplan图框制作

1、 首先&#xff0c;新建一个原理图项目 2、 新建图框。选择“工具”→“主数据”→“图框”→“新建” 在“文件名”中输入文件名&#xff0c;保存。 3、添加新建图框属性选项。选中“新建符号*”&#xff0c;添加选项 4、 设置图框的属性 a、 列/行字符数&#xff0c;设置为…