HonestQiao 发表于 2023-12-13 15:39

【nRF7002-DK Wi-Fi® 6开发套件评测】接入开发板到node-red控制板载LED

<div class='showpostmsg'><p>nRF7002-DK联网功能一级棒,在SDK中,还提供了mqtt连接的模块,这篇分享,就基于mqtt,将nRF7002-DK接入到node-red系统,实现在nod-red中控制板载的两个LED。</p>

<p>&nbsp;</p>

<p><strong>一、nRF7002-DK接入到mqtt服务</strong></p>

<p>1. 从mqtt样例新建工程:</p>

<p>在VSCode的nRF Connect插件界面中,可以直接创建一个新的程序,模版使用样例:</p>

<p></p>

<p>&nbsp;</p>

<p>有好几个mqtt样例,这里直接选择第一个即可:&nbsp;</p>

<p> &nbsp;</p>

<p>添加完成,就会自动打开新建的工程:</p>

<p> &nbsp;</p>

<p>2. 配置修改:</p>

<p>要让这个工程,能够为nRF7002-DK所用,需要做一些配置处理。</p>

<p>1) 首先,先打开dts文件,看一下led的定义:</p>

<p>文件:/opt/nordic/ncs//v2.5.0/nrf/boards/arm/nrf7002dk_nrf7001_nrf5340/nrf7002dk_nrf7001_nrf5340_cpuapp.dts</p>

<p>led定义:</p>

<pre>
<code>    aliases {
        led0 = &amp;led0;
        led1 = &amp;led1;
        sw0 = &amp;button0;
        sw1 = &amp;button1;
        bootloader-led0 = &amp;led0;
    };</code></pre>

<p>从上述dts中可以看到,nRF7002-DK定义了两个led,命名为led0、led1</p>

<p>&nbsp;</p>

<p>2) 在prj.conf中开启GPIO,并设置WIFI连接信息</p>

<p>文件:prj.conf</p>

<pre>
<code class="language-ini"># WiFi
CONFIG_WIFI_CREDENTIALS_STATIC_SSID="OpenBSD"
CONFIG_WIFI_CREDENTIALS_STATIC_PASSWORD="********"
CONFIG_WIFI_CREDENTIALS_STATIC_TYPE_PSK=y

# GPIO
CONFIG_GPIO=y</code></pre>

<p>&nbsp;</p>

<p>3) 配置Kconfig:</p>

<p>文件:src/modules/transport/Kconfig.transport</p>

<pre>
<code>config MQTT_SAMPLE_TRANSPORT_BROKER_HOSTNAME
        string "MQTT broker hostname"
        default "192.168.1.15"

config MQTT_SAMPLE_TRANSPORT_BROKER_USERNAME
        string "MQTT broker username"
        default "test"

config MQTT_SAMPLE_TRANSPORT_BROKER_PASSWORD
        string "MQTT broker password"
        default "********"

config MQTT_SAMPLE_TRANSPORT_PUBLISH_TOPIC
        string "MQTT publish topic"
        default "device/report"

config MQTT_SAMPLE_TRANSPORT_SUBSCRIBE_TOPIC
        string "MQTT subscribe topic"
        default "device/cmd"</code></pre>

<p>在上述配置中,定义了mqtt服务的地址、用户名、密码,以及用于发布消息对应的topic:device/report,和接受命令对应的topic:device/cmd</p>

<p>在开发板上,通过mqtt发送消息出去,那么就发送到了 设备MAC/device/report</p>

<p>在开发板上,通过mqtt祸首命令消息,那么就要订阅&nbsp;设备MAC/device/cmd</p>

<p>&nbsp;</p>

<p>4) 修改sdk源码</p>

<p>sdk中,mqtt连接部分,之列把password留空了,不知道咋想的。好在提供了源码,我们可以自己修改。</p>

<p>文件:/opt/nordic/ncs/v2.5.0/nrf/include/net/mqtt_helper.h</p>

