当前位置: 首页 > news >正文

物联网WEB大屏数据可视化

最近了解WEB大屏显示。一般像嵌入式这类的,MQTT协议会走的多一些,走订阅和发布的策略,网上走了一圈之后,目前有几个实现方案。

这里对比一下几个物联网协议,相对而言MQTT更合适物联网,其它几个协议不是干这个的,不过我推荐一下DDS,这玩意还挺好用的。

(ps:最近了解到一个团队的实现方案是tcp。。。什么魔鬼设计,想的啥呢)

  1. 大屏实现方案

1.买物联网网关,附带WEB大屏服务,这里就不打广告了,自己找一圈,蛮多有支持的。

优势是,有些基础服务是免费的,硬件是现成的,有详细的指导文件。

缺点是,高级一些的服务是要收费的,不合适大批量生产,毕竟从底层硬件到前端程序都是人家的,要找到契合自己的网关也麻烦,比如我遇到的几个,都不支持MQTT协议接入。还有就是,数据都得去人家服务器,多少有点膈应。

2.买云服务器,比如阿里云的可视化数据服务,我整了个15天试用。

优点是,数据都是自己的。

缺点是,要买一堆的配套服务,比如协议转换,服务器啥的,死贵死贵的。

3.技术牛皮,那就自己搭建服务器,然后写前端后台嵌入式,我能搞,但这玩意费劲,要时间,而且中间肯定有那么两个环节自己得摸索一段时间。

优点,啥都是自己的,可定制化程度高,省钱,只要有个服务器就行。

缺点,费时费力。

4.找个低代码平台,看了一下,网上这种公司有,只是要掏钱

优点,省时省力,不花多少钱。

缺点,难找合适的。

  1. 推荐方案

对比一圈之后,还是选择了低代码平台,仔细想想,我是干嵌入式的,后台前端这些,对我来说是行业外的东西,可以去了解,但不需要深入,关键省钱就行。

私有部署 - 使用教程-免费低代码数据可视化平台-触达云屏 (topthink.com)

上面的方案个人觉得蛮合适,哔哩哔哩有教程,作者有个群,现在对大家都有技术支持,可以部署到局域网,重点是对个人免费,我觉得不花钱就可以打败一切了,这些都是他的资料。

  1. 服务器搭建

这部分其实是抄官方资料了,自己可以去看,我就抄linux搭建部分

全新安装说明 | 免费低代码数据可视化平台-触达云屏 (chudayun.com)

1,基础环境安装

安装以下基础环境(参考各官网)

Nginx

Mysql 5.7+

2,创建/导入数据库

初始化数据库:创建数据库 chudy_data_visual,执行 chudy_visual_[版本号] /doc 目录下的 初始化SQL文件

3,创建安装目录

分别执行以下三行命令,创建安装目录

cd /
mkdir app
mkdir app/java

4,部署安装

上传以下文件夹到服务器 /app 目录下

chudy_visual_[版本号]

filesystem

chudy_designer

上传 jdk-8u221-linux-x64.tar.gz文件 到服务器 /app/java目录下,解压。

cd /app/java
tar -zxvf jdk-8u221-linux-x64.tar.gz

修改数据库连接配置文件:

/app/chudy_visual_[版本号] /mgr/config 目录下 application-dev.properties

修改 数据库端口、名称、帐号、密码 等信息。

5,配置nginx

上传 chudy_designer 目录下的 chudy_visual.conf 文件到 服务器 nginx的 conf.d 目录下(一般在 /etc/nginx/conf.d/)

重载Nginx配置使配置生效。

防火墙中配置,放行端口 18088

6,启动应用

cd /app/chudy_visual_[版本号]/mgr/
./mgr.sh start
tail -f visual_cms.out

mgr.sh 支持启动、停止、重启、查看状态

./mgr.sh start | stop | restart | status

7,访问系统

http://IP:18088/

初始帐号 sadmin 密码 111111

  1. 设备端实现

目前测试,我是找了个温湿度传感器在折腾,实现方案是

传感器->C#上位机->MQTT协议->云屏

这里放出C#的代码(ps:反正是测试玩的,不重要)

代码