<pre>
<code class="language-cpp">struct mqtt_helper_conn_params {
        /* The hostname must be null-terminated. */
        struct mqtt_helper_buf hostname;
        struct mqtt_helper_buf device_id;
        struct mqtt_helper_buf user_name;
        struct mqtt_helper_buf password; // 新增的部分
};</code></pre>

<p>&nbsp;</p>

<p>文件:/opt/nordic/ncs/v2.5.0/nrf/subsys/net/lib/mqtt_helper/mqtt_helper.c</p>

<pre>
<code class="language-cpp">static int client_connect(struct mqtt_helper_conn_params *conn_params)
{
        int err;
        struct mqtt_utf8 user_name = {
                .utf8 = conn_params-&gt;user_name.ptr,
                .size = conn_params-&gt;user_name.size,
        };

        // 新增的部分-开始
        struct mqtt_utf8 password = {
                .utf8 = conn_params-&gt;password.ptr,
                .size = conn_params-&gt;password.size,
        };
        // 新增的部分-结束
       
        ...
       
        mqtt_client.user_name                = conn_params-&gt;user_name.size &gt; 0 ? &amp;user_name : NULL;
        // 新增的部分-开始
        mqtt_client.password                = conn_params-&gt;password.size &gt; 0 ? &amp;password : NULL;
        // 新增的部分-结束
       
        ...
       
}</code></pre>

<p>在上述代码中,添加password的定义,并在实际发送参数给mqtt服务的时候,带上传入参数的password</p>

<p>&nbsp;</p>

<p>5) 修改工程源码</p>

<p>首先修改文件: src/modules/sampler/sampler.c</p>

<pre>
<code class="language-cpp">#define FORMAT_STRING "Board is ready, uptime is: %d"</code></pre>

<p>然后修改核心处理文件:src/modules/transport/transport.c</p>

<pre>
<code class="language-cpp">// GPIO头文件
#include &lt;zephyr/drivers/gpio.h&gt;

// LED定义
#define LED1_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);

#define LED2_NODE DT_ALIAS(led1)
static const struct gpio_dt_spec led2 = GPIO_DT_SPEC_GET(LED2_NODE, gpios);

// LED状态
static uint8_t status1 = 0;
static uint8_t status2 = 0;

static void on_mqtt_publish(struct mqtt_helper_buf topic, struct mqtt_helper_buf payload)
{
        LOG_INF("Received payload: %.*s on topic: %.*s", payload.size,
                                                       payload.ptr,
                                                       topic.size,
                                                       topic.ptr);

        // 检查收到的指令
        payload.ptr = '\0';
        if(strcmp(payload.ptr, "LED1ON") == 0 ) {
                LOG_INF("led1: ON");
                status1 = 1;
        }
        else if(strcmp(payload.ptr, "LED1OFF") == 0 ) {
                LOG_INF("led1: OFF");
                status1 = 0;
        }
        else if(strcmp(payload.ptr, "LED2ON") == 0 ) {
                LOG_INF("led2: ON");
                status2 = 1;
        }
        else if(strcmp(payload.ptr, "LED2OFF") == 0 ) {
                LOG_INF("led2: OFF");
                status2 = 0;
        }
        else if(strcmp(payload.ptr, "LEDON") == 0 ) {
                LOG_INF("led1~2: ON");
                status1 = 1;
                status2 = 1;
        }
        else if(strcmp(payload.ptr, "LEDOFF") == 0 ) {
                LOG_INF("led1~2: OFF");
                status1 = 0;
                status2 = 0;
        }
        gpio_pin_set_dt(&amp;led1, status1);
        gpio_pin_set_dt(&amp;led2, status2);
}


static void transport_task(void)
{
    // 此处为添加的代码-开始
        // LED设备初始化
        int ret;

        if (!gpio_is_ready_dt(&amp;led1)) {
                LOG_ERR("led1 is not ready");
                return;
        }

        if (!gpio_is_ready_dt(&amp;led2)) {
                LOG_ERR("led2 is not ready");
                return;
        }

        ret = gpio_pin_configure_dt(&amp;led1, GPIO_OUTPUT_ACTIVE);
        if (ret &lt; 0) {
                LOG_ERR("led1 configure, error: %d", ret);
                return;
        }

        ret = gpio_pin_configure_dt(&amp;led2, GPIO_OUTPUT_ACTIVE);
        if (ret &lt; 0) {
                LOG_ERR("led2 configure, error: %d", ret);
                return;
        }

        // 默认关闭
        status1 = 0;
        status2 = 0;
        gpio_pin_set_dt(&amp;led1, status1);
        gpio_pin_set_dt(&amp;led2, status2);
    // 此处为添加的代码-结束
}</code></pre>

<p>&nbsp;</p>

<p>以上代码,实在原有演示代码的基础上进行添加的。</p>

<p>主要添加的内容包括:</p>

<ul>
        <li>添加gpio头文件</li>
        <li>定义LED1、LED2,分别对应dts中定义的led0、led1</li>
        <li>在&nbsp;on_mqtt_publish() 中,收到消息后,检查是否对应的控制指令</li>
        <li>在 transport_task() 中,进行GPIO LED设备的初始化</li>
</ul>

<p>控制指令具体对应关系如下:</p>

<ul>
        <li>LED1ON:打开LED1(对应dts-led0)</li>
        <li>LED1OFF:关闭LED1(对应dts-led0)</li>
        <li>LED2ON:打开LED2(对应dts-led1)</li>
        <li>LED2OFF:关闭LED2(对应dts-led1)</li>
        <li>LEDON:打开两个LED</li>
        <li>LEDOFF:关闭两个LED</li>
</ul>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>3. 编译测试</p>

<p>编译上述代码并下载到nRF7002-DK开发板:</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>下载完成后,使用串口监听工具监听,可以看到下面的输出信息:</p>

<p> &nbsp;</p>

<p>从上述输出可以看到,实际订阅的topic为:F4CE360026BC/device/cmd,那么上报消息对应的topic为:F4CE360026BC/device/report</p>

<p>根据不同的开发板,这里的 设备MAC地址前缀,是不同的。</p>

<p>&nbsp;</p>

<p>4) 使用mqttf客户端接受消息和下发控制指令</p>

<p>首先订阅&nbsp;F4CE360026BC/device/report 主题,以便接受消息。</p>

<p>然后给&nbsp;F4CE360026BC/device/cmd 发送控制指令:</p>

<p> &nbsp;</p>

<p>在串口监听工具中,也可以看到输出:</p>

<p> &nbsp;</p>

<p>同时,开发板上的LED,会跟随控制指令点亮或者熄灭。</p>

<p>&nbsp;</p>

<p><strong>二、nRF7002-DK接入node-red平台</strong></p>

<p>nRF7002-DK要接入node-red平台,本质是在node-red平台上,与对应的控制nRF7002-DK的mqtt的topic关联起来,从而实现在node-red上,通过mqtt控制nRF7002-DK。</p>

<p>&nbsp;</p>

<p>1. 安装node-red</p>

<p>我是在鲁班猫上安装node-red的,具体步骤如下:</p>

<pre>
<code class="language-bash">sudo apt update
sudo apt install npm
node -v
npm -v

# 配置国内镜像
npm config set registry http://mirrors.cloud.tencent.com/npm/
npm config get registry

# 建立工作目录
mkdir mkdir ~/Projects/node-red/node_modules
cd ~/Projects/node-red

# 安装node-red
npm install --unsafe-perm node-red
export PATH=/home/cat/Projects/node-red/node_modules/.bin:$PATH

# 启动出错,版本太低,至少要node 14
node-red</code></pre>

<p>但是,运行的时候,居然出错了:</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>经过查找资料,确定是nodejs版本太低,至少需要nodejs 14才可以运行。</p>

<p>&nbsp;</p>

<p>鲁班猫使用的是Ubuntu 22.04系统,使用nvm可以很方便的管理nodejs版本,下面就使用nvm来安装nodejs 14.</p>

<pre>
<code class="language-bash"># 安装nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
vim ~/.bashrc_nvm