using System;
using System.Text;
using System.Windows.Forms;using System.IO.Ports;using System.Net;
using System.Net.Sockets;using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
using System.Threading.Tasks;
using System.Threading;namespace 开发快上位机
{public partial class Form1 : Form{public static IMqttClient _mqttClient;byte[] uart_data = new byte[100];byte uart_addr = 0;byte uart_start = 0;byte uart_time = 0;float wendu, shidu;public Form1(){InitializeComponent();System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;}private void Form1_Load(object sender, EventArgs e){button8.Enabled = false;serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);//必须手动添加事件处理程序}private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)//串口数据接收事件{try{uart_start = 1;uart_time = 0;int ilen = serialPort1.BytesToRead;byte[] bytes = new byte[ilen];serialPort1.Read(bytes, 0, ilen);for (int i = 0; i < ilen; i++){uart_data[uart_addr] = bytes[i];uart_addr++;}/*                if (!radioButton6.Checked)//如果接收模式为字符模式{int ilen = serialPort1.BytesToRead;byte[] bytes = new byte[ilen];serialPort1.Read(bytes, 0, ilen);//string str = System.Text.Encoding.Default.GetString(bytes); //xx="中文";//textBox1.AppendText(str);//添加内容}else{ //如果接收模式为数值接收byte data;data = (byte)serialPort1.ReadByte();//此处需要强制类型转换,将(int)类型数据转换为(byte类型数据,不必考虑是否会丢失数据//string str = Convert.ToString(data, 16).ToUpper();//转换为大写十六进制字符串//textBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");//空位补“0”   }*/}catch{textBox1.AppendText("串口数据接收出错,请检查!\r\n");}}private void button1_Click(object sender, EventArgs e){if (button1.Text == "串口连接"){try{serialPort1.PortName = comboBox1.Text;serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);serialPort1.Open();button1.Text = "断开连接";button2.Enabled = false;panel2.Enabled = false;comboBox1.Enabled = false;comboBox2.Enabled = false;comboBox3.Enabled = false;comboBox4.Enabled = false;textBox1.AppendText("串口已连接\r\n");}catch{if (serialPort1.IsOpen)serialPort1.Close();button1.Text = "串口连接";button2.Enabled = true;comboBox1.Enabled = true;panel2.Enabled = true;comboBox2.Enabled = true;comboBox3.Enabled = true;comboBox4.Enabled = true;textBox1.AppendText("请检查串口连接\r\n");}}else if (button1.Text == "断开连接"){try{serialPort1.Close();button1.Text = "串口连接";button2.Enabled = true;comboBox1.Enabled = true;comboBox2.Enabled = true;comboBox3.Enabled = true;panel2.Enabled = true;comboBox4.Enabled = true;textBox1.AppendText("串口已断开\r\n");}catch { }}}private void SearchAndAddSerialToComboBox(SerialPort MyPort, ComboBox MyBox){                                                               //将可用端口号添加到ComboBoxstring Buffer;                                              //缓存string[] MyString = new string[Convert.ToInt32(comboBox3.Text)];                         //最多容纳20个,太多会影响调试效率        MyBox.Items.Clear();                                        //清空ComboBox内容for (int i = 1; i < Convert.ToInt32(comboBox3.Text); i++)                                //循环{try{                                   //核心原理是依靠try和catch完成遍历progressBar1.Value = i * (100 / Convert.ToInt32(comboBox3.Text));Buffer = "COM" + i.ToString();MyPort.PortName = Buffer;MyPort.Open();                                      //如果失败,后面的代码不会执行MyString[i - 1] = Buffer;MyBox.Items.Add(Buffer);                            //打开成功,添加至下俩列表comboBox1.Text = Buffer.ToString();MyPort.Close();                                     //关闭}catch { }}}private void button2_Click(object sender, EventArgs e){textBox1.AppendText("开始自动配置串口\r\n");//出错提示textBox1.AppendText("串口扫描\r\n");//出错提示SearchAndAddSerialToComboBox(serialPort1, comboBox1);       //扫描并讲课用串口添加至下拉列表textBox1.AppendText("端口扫描完毕\r\n");//出错提示textBox1.AppendText("正在配置波特率\r\n");//出错提示comboBox2.Text = comboBox4.Text;serialPort1.BaudRate = Convert.ToInt32(comboBox2.Text);progressBar1.Value = 0;textBox1.AppendText("自动配置完成\r\n");//出错提示button1_Click(sender, e);}private void button3_Click(object sender, EventArgs e){textBox1.Clear();}private void button5_Click(object sender, EventArgs e){textBox3.Clear();}private void button4_Click(object sender, EventArgs e){System.IO.File.WriteAllText(@"C:\Users\Administrator\Desktop\发送区数据.txt", textBox1.Text);System.IO.File.WriteAllText(@"C:\Users\Administrator\Desktop\接收区数据.txt", textBox3.Text);textBox1.AppendText("数据保存完成!\r\n");}void uart_send(object sender, EventArgs e,string data){byte[] Data = new byte[1];//作用同上集if (serialPort1.IsOpen)//判断串口是否打开,如果打开执行下一步操作{try{if (data != ""){if (!radioButton6.Checked)//如果发送模式是字符模式{try{//实现串口发送汉字Encoding gb = System.Text.Encoding.GetEncoding("gb2312");byte[] bytes = gb.GetBytes(data);serialPort1.Write(bytes, 0, bytes.Length);}catch{textBox1.AppendText("串口数据写入错误\r\n");//出错提示serialPort1.Close();button1_Click(sender, e);}}else{for (int i = 0; i < (data.Length - data.Length % 2) / 2; i++)//取余3运算作用是防止用户输入的字符为奇数个{Data[0] = Convert.ToByte(data.Substring(i * 2, 2), 16);serialPort1.Write(Data, 0, 1);//循环发送(如果输入字符为0A0BB,则只发送0A,0B)}if (data.Length % 2 != 0)//剩下一位单独处理{Data[0] = Convert.ToByte(data.Substring(data.Length - 1, 1), 16);//单独发送B(0B)serialPort1.Write(Data, 0, 1);//发送}}}}catch{textBox1.AppendText("串口数据写入错误\r\n");//出错提示}}}private void button6_Click(object sender, EventArgs e){uart_send(sender,e, textBox3.Text);}private void button9_Click(object sender, EventArgs e){var optionsBuilder = new MqttClientOptionsBuilder().WithTcpServer(textBox2.Text, Convert.ToInt16(textBox4.Text)) // 要访问的mqtt服务端的 ip 和 端口号.WithCredentials("admin", "123456") // 要访问的mqtt服务端的用户名和密码.WithClientId("testclient02") // 设置客户端id.WithCleanSession().WithTls(new MqttClientOptionsBuilderTlsParameters{UseTls = false  // 是否使用 tls加密});var clientOptions = optionsBuilder.Build();_mqttClient = new MqttFactory().CreateMqttClient();_mqttClient.ConnectedAsync += _mqttClient_ConnectedAsync; // 客户端连接成功事件_mqttClient.DisconnectedAsync += _mqttClient_DisconnectedAsync; // 客户端连接关闭事件_mqttClient.ApplicationMessageReceivedAsync += _mqttClient_ApplicationMessageReceivedAsync; // 收到消息事件_mqttClient.ConnectAsync(clientOptions);}/// <summary>/// 客户端连接关闭事件/// </summary>/// <param name="arg"></param>/// <returns></returns>private Task _mqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg){button8.Enabled = false;button9.Text = "连接";textBox6.AppendText($"客户端已断开与服务端的连接……\n");return Task.CompletedTask;}/// <summary>/// 客户端连接成功事件/// </summary>/// <param name="arg"></param>/// <returns></returns>private Task _mqttClient_ConnectedAsync(MqttClientConnectedEventArgs arg){button8.Enabled = Enabled;button9.Text = "断开";textBox6.AppendText($"客户端已连接服务端……\n");// 订阅消息主题// MqttQualityOfServiceLevel: (QoS):  0 最多一次,接收者不确认收到消息,并且消息不被发送者存储和重新发送提供与底层 TCP 协议相同的保证。// 1: 保证一条消息至少有一次会传递给接收方。发送方存储消息,直到它从接收方收到确认收到消息的数据包。一条消息可以多次发送或传递。// 2: 保证每条消息仅由预期的收件人接收一次。级别2是最安全和最慢的服务质量级别,保证由发送方和接收方之间的至少两个请求/响应(四次握手)。_mqttClient.SubscribeAsync("sub", MqttQualityOfServiceLevel.AtLeastOnce);return Task.CompletedTask;}/// <summary>/// 收到消息事件/// </summary>/// <param name="arg"></param>/// <returns></returns>private Task _mqttClient_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg){textBox6.AppendText($"Topic主题=【{arg.ApplicationMessage.Topic}】 消息={Encoding.UTF8.GetString(arg.ApplicationMessage.Payload)}");string str = Encoding.UTF8.GetString(arg.ApplicationMessage.Payload);if (str.Contains("on") || str.Contains("off")){textBox6.AppendText("\r\n控制继电器\r\n");//出错提示byte[] Data = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xc4, 0x0b };//作用同上集if (serialPort1.IsOpen)//判断串口是否打开,如果打开执行下一步操作{try{serialPort1.Write(Data, 0, 8);//循环发送(如果输入字符为0A0BB,则只发送0A,0B)}catch{textBox1.AppendText("串口数据写入错误\r\n");//出错提示}}}//textBox6.AppendText($"ApplicationMessageReceivedAsync:客户端ID=【{arg.ClientId}】接收到消息。 Topic主题=【{arg.ApplicationMessage.Topic}】 消息=【{Encoding.UTF8.GetString(arg.ApplicationMessage.Payload)}】 qos等级=【{arg.ApplicationMessage.QualityOfServiceLevel}】");return Task.CompletedTask;}public void Publish(string topic,string data){var message = new MqttApplicationMessage{Topic = topic,Payload = Encoding.Default.GetBytes(data),QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce,Retain = true  // 服务端是否保留消息。true为保留,如果有新的订阅者连接,就会立马收到该消息。};_mqttClient.PublishAsync(message);}private void button8_Click(object sender, EventArgs e){if(textBox8.Text != "")Publish(textBox7.Text,textBox8.Text);}private void button7_Click(object sender, EventArgs e){textBox6.Text = "";textBox8.Text = "";}private void button10_Click(object sender, EventArgs e){textBox6.AppendText("\r\n读取温度\r\n");//出错提示byte[] Data = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0xc4, 0x0b };//作用同上集if (serialPort1.IsOpen)//判断串口是否打开,如果打开执行下一步操作{try{serialPort1.Write(Data, 0, 8);//循环发送(如果输入字符为0A0BB,则只发送0A,0B)}catch{textBox1.AppendText("串口数据写入错误\r\n");//出错提示}}}string zhongliang1 = "{\"value\":";string zhongliang2 = ",\"unit\": \"Kg\",\"min\": 0,\"max\": 100,\"label\": \"11\"}";string wenshidu1 = "[{\"extObj\": {},\"value\": \"";string wenshidu2 = "\",\"prefixText\": \"\",\"suffixText\": \"\",\"descText\": \"\",\"backgroundColor\": \"\",\"icon\": \"\",\"color\": \"\"}]";private void button11_Click(object sender, EventArgs e){string data;data = wenshidu1 + textBox9.Text + wenshidu2;Publish("wendu", data);}private void button12_Click(object sender, EventArgs e){string data;data = wenshidu1 + textBox10.Text + wenshidu2;Publish("shidu", data);}private void button13_Click(object sender, EventArgs e){string data;data = zhongliang1 + textBox11.Text + zhongliang2;Publish("zhongliang", data);}private void timer1_Tick(object sender, EventArgs e){if (uart_start == 1){uart_time++;if (uart_time >= 100){textBox1.AppendText(uart_addr.ToString());//空位补“0”for (int i = 0; i < uart_addr; i++){string str = Convert.ToString(uart_data[i], 16).ToUpper();//转换为大写十六进制字符串textBox1.AppendText("0x" + (str.Length == 1 ? "0" + str : str) + " ");//空位补“0”}if (uart_data[0] == 0x01 && uart_data[1] == 0x03 && uart_data[2] == 0x04){shidu = uart_data[3] << 8 | uart_data[4];wendu = uart_data[5] << 8 | uart_data[6];shidu = shidu / 10;wendu = wendu / 10;string str1,str2;textBox9.Text = wendu.ToString();textBox10.Text = shidu.ToString();button11_Click(sender,  e);button12_Click(sender,  e);}uart_start = 0;uart_time = 0;uart_addr = 0;}}}}
}
  1. 测试效果

简化操作,直接搞了几个按键去发

当然实际项目不会这么干,实际项目的构成应该是

  1. 单片机接传感器,以MODBUS/无线等方式提供数据访问接口

  1. linux网关实现数据转发,比如NXP的IMX6,上面实现MQTT客户端

  1. 云服务器做MQTT服务器,实现数据转发

  1. WEB云屏/微信小程序/桌面应用等订阅MQTT数据

上面是我的微信和QQ群,欢迎新朋友的加入。

相关文章:

物联网WEB大屏数据可视化

最近了解WEB大屏显示。一般像嵌入式这类的&#xff0c;MQTT协议会走的多一些&#xff0c;走订阅和发布的策略&#xff0c;网上走了一圈之后&#xff0c;目前有几个实现方案。这里对比一下几个物联网协议&#xff0c;相对而言MQTT更合适物联网&#xff0c;其它几个协议不是干这个…...

新:DlhSoft Gantt Chart for WPF Crack

用于 Silverlight/WPF 4.3.48 的 DlhSoft 甘特图灯光库 改进甘特图、网络图和 PERT 图表组件的 PERT 关键路径算法。2023 年 3 月 2 日 - 17:09新版本特征 改进了甘特图、网络图和 PERT 图表组件的 PERT 关键路径算法。Silverlight/WPF 标准版的 DlhSoft 甘特图灯光库 DlhSoft …...

C++基础(一)—— C++概述、C++对C的扩展(作用域、struct类型、引用、内联函数、函数默认参数、函数占位参数、函数重载)

1. C概述1.1 c简介“c”中的来自于c语言中的递增运算符&#xff0c;该运算符将变量加1。c起初也叫”c withclsss”.通过名称表明&#xff0c;c是对C的扩展&#xff0c;因此c是c语言的超集&#xff0c;这意味着任何有效的c程序都是有效的c程序。c程序可以使用已有的c程序库。为什…...

Rust学习总结之if,while,loop,for使用

目录 一&#xff1a;if的使用 二&#xff1a;while的使用 三&#xff1a;loop的使用 四&#xff1a;for的使用 本文总结的四种语句&#xff08;if&#xff0c;while&#xff0c;loop&#xff0c;for&#xff09;除了loop&#xff0c;其他的三个在C语言或者Python中都是常见…...

Java知识复习(十一)RabbitMQ

1、RabbitMQ简介 RabbitMQ 是采用 Erlang 语言实现 AMQP(Advanced Message Queuing Protocol&#xff0c;高级消息队列协议&#xff09;的消息中间件 2、RabbitMQ核心概念 RabbitMQ 整体上是一个生产者与消费者模型&#xff0c;主要负责接收、存储和转发消息 3、Producer和…...

thinkphp图片压缩类

<?php namespace app\lib; /** * 图片压缩类&#xff1a;通过缩放来压缩。 * 如果要保持源图比例&#xff0c;把参数$percent保持为1即可。 * 即使原比例压缩&#xff0c;也可大幅度缩小。数码相机4M图片。也可以缩为700KB左右。如果缩小比例&#xff0c;则体积会更小。…...

如何将图数据库应用于电影智能推荐

导读 电影&#xff0c;是一种结合视觉与听觉的现代艺术。如今&#xff0c;电影已不单是人们娱乐消遣的生活方式&#xff0c;也逐渐成为国家文化软实力的重要标志之一。据有关数据统计&#xff0c;2021年中国影视行业市场规模达2349亿元&#xff0c;同比增长23.2%&#xff0c;预…...

CSS实现动画效果的菜单收起展开图标,html实现动画效果的箭头

效果 实现代码 此处JS代码引入了jquery <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><style>.menu-icon{position: absolute;left: 20%;top: 30%;transition: all .3s;}.menu-icon:before, .menu…...

大数据平台小结

搭建大数据平台启动流程1、启动Nginx服务&#xff08;在bdp-web-mysql服务中&#xff09;cd /usr/local/nginx/# 启动Nginx ./sbin/nginx# 查看端口是否存在 netstat -tunlp|grep 200012、启动zookeeper&#xff08;在bdp-executor-realtime123&#xff09;cd /app/bdp/apache-…...

力扣-139单词拆分

力扣-139单词拆分 1、题目 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 示例 1&#xff1a; 输入: s "…...

图机器学习-图神经网络

图神经网络 前面讲了图机器学习的一些传统方法&#xff0c;现在正式进入到课程的核心部分&#xff1a;图神经网络。 Design of GNN 那么图神经网络和我们之前接触的一些深度神经网络有什么不同呢&#xff1f; 对于别的类型的神经网络&#xff0c;往往我们都是处理一些类似网…...

配置Airbyte资源限制

资源限制有三种不同的级别配置&#xff1a;Instance-wide - 应用到Airbyte实例创建的Sync Job的所有容器上。Connector-specific - 应用到Airbyte实例创建的Sync Job的所有指定类型连接器的容器上Connection-specific - 应用到Airbyte实例创建的Sync Job的所有指定管道的容器上…...

python实现PCA降维画分类散点图并标出95%的置信区间

此代码以数据集鸢尾花为例&#xff0c;对其使用PCA降维后&#xff0c;绘制了三个类别的样本点和对应的置信圆&#xff08;即椭圆&#xff09;。先放效果图。 下面是完整代码&#xff1a; from matplotlib.patches import Ellipsedef plot_point_cov(points, nstd3, axNone, **…...

Mysql高级之索引结构详解

Mysql的索引详解1.索引定义2.索引结构2.1数据结构分析2.1.1熟知的数据结构2.1.2分析为什么这么多的数据结构不全适用于索引结构2.2Hash结构2.3B tree结构3.索引分类3.1聚集索引&#xff08;聚簇索引&#xff09;3.2非聚集索引&#xff08;稀疏索引&#xff09;3.3联合索引3.4主…...

【线程-J.U.C】

Lock J.U.C最核心组件&#xff0c;Lock接口出现之前&#xff0c;多线程的并发安全只能由synchronized处理&#xff0c;但java5之后&#xff0c;Lock的出现可以解决synchronized的短板&#xff0c;更加灵活。 Lock本质上是一个接口&#xff0c;定义了释放锁&#xff08;unlock&…...

docker布署spring boot jar包项目

目录docker 安装创建目录制作镜像启动容器查看日志docker 安装 Docker安装、详解与部署 创建目录 服务器中创建一个目录&#xff0c;存放项目jar包和Dockerfile 文件 mkdir /目录位置创建目录后创建Dockerfile文件&#xff0c;上传jar包到同一目录下 创建dockerfile vim Doc…...

极简Vue3教程--Pinia状态管理

Pinia&#xff08;发音为/piːnjʌ/&#xff0c;如英语中的“peenya”&#xff09;是最接近pia&#xff08;西班牙语中的菠萝&#xff09;的词&#xff1b;Pinia开始于大概2019年&#xff0c;最初是作为一个实验为Vue重新设计状态管理&#xff0c;让它用起来像组合式API&#x…...

常用的map转bean互转方法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 常用的map转bean互转方法一、hutool工具类二、fastjson工具类三、beanutils_BeanUtils工具类 不太好用四、cglib BeanMap工具类 不太好用五、reflect 反射来玩 不太好玩六、I…...

2.4G收发一体芯片NRF24L01P跟国产软硬件兼容 SI24R1对比

超低功耗高性能 2.4GHz GFSK 无线收发器芯片Si24R1&#xff0c;软硬件兼容NRF24L01P. Si24R1 是一颗工作在 2.4GHz ISM 频段&#xff0c;专为低功耗无线场合设计&#xff0c;集成嵌入式ARQ 基带协议引擎的无线收发器芯片。工作频率范围为 2400MHz-2525MHz&#xff0c;共有 126个…...

设计模式之七大原则(一)——单一职责原则、开放-关闭原则

目录一、设计模式的目的二、设计模式的七大原则1.单一职责原则2.开放-关闭原则一、设计模式的目的 设计模式的目的是为了提高代码重用性、可读性、可扩展性、可靠性&#xff0c;使得程序呈现出高内聚、低耦合的特性。 代码重用性&#xff08;相同功能的代码&#xff0c;不用多…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

Frozen-Flask :将 Flask 应用“冻结”为静态文件

Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是&#xff1a;将一个 Flask Web 应用生成成纯静态 HTML 文件&#xff0c;从而可以部署到静态网站托管服务上&#xff0c;如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...