# 使用nvm安装stable版本node
. ~/.bashrc_nvm
nvm install 14
nvm use 14
node -v
npm -v

# 重新安装:务必删除了,重新安装
rm -rf node_modules
npm install --unsafe-perm node-red
export PATH=/home/cat/Projects/node-red/node_modules/.bin:$PATH

# 启动
node-red</code></pre>

<p>需要注意的是,一定要把原有的node_modules目录删除了,重新进行,分则可能运行node-red的时候出现段错误。</p>

<p>安装完成,启动node-red,输出信息如下:</p>

<p><img alt="" data-sourcepos="670:1-670:30" src="localfile://path?assets/17024488598370.jpg" /> &nbsp;</p>

<p>2. node-red中文设置</p>

<p> &nbsp;</p>

<p> &nbsp;</p>

<p>设置完成后,要刷新一下界面,才会变为中文界面。</p>

<p>&nbsp;</p>

<p>3. 安装dashboard</p>

<p>要在界面上显示按钮,点击按钮时产生操作,需要安装dashboard界面ui模块,具体如下:</p>

<p> &nbsp;</p>

<p> &nbsp;</p>

<p>4. 添加按钮</p>

<p>在左边搜索button,然后依次添加6个按钮,对应如下:</p>

<p> &nbsp;</p>

<p>并依次设置每个按钮:</p>

<p> &nbsp;</p>

<p>5. 设置mqtt</p>

<p>在左边搜索mqtt,添加mqtt out,用于发送mqtt指令。</p>

<p>&nbsp;首次添加mqtt节点的时候,需要添加mqtt服务器的配置。&nbsp;</p>

<p>&nbsp;</p>

<p>6. 关联按钮到mqtt</p>

<p>从按钮尾部拉线到mqtt节点即可,将所有的按钮都连接到刚才添加的mqtt out节点:</p>

<p> &nbsp;</p>

<p>7. 添加UI界面:</p>

<p>在按钮配置界面的Group中,添加新的Tab和Group:</p>

<p> &nbsp;</p>

<p>然后从右上角的小箭头,选择dashboard,进入界面排版设置:</p>

<p> &nbsp;</p>

<p>在该界面,可以拖动按钮节点的位置,从而实现最终的按钮顺序:</p>

<p> &nbsp;</p>

<p>8. 部署查看</p>

<p>设置完成后,点击右上角的部署按钮:</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>如果提示有的按钮设置不正确,需要依次点进去,设置好对应的Group即可。</p>

<p>&nbsp;</p>

<p>正确无误部署好,打开浏览器:&nbsp; http://node-red服务器ip:1880/ui 即可查看基础的UI界面:</p>

<p></p>

<p>&nbsp;</p>

<p>在该界面上,点击对应的按钮,开发板会收到对应的控制指令,并进行LED的控制:</p>

<p> &nbsp;&nbsp;</p>

<p><strong>三、总结</strong></p>

<p>只要将nRF7002-DK接入了mqtt服务,那就相当于是给一座孤岛通上了网络,从此可以方便的和外界发生联系了。</p>

<p>在这片分享中,使用node-red这个低代码IoT平台,来实现简单快捷的接入nRF7002-DK,并实现通过界面按钮,来控制板载LED。</p>

<p>当然,这里只是一个基础的展示,还可以在nRF7002-DK上接入传感器,读取传感器的数值,并通过mqtt发布出去,例如使用温湿度传感器获取环境数据,mqtt发布后,node-red可以收到,并在界面上进行呈现,从而实现更丰富的功能和界面了。</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

chejm 发表于 2023-12-15 23:17

<p>楼主的分享十分有用,先收藏起来,慢慢学习,非常感谢楼主的无私奉献</p>

HonestQiao 发表于 2023-12-16 21:14

chejm 发表于 2023-12-15 23:17
楼主的分享十分有用,先收藏起来,慢慢学习,非常感谢楼主的无私奉献

<p>好东西,就是要一起分享</p>
页: [1]
查看完整版本: 【nRF7002-DK Wi-Fi® 6开发套件评测】接入开发板到node-red控制板载LED