-- Table structure for table `WisdomBarReply`
--

CREATE TABLE `WisdomBarReply` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `rid` int(11) NOT NULL,
  `content` text NOT NULL,
  `imgtext` varchar(80) NOT NULL DEFAULT '',
  `date` datetime NOT NULL,
  `userid` int(11) NOT NULL,
  KEY `id` (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=290 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;

--
-- Dumping data for table `WisdomBarReply`
--

INSERT INTO `WisdomBarReply` VALUES
(282,339,'喷雾器更换锂电池34元','','2025-06-27 07:19:00',1),
(281,339,'喷雾器喷杆9元','','2025-06-27 07:19:00',1),
(280,339,'芸苔素 12 +磷酸二氢钾19+钙镁鹏锌铁10+比作米40+螺螨酯84+阿维49=214元','','2025-06-27 11:44:00',1),
(278,339,'ros217  170+160=330元','','2025-06-27 11:39:00',1),
(279,339,'除草 21+19+14=54元','','2025-06-27 11:40:00',1),
(277,339,'5袋尿素100元','','2025-06-27 11:38:00',1),
(276,338,'收费25','','2025-06-27 11:16:00',1),
(283,340,'200','','2025-08-22 06:26:00',1),
(284,340,'200','','2025-08-27 12:12:00',1),
(285,207,'跟箱子重5.5斤(也就是3瓶小机油)','','2025-08-31 07:28:00',1),
(286,342,'人和村 经纬度 24.844029,108.312899','','2025-09-07 01:55:00',1),
(287,340,'200','','2025-09-08 07:30:00',1),
(288,340,'200','','2025-09-11 07:27:00',1),
(289,340,'200','','2025-09-19 12:48:00',1);

--
-- Table structure for table `WisdomProgram`
--

CREATE TABLE `WisdomProgram` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(20) NOT NULL DEFAULT '',
  `userid` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;

--
-- Dumping data for table `WisdomProgram`
--

INSERT INTO `WisdomProgram` VALUES
(1,'linux树莓派',1),
(2,'mysql',1),
(3,'golang',1),
(4,'arduino',1),
(5,'c++',1),
(6,'stm32',1),
(7,'php',1),
(8,'python',1);

--
-- Table structure for table `WisdomProgramReply`
--

CREATE TABLE `WisdomProgramReply` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tid` int(11) NOT NULL DEFAULT 0,
  `title` varchar(64) NOT NULL DEFAULT 'null',
  `content` text NOT NULL,
  `imgtext` varchar(100) NOT NULL DEFAULT '',
  `userid` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=318 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;

--
-- Dumping data for table `WisdomProgramReply`
--

INSERT INTO `WisdomProgramReply` VALUES
(1,1,'linux 服务器设置','\r\nsudo passwd root //设置root密码\r\n密码\r\n密码\r\nsu root //登陆root\r\n//配置 ssh权限\r\nvi /etc/ssh/sshd_config\r\n\r\nLoginGraceTime 2m\r\nPermitRootLogin yes\r\n//把#号去掉,保存退出\r\n---------------------------------------------------\r\n//更新系统\r\napt-get update\r\n\r\n--------------------安装mysql ------------------------\r\nsudo apt-get install mysql-server mysql-client\r\n\r\n//设置 mysql 可以外网访问\r\nsudo vim /etc/mysql/mysql.conf.d/mysqld.cnf\r\nbind-address前添加 #注释掉该行\r\n\r\n//还没设置前用户不需要密码\r\nsudo mysql -uroot -p //回车 \r\n//远程访问数据库\r\nupdate mysql.user set host=\'%\';\r\nflush privileges;\r\n//更改密码\r\nALTER USER \'root\'@\'%\' IDENTIFIED WITH mysql_native_password BY \'qq282246101\';\r\nflush privileges;\r\nexit\r\n------------------------------------------------------\r\n//杀死之前的相关进程\r\nps -e|grep apt-get \r\n//安装gcc\r\napt install gcc\r\n------------------------------------------------------\r\n//支持程序关机\r\nchmod 4777 /sbin/shutdown\r\n------------------------------------------------------\r\n//校准时间\r\nsudo dpkg-reconfigure tzdata\r\nAsia\r\nshanghai\r\n//查看时间是否准确\r\ndate \r\n//安装,设置开机同步时间\r\napt install ntpdate\r\ncrontab -e\r\n@reboot ntpdate ntp.ubuntu.com\r\n@reboot sleep 3; cd /opt/website; nohup ./main &\r\n------------------------------------------------------\r\n# 安装redis\r\nsudo apt install redis-server\r\n# 配置\r\nsudo vim /etc/redis/redis.conf\r\n# 找到 supervised 设置为 systemd\r\nsudo service redis restart  # 重新加载Redis服务文件\r\nsudo systemctl status redis # 查看 Redis 的运行状态\r\n# 一些操作\r\nsudo service redis start  # 启动\r\nsudo service redis stop  # 关闭\r\nsudo service redis restart  # 重启\r\nredis-cli  # 客户端连接\r\n# 远程连接 \r\nsudo vi /etc/redis/redis.conf\r\n# 将 bind 127.0.0.1 ::1 改为 bind 0.0.0.0\r\nsudo service redis restart  # 重启\r\n# 设置密码\r\nsudo vi /etc/redis/redis.conf\r\n# 设置：requirepass 自己的密码\r\n默认端口6379\r\nredis-server /etc/redis/redis.conf --test 用于找出配置错误','',1),
(2,1,' php也能执行关机命令shutdown 网卡ifconfig','//root用户登陆\r\nchmod 4755 /sbin/shutdown\r\n\r\nchmod 4755 /sbin/ifconfig\r\n          ','',1),
(3,1,'ubuntu 18 设置wifi开机自动连接','apt install wireless-tools\r\n安装完后，就可以使用iwconfig按下面步骤设置无线网络了\r\niwconfig wlan0 power on\r\nifconfig wlan0 up\r\niwconfig wlan0 essid \"无线名称\"\r\n//然后使用wpa_passphrase生成无线密钥\r\nsudo -i \r\nwpa_passphrase 无线名称 密码 > /etc/wpa_supplicant/wpa_supplicant.conf\r\nvim /etc/wpa_supplicant/wpa_supplicant.conf\r\n//里面应该有大致以下内容\r\nnetwork={\r\n        ssid=\"my_network\"   #注意ssid名区分大小写。\r\n        proto=RSN           #Robust Security Network:强健安全网络，表示这个网络配置比WEP模式要更安全。\r\n        key_mgmt=WPA-PSK    #请无论你是使用WPA-PSK，WPA2-PSK，都请在这里输入 WPA-PSK。这在wpa_supplicant看来WPA-PSK，WPA2-PSK都是 WPA-PSK\r\n        pairwise=CCMP TKIP  #关键点，wpa_supplicant目前还不认AES的加密标准\r\n        group=CCMP TKIP     #同上\r\n        psk=7b271c9a7c8a6ac07d12403a1f0792d7d92b5957ff8dfd56481ced43ec6a6515 #wpa_supplicant算出来的加密密码。\r\nchmod +wrx /etc/wpa_supplicant.conf\r\n//以上配置文件设置完成后，接下来手动应用配置\r\n//为了开机自动开启wifi，需要将启动脚本加到自动执行服务中，首先在/etc/rc.local中加入如下脚本：\r\n#!/bin/bash\r\nip link set wlan0 up && killall wpa_supplicant && wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf &&\r\ndhclient wlan0\r\nexit 0\r\nchmod a+x /etc/rc.local\r\n然后编辑 /lib/systemd/system/rc-local.service加入如下配置：\r\n[Unit]\r\nDescription=/etc/rc.local Compatibility\r\nDocumentation=man:systemd-rc-local-generator(8)\r\nConditionPathExists=/etc/rc.local\r\nAfter=network.target\r\n\r\n[Service]\r\nType=forking\r\nExecStart=/etc/rc.local start\r\nTimeoutSec=0\r\nRemainAfterExit=yes\r\nGuessMainPID=no\r\n[Install]\r\nWantedBy=multi-user.target\r\nAlias=rc-local.service\r\n\r\nsystemctl enable rc-local.service\r\nsystemctl disable rc-local.service\r\nsystemctl start rc-local.service\r\nsystemctl status rc-local.service\r\n如下内容为成功了\r\n● rc-local.service - /etc/rc.local Compatibility\r\n   Loaded: loaded (/lib/systemd/system/rc-local.service; enabled; vendor preset: enabled)\r\n  Drop-In: /lib/systemd/system/rc-local.service.d\r\n           └─debian.conf\r\n   Active: active (running) since Fri 2019-10-25 16:03:17 UTC; 26min ago\r\n     Docs: man:systemd-rc-local-generator(8)\r\n  Process: 1621 ExecStart=/etc/rc.local start (code=exited, status=0/SUCCESS)\r\n    Tasks: 2 (limit: 1056)\r\n   CGroup: /system.slice/rc-local.service\r\n           ├─1627 wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf\r\n           └─1647 dhclient wlan0\r\n//重启\r\nreboot ','',1),
(4,1,'ffmpeg','ffmpeg -i 查看 视频文件属性\r\n1.pass1编码\r\n\r\nffmpeg -i 01.rmvb -an -vcodec libx264 -b 560k -pass 1 -f mp4 -y 新名.mp4\r\n\r\n-acodec libfaac output.aac 音频编码 aac\r\n-an : 不编码音频\r\n-vcodec : 设置视频的编码，我这里使用的是x264\r\n-b : 这个是码率\r\n-f : 强制使用格式\r\n-y : 自动输y确认\r\nNUL : 因为是pass1 所以不需要输出文件，直接用NUL\r\n\r\n2.pass2编码\r\n\r\nffmpeg -i 01.rmvb -acodec copy -vcodec libx264 -b 560k -pass 2 -f mp4 01.mp4\r\n\r\n因为现在很多rmvb的音频部分都是aac编码的，所以可以直接用-acodec copy复制音频部份\r\n3、针对某些文件的参数调整\r\n\r\n有些rmvb或着mkv之类的分辨率比较高，所以传到itouch需要调整一下。在ffmpeg里面可以用-s参数:\r\n\r\nffmpeg -i 01.rmvb -acodec copy -vcodec libx264 -b 560k -s 960x640 -f mp4 01.mp4\r\n\r\n960x640需要自己计算一下，按比例进行调整\r\n\r\n按时间截取:\r\n\r\nffmpeg -i 01.rmvb -acodec copy -vcodec libx264 -b 560k -ss 00:00:00 -t 00:01:00 -f mp4 01.mp4\r\n\r\n设置B-frame对动画片有些好处，2pass的时候不是很明显，1pass的比较明显:\r\n\r\nffmpeg -i 01.rmvb -acodec copy -vcodec libx264 -b 560k -bf 6 -f mp4 01.mp4\r\n\r\n\r\nwindows下安装\r\n可以将 ffmpeg 的 bin 目录（包含 ffmpeg.exe、ffprobe.exe 等文件）添加到系统的环境变量中','',1),
(5,1,'ceate_ap开启热点','在终端中运行 rfkill list，查看所有被禁用的无线设备列表。如果 wlan0 被列出并显示为 Soft blocked: yes（软件禁用）或 Hard blocked: yes（硬件禁用），则需要解除禁用。\r\n sudo rfkill unblock wlan\r\n这将尝试解除对无线设备的软件禁用\r\nifconfig wlan0 up\r\n//安装依赖库\r\nsudo apt-get install hostapd\r\nsudo apt-get install network-manager\r\nsudo apt-get install util-linux procps hostapd iproute2 iw haveged dnsmasq\r\n//也可以QQ云盘里下载create_ap-master.zip再安装\r\nsudo git clone https://github.com/oblique/create_ap\r\ncd create_ap\r\nsudo make install\r\n//临时启用热点 360xyz是wifi名  qq282246101是密码\r\n//sudo create_ap wlan0 eth0 360xyz qq282246101\r\nsudo apt install iptables\r\n//修改 create_ap.service 服务功能的配置\r\nsudo vim /etc/create_ap.conf\r\n————————WiFi 2.4g 只需要改这三项————————\r\n//固定设置自己的 GATEWAY（网关）、SSID（热点名）、PASSPHRASE（密码）\r\nGATEWAY=???\r\nSSID=???\r\nPASSPHRASE=???\r\n\r\n//防止它人连接WIFI\r\nMAC_FILTER=0    //1代表使用MAC过滤\r\nMAC_FILTER_ACCEPT=/etc/hostapd/hostapd.accept   \r\n// 创建hostapd.accept 文件 这个文件存MAC地址，有地址才能访问网络\r\ntouch /etc/hostapd/hostapd.accept\r\ncd /etc/hostapd\r\nchmod ugo+x hostapd.accept\r\nvi hostapd.accept\r\n6a:e4:07:75:d2:ee  #我的手机\r\n5a:ab:53:13:82:98  #小罗手机\r\nd0:fa:1d:11:a1:8f   #360摄像头\r\n\r\n—————---WiFi 5G 配置增加如下修改——————---\r\n//149信道是5G信道\r\nCHANNEL=149 \r\nIEEE80211N=1\r\nIEEE80211AC=1\r\nCOUNTRY=US  \r\n\r\n\r\n//设置服务开机启动。\r\nsystemctl enable create_ap.service\r\n//查看服务是否开机启动。\r\nsystemctl is-enable create_ap\r\n\r\n# 启动服务：\r\nsystemctl start create_ap\r\n# 关闭服务：\r\nsystemctl stop create_ap\r\n# 重启服务：\r\nsystemctl restart create_ap\r\n# 显示服务状态：\r\nsystemctl status create_ap\r\n# 禁用服务开机启动：\r\nsystemctl disable create_ap.service\r\n//连接有线网络就是无线中继器,断开有线就是独立AP\r\n\r\n//设置发射功率 调小\r\nsudo iwconfig wlan0 txpower 5\r\nsudo create_ap --fix-unmanaged\r\nvi /etc/hosts //设置别名访问特IP  写入\r\n127.0.0.1 raspberry.nobiggie.cn\r\n','',1),
(6,1,'Ubuntu下卸载nginx','sudo apt-get remove nginx nginx-common # 卸载删除除了配置文件以外的所有文件\r\nsudo apt-get purge nginx nginx-common # 卸载所有东东，包括删除配置文件\r\nsudo apt-get autoremove # 在上面命令结束后执行，主要是卸载删除Nginx的不再被使用的依赖包\r\nsudo apt-get remove nginx-full nginx-common #卸载删除两个主要的包。','',1),
(7,1,'ubuntu 重装php7','一、删除php的相关包及配置\r\n    sudo apt-get autoremove php7*\r\n二、删除关联\r\n    sudo find /etc -name \"*php*\" |xargs  rm -rf\r\n三、清除dept列表\r\n    sudo apt purge `dpkg -l | grep php| awk \'{print $2}\' |tr \"\\n\" \" \"`','',1),
(8,1,'crontab 定时任务','#开机启动go程序\r\n@reboot sleep 3; cd /var/www/html; nohup ./main &\r\n#如果启动失败\r\n@reboot sleep 3; cd /var/www/html; nohup ./main\r\n#晚上关闭WIFI\r\n#0 20 * * * ifconfig wlan0 down\r\n\r\n#每天夜里1点30分备分远程服务器数据库到本地\r\n#30 1 * * * /var/www/html/mysql_source.sh\r\n\r\n#夜里关机 chmod 4777 /sbin/shutdown\r\n#30 2 * * * /sbin/shutdown -h now\r\n\r\n#每次重启后 清空redis数据 启动swoole_redis (限php swoole) 启动swoole_websocket\r\n#@reboot rm -f /var/www/html/app/Libraries/myclass/server/db\r\n#@reboot sleep 10; /usr/bin/php /var/www/html/app/Libraries/myclass/server/Swoole_redis.php > /dev/null &\r\n#@reboot sleep 20; /usr/bin/php /var/www/html/app/Libraries/myclass/server/Swoole_websocket.php > /dev/null &\r\n\r\n#4到8月份检测CPU温度过60度保护关机\r\n#* * * 4-8 * /usr/bin/curl http://localhost/service/CpuHighDown\r\n#定时提醒 每天早上6点触发\r\n0 6 * * * /usr/bin/curl http://localhost/service/TimeingSend\r\n\r\n#每天早上6点10分自动校准时间\r\n#10 6 * * * /usr/sbin/ntpdate ntp.ubuntu.com;/sbin/hwclock -w','',1),
(9,1,' 树莓派花生壳信息\r\n',' Oray Phtunnel Raspberry 5.0.0 \r\n --------------------------------\r\n  SN: oray296b3a9ef73f \r\n  Default password: admin  |\r\n -------------------------------\r\n Remote Management Address http://b.oray.com\r\n\r\n1、输入命令：phddns回车，可以看到扩展功能。phddns start（启动）| status（状态）| stop（停止）|restart（重启）| reset（重置）|enable（开机自启动）|disable（关闭开机自启动）|version（版本）\r\n日志文件存放路径：/var/log/phddns\r\n在浏览器中访问远程管理地址http://b.oray.com ，在登录页面中输入SN码与默认密码（admin）登录\r\n\r\n卸载命令：dpkg -r phddns            ','',1),
(10,1,'nginx缺少fastcgi-php.conf 文件','# regex to split $uri to $fastcgi_script_name and $fastcgi_path\r\nfastcgi_split_path_info ^(.+\\.php)(/.+)$;\r\n\r\n# Check that the PHP script exists before passing it\r\ntry_files $fastcgi_script_name =404;\r\n\r\n# Bypass the fact that try_files resets $fastcgi_path_info\r\n# see: http://trac.nginx.org/nginx/ticket/321\r\nset $path_info $fastcgi_path_info;\r\nfastcgi_param PATH_INFO $path_info;\r\n\r\nfastcgi_index index.php;\r\ninclude fastcgi.conf;\r\n','',1),
(11,1,'ubuntu 更新php新版本','一、删除php的相关包及配置\r\n    sudo apt-get autoremove php7*\r\n二、删除关联\r\n    sudo find /etc -name \"*php*\" |xargs  rm -rf\r\n三、清除dept列表\r\n    sudo apt purge `dpkg -l | grep php| awk \'{print $2}\' |tr \"\\n\" \" \"`\r\n//这行代码可有可无\r\nsudo apt install software-properties-common\r\n//电信网络有时连接不了,使用别的网络\r\nsudo add-apt-repository ppa:ondrej/php\r\napt install php{新版}-fpm\r\nphp{新版}-mysql \r\nphp{新版}-gd\r\nphp{新版}-json\r\nphp{新版}-shmop\r\nphp{新版}-sqlite3\r\nphp{新版}-mbstring\r\nphp{新版}-sockets\r\nphp{新版}-redis\r\nphp{新版}-intl\r\nphp{新版}-xml   \r\nphp{新版}-curl\r\nphp{新版}-swoole  ','',1),
(12,1,'\r\nlinux 添加环境变量','vi~/.bashrc \r\n在里面写入环境变量\r\nsource ~/.bashrc\r\nreboot  //看效果\r\n','',1),
(13,1,'centos8 安装lnmp','yum -y upgrade 只更新软件包,不更新内核\r\nyum install nginx\r\nsystemctl restart nginx -y\r\n网站根目录 /usr/share/nginx/html\r\n//nginx 重写 rewrite\r\n/etc/nginx/nginx.conf文件下\r\n//在 location / { 　} 上\r\ninclude /网站根目录/nginx.htaccess\r\n//nginx.htaccess 写入以下内容\r\nif (!-e $request_filename) {\r\n         rewrite  ^(.*)$  /index.php?s=$1  last;\r\n         break;\r\n} \r\nsystemctl restart nginx\r\n------------ 安装php7.2 -----------------\r\nyum install php -y\r\nyum install php-sqlite3 -y\r\nyum install php-pdo php-gd\r\nyum install php-mysqlnd\r\n//后台返回数据json报错记得安装php-json\r\nyum install php-json\r\nvim /etc/nginx/nginx.conf.default \r\nindex.html前加入index.php\r\n------------ 安装mysql-----------------\r\nyum install mysql-server\r\nsystemctl restart mysqld.service\r\nmysql -uroot -p //回车\r\n//远程访问数据库\r\nupdate mysql.user set host=\'%\';\r\nflush privileges;\r\n//更改密码\r\nALTER USER \'root\'@\'%\' IDENTIFIED WITH mysql_native_password BY \'qq282246101\';\r\nflush privileges;\r\nexit;','',1),
(14,1,'linux常用命令','#更改ip地址\r\nifconfig eth0 192.168.100.254 netmask 255.255.255.0\r\n#更改网关\r\nroute add default gw  192.168.100.1\r\n#关闭防火墙\r\nsystemctl stop firewalld.service\r\n#设置开机自动启动\r\nsystemctl enable 程序名.service\r\n\r\n#循环定时      crontab -e\r\n#在下面进行编辑 每天夜里3点30分执行备份\r\n30 3 * * * /执行文件路径/mysql.sh\r\n\r\n#记得给文件权限\r\nchmod ugo+x /执行文件路径/mysql.sh\r\n　　u 表示“用户（user）”，即文件或目录的所有者\r\n　　g 表示“同组（group）用户”，即与文件属主有相同组ID的所有用户\r\n　　o 表示“其他（others）用户\r\n+-增加或减少  r读取 x执行 w写入\r\n\r\n#复制文件 -v 是显示进度的意思\r\ncp -f -v /源文件/  /目标文件目录\r\n#复制文件夹及文件夹下的所有子目录文件 -v 是显示进度的意思\r\ncp -r -v /源文件目录/  /目标文件目录\r\n\r\n#安装支持ntfs格式的磁盘\r\napt install ntfs-3g -y  \r\nblkid  或者 fdisk -l#查看Linux系统每个磁盘与分区的信息\r\n#挂载磁盘\r\nmount /dev/sda1 /mnt\r\n#卸载磁盘\r\numount /mnt  \r\n\r\nrm -r /路径    	#删除文件夹\r\nrm -f /路径/文件名    #删除文件\r\nrm -r -f *                   #删除该目录所有文件夹和文件\r\n#mysql 备份命令 mysql密码跟-p之间没有空格\r\n/usr/bin/mysqldump -u root -p密码 数据库名 > /路径/$(date +%Y%m%d%H%M).sql;\r\ntouch /路径/文件  #新建文件     \r\nmkdir -p /路径/文件夹  #新建文件夹   \r\napt-get remove packagename --purge #卸截软件及配置文件\r\n\r\nlast -x|grep shutdown #查看关机时间日志\r\nlast -x|grep shutdown|head -1 #查看最后一次关机时间\r\n让php 也能执行关机命令shutdown\r\n#root用户登陆\r\nchmod u+s,u=rwx,go=rx /sbin/shutdown   #(4755)\r\n/sbin/shutdown\r\n\r\napt-get install unrar\r\nunrar x -p密码 文件.rar  /解压目录\r\n//去除根目录的方法\r\nunrar x -p密码 文件.rar\r\nmv 根目录/* /目标目录\r\n\r\n\r\napt-get install unzip \r\nunzip  文件.zip  /解压目录 \r\ntar -xvf 包名  #普通没有进行压缩的文件解压 \r\ntar -zxvf 包名  #对于进行过压缩的文件解压 \r\ntar -cvf renwolesshel.tar.gz  renwolesshel  #不压缩打包\r\ntar -czvf renwolesshel.tar.gz  renwolesshel  #压缩打包\r\n\r\nnetstat -tunlp|grep 端口  #查看某个服务\r\nkill -9 端口下的id  #关闭某个服务\r\n\r\nsudo dpkg-reconfigure tzdata #校准时间\r\nAsia\r\nshanghai\r\ntop -o %MEM  #查看程序内存占用情况，同时也可以查看CPU使用率','',1),
(15,1,'linux 循环自动定时备份mysql数据库','//新建mysql.sh \r\ntouch /路径/mysql.sh\r\nvim /路径/mysql.sh  //写入以下内容\r\n/usr/bin/mysqldump -u root -p密码 数据库名 > /路径/$(date +%Y%m%d%H%M).sql;\r\n//备份远程云主机方法\r\n/usr/bin/mysqldump -h云主机ip -u root -p密码 数据库名 > /路径/$(date +%Y%m%d%H%M).sql;\r\n//设置可执行权限\r\nchmod -x /路径/mysql.sh\r\ncrontab -e \r\n//定时每天夜里3.30分进行备份\r\n30 3 * * * /路径/mysql.sh\r\n//自动删除前5天的备份\r\nrm -f /路径/$(date -d -5day +%Y%m%d%H%M).sql; \r\n//6点到23点间执行\r\n* 6-23 **** /','',1),
(16,1,'树莓派 debian 安装','1.刷好系统之后，新建一个文件 userconf.txt 来设置初始话账号密码\r\npi:$6$/4.VdYgDm7RJ0qM1$FwXCeQgDKkqrOU3RIRuDSKpauAbBvP11msq9X58c8Que2l1Dwq3vdJMgiZlQSbEXGaY5esVHGBNbCxKLVNqZW1\r\n用户名：pi\r\n密码：raspberry\r\n2.新建一个空白文件，文件名：ssh，不要后缀，不用写入数据\r\n','',1),
(17,1,'网络无法连接外网','sudo nano /etc/dnsmasq.conf\r\n\r\nserver=8.8.8.8\r\nserver=8.8.4.4\r\n\r\n\r\nsudo service dnsmasq restart','',1),
(18,1,'scp 命令进行文件上传,下载','window linux 下都通用\r\n\r\n文件上传命令\r\nscp -f 本地路径/文件名 root@192.168.7.254:/远程文件目录\r\n文件夹上传命令\r\nscp -r 本地路径/文件夹 root@192.168.7.254:/远程文件目录\r\n上传本目录下的所有文件\r\nscp -r * -f * root@192.168.7.254:/远程文件目录\r\n下载文件\r\nscp -f root@192.168.7.254:/远程文件目录 本地路径 ','',1),
(32,2,'mysql基础语句','//增 添加插入数据\r\ninsert into table(a,b,c) values (\'?\',\'?\',\'?\');\r\n//删 删除一条数据\r\ndelete from table where id=\'?\';\r\n//更 修改数据\r\nupdate table set a=\'?\',b=\'?\' where id=\'?\'\r\n//查 查询一条数据\r\nselect id from table where name=\'?\';\r\n//更改字段名称\r\nALTER TABLE 表名 CHANGE 原来字段 新字段  VARCHAR(字段长度)\r\n\r\n查看数据结构\r\ndesc table;\r\n\r\n删除字段\r\nALTER TABLE 表名 drop COLUMN 字段名;\r\n\r\n增加字段\r\nALTER TABLE 表名 ADD 字段名 类型  NOT NULL 默认(DEFAULT \'0\'); \r\n指定字段kuaidi_number后追加字段\r\nALTER TABLE 表名 ADD 字段名 类型  NOT NULL DEFAULT \'0\' after kuaidi_number;\r\n\r\nmysql 更改字段类型\r\nALTER TABLE 表名 modify column 字段 类型 NOT NULL 默认(DEFAULT \'0\');  \r\n\r\n//更改字段名 及字段属性 默认值\r\nALTER TABLE 表名 change 旧字段 新字段 varchar(32) DEFAULT 1\r\n\r\n修改字段默认值语法：\r\nalter  table 表名 alter  column 字段名 drop default （本身存在默认值,则先删除）\r\nalter  table 表名 alter  column 字段名 set default 默认值 （本身不存在默认值可直接设定）  \r\n\r\n//修改字段 not null\r\nalter table CommerceCustomer modify address varchar(64)  not null\r\n\r\n//复制远程服务器数据库到本地数据库 \r\nmysqldump -h360xyz.cn -uroot -pqq282246101 --opt --compress xyz --skip-lock-tables | mysql -h localhost -uroot -pqq282246101 xyz \r\n\r\n//备份本地数据库成一个sql文件 并且文件大于5个自动删除最久一个文件\r\n/usr/bin/mysqldump -hlocalhost -uroot -pqq282246101 xyz > /var/www/html/vvwd/tool/sql/$(date +%Y%m%d%H%M).sql;\r\nrm -f /var/www/html/vvwd/tool/sql/$(date -d -5day +%Y%m%d%H%M).sql;  \r\n','',1),
(33,2,'windows或linux备份远程mysql命令','运行 cmd 到mysqldump.exe的目录下(mysqldump.exe可以从mysql目录里复制) 以下命令\r\nmysqldump -h服务器ip -u root -p密码 数据库名 > /路径/xyz.sql;\r\n或者写个.bat批处理文件直接点击就可以了            ','',1),
(34,2,'ubuntu 安装mysql','------------安装mysql-------------------\r\nsudo apt-get install mysql-server mysql-client\r\n\r\n//设置 mysql 可以外网访问\r\nsudo vim /etc/mysql/mysql.conf.d/mysqld.cnf\r\nbind-address前添加 #注释掉该行\r\n//刚安装完成时root用户不需要密码\r\nsudo mysql -uroot -p //回车 \r\n//远程访问数据库\r\nupdate mysql.user set host=\'%\';\r\nflush privileges;\r\n//更改密码\r\nALTER USER \'root\'@\'%\' IDENTIFIED WITH mysql_native_password BY \'qq282246101\';\r\nflush privileges;\r\nsudo service mysql restart //重启','',1),
(35,2,'windows下的mysql默认不是utf-8编码','不是UTF-8编码中文时会现乱码或sql无法识别中文字符，需要手动更改一下为UTF-8\r\nmysql 下找到 my.ini\r\n查找 [mysqld]\r\n在它下面输入 character-set-server=utf8   保存后重启mysql\r\n','',1),
(36,2,'计算所有行某个字段的相加总合','SELECT sum(字段名) FROM TABLE','',1),
(37,2,'windows 下修改mysql密码',' set password for root@localhost=password(\'qq282246101\');','',1),
(38,2,'debian 11 安装MYSQL5.7.39 ','https://downloads.mysql.com/archives/community/\r\n选择debian适合的版本\r\ncd 到预定安装目录\r\n解压\r\ntar -xvf mysql-server_5.7.39-1debian10_amd64.deb-bundle.tar\r\n\r\n依赖安装\r\napt install psmisc libaio1 libnuma1 libatomic1 libmecab2\r\n\r\n安装MySQL程序（需要按照顺序依次安装）\r\n\r\n    dpkg -i mysql-common_5.7.39-1debian10_amd64.deb\r\n    dpkg -i mysql-community-client_5.7.39-1debian10_amd64.deb\r\n    dpkg -i mysql-client_5.7.39-1debian10_amd64.deb\r\n    dpkg -i mysql-community-server_5.7.39-1debian10_amd64.deb\r\n# 期间会提示输入密码, 并确认密码\r\n    dpkg -i mysql-server_5.7.39-1debian10_amd64.deb\r\n\r\n# 配置客户端默认字符集，新增参数default-character-set=utf8\r\n    vim /etc/mysql/conf.d/mysql.cnf\r\n     \r\n    default-character-set=utf8\r\n     \r\n','',1),
(39,2,'windows source命令导入报错','mysql -uroot --default-character-set=utf8 -p','',1),
(40,2,'linux redis安装配置 ','sudo apt update\r\n\r\n# 安装\r\nsudo apt install redis-server\r\n\r\n# 配置\r\nsudo vim /etc/redis/redis.conf\r\n# 找到 supervised 设置为 systemd\r\nsudo service redis restart  # 重新加载Redis服务文件\r\nsudo systemctl status redis # 查看 Redis 的运行状态\r\n\r\n# 一些操作\r\nsudo service redis start  # 启动\r\nsudo service redis stop  # 关闭\r\nsudo service redis restart  # 重启\r\nredis-cli  # 客户端连接\r\n\r\n# 远程连接 \r\nsudo vi /etc/redis/redis.conf\r\n# 将 bind 127.0.0.1 ::1 改为 bind 0.0.0.0\r\nsudo service redis restart  # 重启\r\n\r\n# 设置密码\r\nsudo vi /etc/redis/redis.conf\r\n# 设置：requirepass 自己的密码\r\n\r\n默认端口6379','',1),
(41,2,'mysql 复制数据库某表','mysql 复制数据库某表到另一个数据库\r\n//先复制数据结构\r\nCREATE TABLE English.English1000 LIKE xyz.English1000\r\nEnglish.English1000为目标    xyz.English1000为源\r\n//复制数据\r\nINSERT INTO English.English1000 SELECT * FROM xyz.English1000;','',1),
(42,2,'windows redis使用与设置密码 ','redis 根目录\r\n修改redis.windows-service.conf\r\nappendonly yes\r\nrequirepass qq282246101\r\n\r\n','',1),
(43,2,'linux mysql备份指定几个表','mysqldump -uroot -pqq282246101 xyz  WarehouseGoods WarehousePreorder WisdomCategory WisdomPreview WisdomToolsType WisdomToolsName WisdomBartitle WisdomBarrtitle > /home/php.sql','',1),
(44,2,'mariaDB远程访问设置','sudo apt install mariadb-server\r\n/etc/mysql/mariadb.conf.d/60-galera.cnf\r\nbind-address = 0.0.0.0 去掉前面的 #\r\nmysql -uroot -p\r\n-- 登录 MariaDB 后执行\r\nALTER USER \'root\'@\'localhost\' IDENTIFIED BY \'新密码\';\r\nFLUSH PRIVILEGES; -- 刷新权限使设置生效','',1),
(45,2,'Linux phpmyadmin配置1 config.inc.php','phpMyAdmin-5.2.1-all-languages.tar.gz 解压到 /usr/share/phpmyadmin\r\n创建config.inc.php 如下代码\r\n\r\n\r\n<?php\r\n/**\r\n * phpMyAdmin sample configuration, you can use it as base for\r\n * manual configuration. For easier setup you can use setup/\r\n *\r\n * All directives are explained in documentation in the doc/ folder\r\n * or at <https://docs.phpmyadmin.net/>.\r\n */\r\n\r\ndeclare(strict_types=1);\r\n\r\n/**\r\n * This is needed for cookie based authentication to encrypt the cookie.\r\n * Needs to be a 32-bytes long string of random bytes. See FAQ 2.10.\r\n */\r\n$cfg[\'blowfish_secret\'] = \'\'; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */\r\n\r\n/**\r\n * Servers configuration\r\n */\r\n$i = 0;\r\n\r\n/**\r\n * First server\r\n */\r\n$i++;\r\n/* Authentication type */\r\n$cfg[\'Servers\'][$i][\'auth_type\'] = \'cookie\';\r\n/* Server parameters */\r\n$cfg[\'Servers\'][$i][\'host\'] = \'localhost\';\r\n$cfg[\'Servers\'][$i][\'compress\'] = false;\r\n$cfg[\'Servers\'][$i][\'AllowNoPassword\'] = false;\r\n\r\n/**\r\n * phpMyAdmin configuration storage settings.\r\n */\r\n\r\n/* User used to manipulate with storage */\r\n $cfg[\'Servers\'][$i][\'controlhost\'] = \'localhost\';\r\n $cfg[\'Servers\'][$i][\'controlport\'] = \'3306\';\r\n $cfg[\'Servers\'][$i][\'controluser\'] = \'root\';\r\n $cfg[\'Servers\'][$i][\'controlpass\'] = \'qq282246101\';\r\n\r\n/* Storage database and tables */\r\n $cfg[\'Servers\'][$i][\'pmadb\'] = \'phpmyadmin\';\r\n $cfg[\'Servers\'][$i][\'bookmarktable\'] = \'pma__bookmark\';\r\n $cfg[\'Servers\'][$i][\'relation\'] = \'pma__relation\';\r\n $cfg[\'Servers\'][$i][\'table_info\'] = \'pma__table_info\';\r\n $cfg[\'Servers\'][$i][\'table_coords\'] = \'pma__table_coords\';\r\n $cfg[\'Servers\'][$i][\'pdf_pages\'] = \'pma__pdf_pages\';\r\n $cfg[\'Servers\'][$i][\'column_info\'] = \'pma__column_info\';\r\n $cfg[\'Servers\'][$i][\'history\'] = \'pma__history\';\r\n $cfg[\'Servers\'][$i][\'table_uiprefs\'] = \'pma__table_uiprefs\';\r\n $cfg[\'Servers\'][$i][\'tracking\'] = \'pma__tracking\';\r\n $cfg[\'Servers\'][$i][\'userconfig\'] = \'pma__userconfig\';\r\n $cfg[\'Servers\'][$i][\'recent\'] = \'pma__recent\';\r\n $cfg[\'Servers\'][$i][\'favorite\'] = \'pma__favorite\';\r\n $cfg[\'Servers\'][$i][\'users\'] = \'pma__users\';\r\n $cfg[\'Servers\'][$i][\'usergroups\'] = \'pma__usergroups\';\r\n $cfg[\'Servers\'][$i][\'navigationhiding\'] = \'pma__navigationhiding\';\r\n $cfg[\'Servers\'][$i][\'savedsearches\'] = \'pma__savedsearches\';\r\n $cfg[\'Servers\'][$i][\'central_columns\'] = \'pma__central_columns\';\r\n $cfg[\'Servers\'][$i][\'designer_settings\'] = \'pma__designer_settings\';\r\n $cfg[\'Servers\'][$i][\'export_templates\'] = \'pma__export_templates\';\r\n\r\n/**\r\n * End of servers configuration\r\n */\r\n\r\n/**\r\n * Directories for saving/loading files from server\r\n */\r\n$cfg[\'UploadDir\'] = \'\';\r\n$cfg[\'SaveDir\'] = \'\';\r\n\r\n/**\r\n * Whether to display icons or text or both icons and text in table row\r\n * action segment. Value can be either of \'icons\', \'text\' or \'both\'.\r\n * default = \'both\'\r\n */\r\n//$cfg[\'RowActionType\'] = \'icons\';\r\n\r\n/**\r\n * Defines whether a user should be displayed a \"show all (records)\"\r\n * button in browse mode or not.\r\n * default = false\r\n */\r\n//$cfg[\'ShowAll\'] = true;\r\n\r\n/**\r\n * Number of rows displayed when browsing a result set. If the result\r\n * set contains more rows, \"Previous\" and \"Next\".\r\n * Possible values: 25, 50, 100, 250, 500\r\n * default = 25\r\n */\r\n//$cfg[\'MaxRows\'] = 50;\r\n\r\n/**\r\n * Disallow editing of binary fields\r\n * valid values are:\r\n *   false    allow editing\r\n *   \'blob\'   allow editing except for BLOB fields\r\n *   \'noblob\' disallow editing except for BLOB fields\r\n *   \'all\'    disallow editing\r\n * default = \'blob\'\r\n */\r\n//$cfg[\'ProtectBinary\'] = false;\r\n\r\n/**\r\n * Default language to use, if not browser-defined or user-defined\r\n * (you find all languages in the locale folder)\r\n * uncomment the desired line:\r\n * default = \'en\'\r\n */\r\n//$cfg[\'DefaultLang\'] = \'en\';\r\n//$cfg[\'DefaultLang\'] = \'de\';\r\n\r\n/**\r\n * How many columns should be used for table display of a database?\r\n * (a value larger than 1 results in some information being hidden)\r\n * default = 1\r\n */\r\n//$cfg[\'PropertiesNumColumns\'] = 2;\r\n\r\n/**\r\n * Set to true if you want DB-based query history.If false, this utilizes\r\n * JS-routines to display query history (lost by window close)\r\n *\r\n * This requires configuration storage enabled, see above.\r\n * default = false\r\n */\r\n//$cfg[\'QueryHistoryDB\'] = true;\r\n\r\n/**\r\n * When using DB-based query history, how many entries should be kept?\r\n * default = 25\r\n */\r\n//$cfg[\'QueryHistoryMax\'] = 100;\r\n\r\n/**\r\n * Whether or not to query the user before sending the error report to\r\n * the phpMyAdmin team when a JavaScript error occurs\r\n *\r\n * Available options\r\n * (\'ask\' | \'always\' | \'never\')\r\n * default = \'ask\'\r\n */\r\n//$cfg[\'SendErrorReports\'] = \'always\';\r\n\r\n/**\r\n * \'URLQueryEncryption\' defines whether phpMyAdmin will encrypt sensitive data from the URL query string.\r\n * \'URLQueryEncryptionSecretKey\' is a 32 bytes long secret key used to encrypt/decrypt the URL query string.\r\n */\r\n//$cfg[\'URLQueryEncryption\'] = true;\r\n//$cfg[\'URLQueryEncryptionSecretKey\'] = \'\';\r\n\r\n/**\r\n * You can find more configuration options in the documentation\r\n * in the doc/ folder or at <https://docs.phpmyadmin.net/>.\r\n */\r\n','',1),
(46,2,'Linux phpmyadmin配置2','sudo vim /etc/apache2/conf-available/phpmyadmin.conf\r\n//写入如下代码\r\nAlias /phpmyadmin /usr/share/phpmyadmin\r\n\r\n<Directory /usr/share/phpmyadmin>\r\n    Options SymLinksIfOwnerMatch\r\n    DirectoryIndex index.php\r\n\r\n    <IfModule mod_php5.c>\r\n        <IfModule mod_mime.c>\r\n            AddType application/x-httpd-php .php\r\n        </IfModule>\r\n        <FilesMatch \".+\\.php$\">\r\n            SetHandler application/x-httpd-php\r\n        </FilesMatch>\r\n\r\n        php_value include_path .\r\n        php_admin_value open_basedir /usr/share/phpmyadmin/:/etc/phpmyadmin/:/var/lib/phpmyadmin/:/usr/share/php/php-gettext/:/usr/share/php/php-php-gettext/:/usr/share/javascript/:/usr/share/php/tcpdf/:/usr/share/doc/phpmyadmin/:/usr/share/php/phpseclib/\r\n        php_admin_value mbstring.func_overload 0\r\n    </IfModule>\r\n    <IfModule mod_php.c>\r\n        <IfModule mod_mime.c>\r\n            AddType application/x-httpd-php .php\r\n        </IfModule>\r\n        <FilesMatch \".+\\.php$\">\r\n            SetHandler application/x-httpd-php\r\n        </FilesMatch>\r\n\r\n        php_value include_path .\r\n        php_admin_value open_basedir /usr/share/phpmyadmin/:/etc/phpmyadmin/:/var/lib/phpmyadmin/:/usr/share/php/php-gettext/:/usr/share/php/php-php-gettext/:/usr/share/javascript/:/usr/share/php/tcpdf/:/usr/share/doc/phpmyadmin/:/usr/share/php/phpseclib/\r\n        php_admin_value mbstring.func_overload 0\r\n    </IfModule>\r\n\r\n</Directory>\r\n# Authorize for setup\r\n<Directory /usr/share/phpmyadmin/setup>\r\n    <IfModule mod_authz_core.c>\r\n        <IfModule mod_authn_file.c>\r\n            AuthType Basic\r\n            AuthName \"phpMyAdmin Setup\"\r\n            AuthUserFile /etc/phpmyadmin/htpasswd.setup\r\n        </IfModule>\r\n        Require valid-user\r\n    </IfModule>\r\n</Directory>\r\n\r\n# Disallow web access to directories that don\'t need it\r\n<Directory /usr/share/phpmyadmin/templates>\r\n    Require all denied\r\n</Directory>\r\n<Directory /usr/share/phpmyadmin/libraries>\r\n    Require all denied\r\n</Directory>\r\n<Directory /usr/share/phpmyadmin/setup/lib>\r\n    Require all denied\r\n</Directory>\r\n\r\n\r\n# 2. 启用phpMyAdmin配置文件\r\n#sudo a2enconf phpmyadmin.conf\r\n#sudo systemctl reload apache2\r\n','',1),
(47,3,'vscode golang 安装插件','https://goproxy.io/zh/ 一个全球代理为 Go 模块而生\r\n\r\ngo env -w GO111MODULE=on\r\n\r\n可选一  go env -w GOPROXY=https://goproxy.io,direct\r\n可选二 go env -w GOPROXY=https://goproxy.cn,direct\r\n或者 # 还可以设置不走 proxy 的私有仓库或组，多个用逗号相隔（可选）\r\ngo env -w GOPRIVATE = \"git.mycompany.com,github.com/my/private\"','',1),
(48,3,'golang 调用异步协程','//定义这个WaitGroup是为了 go协程执行完毕后wg.Wait() 放行主线程继续往下	\r\n	wg := sync.WaitGroup{}\r\n	wg.Add(10)//表示调用异步次数\r\n	for i := 0; i < 10; i++ {\r\n		go func(i int) {\r\n			fmt.Println(i)\r\n		wg.Done()//调用次数减1\r\n		}(i)\r\n	}\r\n//wg 是为了等待异步执行完毕 有这句话就算主程序完成了程序还是要等待 直到异步完成为止\r\n	wg.Wait()\r\n	fmt.Println(\"ok\")\r\n\r\n//示例如下\r\n\r\nfunc Aaa(wg *sync.WaitGroup) {\r\n	fmt.Println(\"Aaa\")\r\n	wg.Done()\r\n}\r\nfunc Baa(wg *sync.WaitGroup) {\r\n	fmt.Println(\"Baa\")\r\n	wg.Done()\r\n}\r\nfunc Caa(wg *sync.WaitGroup) {\r\n	fmt.Println(\"Caa\")\r\n	wg.Done()\r\n}\r\nfunc Daa(wg *sync.WaitGroup) {\r\n	fmt.Println(\"Daa\")\r\n	wg.Done()\r\n}\r\nfunc main() {\r\n	wg := sync.WaitGroup{}\r\n	wg.Add(4)\r\n	go Aaa(&wg)\r\n	go Baa(&wg)\r\n	go Caa(&wg)\r\n	go Daa(&wg)\r\n	wg.Wait()\r\n	fmt.Println(\"ok\")\r\n}','',1),
(49,3,'linux 手动安装golang或更新版本 ','官网下载最新包\r\n如果是 树莓派 就下载 arm构架的包\r\n下载后放到 /usr/local/下面 这里是linux默认安装的地方 当然也可以装到别的地方\r\n把包放到这个目录下 cd 到该目录\r\ntar -zxvf 包名  //进行解压\r\n\r\n最重要一点来了  设置环境变量\r\n\r\nvi ~/.bashrc\r\n\r\n里面添加\r\n\r\n//更新golang版本 直接进入/usr/local/\r\nrm -r go\r\n//然后把包放到这个目录下解压就可以了\r\n//我们的工作目录设置是 /opt/go\r\n//下面有三个目录 bin  pkg(这个目录是依赖包目录很重要千万别删) src(代码目录 也就是工作目录 写完代码直接命令运行或编译 go run main.go   或者 go build main.go)\r\n\r\nexport GOROOT=/usr/local/go  //就是你包解压的地方\r\n\r\nexport GOPATH=/opt/go  //你网站运行的目录\r\n\r\nexport PATH=$GOPATH/bin:$GOROOT/bin:$PATH\r\n\r\n保存退出\r\n\r\n再  source ~/.bashrc\r\n//下载beego\r\ngo get github.com/astaxie/beego\r\ngo get github.com/beego/bee','',1),
(50,3,'defer 关键名','defer 关键名 相当于c# finaly\r\n\r\n\r\n\r\ndefer conn.close()\r\n\r\ndb.select()...\r\n\r\n//它是会等待db.select()...再进行conn.close() 它会等他代码下一行语句执行完毕再调用到它','',1),
(51,3,'go 判断客户端是是手机还是电脑','import (\r\n\r\n	\"strings\"\r\n\r\n	\"github.com/astaxie/beego\"\r\n\r\n)\r\n\r\ntype Isphome struct{\r\n\r\n	beego.Controller\r\n\r\n}\r\n\r\nfunc (c *Isphome)Isphone() bool{\r\n\r\n	//User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0\r\n\r\n	UserAgent := c.Ctx.Request.Header.Get(\"User-Agent\")\r\n\r\n	//找不到返回 -1 成功为正数\r\n\r\n	i := strings.Index(UserAgent, \"Windows\")\r\n\r\n	if i> -1 {\r\n\r\n		return true\r\n\r\n	}else{\r\n\r\n		return false\r\n\r\n	}\r\n\r\n}\r\n','',1),
(52,3,'golang 执行先后','先执行引入包的 全局变量 -> init方法\r\n\r\n再执行本文件的 全局变量 -> init方法\r\n\r\n再到 main()方法','',1),
(53,3,'golang mysql自定义 类','package models\r\n\r\nimport (\r\n	\"database/sql\"\r\n	\"fmt\"\r\n\r\n	\"time\"\r\n\r\n	_ \"github.com/go-sql-driver/mysql\"\r\n)\r\n\r\ntype GoSql struct {\r\n	conn *sql.DB\r\n	arr  []interface{}\r\n	stmt *sql.Stmt\r\n}\r\n\r\n// mysqlPasswd DES  8位Key加密过了\r\nfunc (ggg *GoSql) ConnectDb(mysqlHost, mysqlUser, mysqlPasswd, port, dbDatabase string) *GoSql {\r\n	var err error\r\n	ggg.conn, err = sql.Open(\"mysql\", mysqlUser+\":\"+mysqlPasswd+\"@tcp(\"+mysqlHost+\":\"+port+\")/\"+dbDatabase+\"?charset=utf8\")\r\n	if err != nil {\r\n		fmt.Println(\"连接数据库fail\")\r\n		ggg.conn.Close()\r\n		return nil\r\n	}\r\n	//设置每个链接的过期时间\r\n	ggg.conn.SetConnMaxLifetime(180 * time.Second)\r\n	//设置最大连接数\r\n	ggg.conn.SetMaxOpenConns(30)\r\n	//设置最大空闲连接数\r\n	ggg.conn.SetMaxIdleConns(10)\r\n	return ggg\r\n}\r\nfunc (ggg *GoSql) Ping() error {\r\n	// 测试数据库连接\r\n	err := ggg.conn.Ping()\r\n	if err != nil {\r\n		return err\r\n	}\r\n	return nil\r\n}\r\n\r\n// 第一个参数 sql语句 第二个参数 sql语句 ? 对应的值\r\nfunc (ggg *GoSql) Sql(sql string, arr ...interface{}) *GoSql {\r\n	Stmt, err := ggg.conn.Prepare(sql)\r\n	if err != nil {\r\n		ggg.conn.Close()\r\n		return nil\r\n	}\r\n	ggg.stmt = Stmt\r\n	ggg.arr = arr\r\n	return ggg\r\n}\r\n\r\n// 参数就是返回结果只  查询success 返回 true 如果只判断bool Row里不用传 指针取值\r\nfunc (ggg *GoSql) Row(show ...interface{}) bool {\r\n	row, err := ggg.stmt.Query(ggg.arr...)\r\n	if err != nil {\r\n		return false\r\n	}\r\n	defer row.Close()\r\n	bl := row.Next()\r\n	if !bl {\r\n		return false\r\n	}\r\n	row.Scan(show...)\r\n\r\n	return true\r\n}\r\n\r\n// 返回*sql.Rows, error 手动写 指针取值\r\nfunc (ggg *GoSql) MultiRows() (*sql.Rows, error) {\r\n	rows, err1 := ggg.stmt.Query(ggg.arr...)\r\n	return rows, err1\r\n}\r\n\r\n/*\r\n执行查询并返回多行结果。\r\n每行结果存储为一个映射，键为列名，值为该列的值。\r\n返回的映射的键是行号，值是该行的数据映射。\r\n如果查询过程中发生错误，将返回一个空的映射和错误。\r\nfail返回空MAP 数据库字段默认null即sql.NullString之类不能使用该方法\r\n*/\r\n\r\nfunc (ggg *GoSql) AutoMultiRows() map[int]map[string]interface{} {\r\n	// 初始化结果映射\r\n	result := make(map[int]map[string]interface{})\r\n	// 执行查询\r\n	rows, err := ggg.stmt.Query(ggg.arr...)\r\n	if err != nil {\r\n		// 关闭rows资源，避免资源泄露\r\n		rows.Close()\r\n		return nil\r\n	}\r\n\r\n	// 获取查询结果的列名\r\n	columns, err1 := rows.Columns()\r\n	if err1 != nil {\r\n		// 关闭rows资源，避免资源泄露\r\n		rows.Close()\r\n		return nil\r\n	}\r\n\r\n	// 初始化与列数相等的切片，用于存储每行的数据\r\n	values := make([]interface{}, len(columns))\r\n	valuePtrs := make([]interface{}, len(columns))\r\n	// 将每列的指针存储到valuePtrs中，以便Scan能够直接填充数据\r\n	for i := range columns {\r\n		valuePtrs[i] = &values[i]\r\n	}\r\n	rowIndex := 0\r\n	// 关闭rows资源，避免资源泄露\r\n	defer rows.Close()\r\n	// 遍历查询结果的每一行\r\n	for rows.Next() {\r\n		// 将当前行的数据填充到valuePtrs指向的变量中\r\n		if err := rows.Scan(valuePtrs...); err != nil {\r\n			return nil\r\n		}\r\n		// 初始化当前行的数据映射\r\n		rowData := make(map[string]interface{})\r\n		for i, colName := range columns {\r\n			var v interface{}\r\n			val := values[i]\r\n			b, ok := val.([]byte)\r\n			if ok {\r\n				v = string(b)\r\n			} else {\r\n				v = val\r\n			}\r\n			rowData[colName] = v\r\n		}\r\n		// 将当前行的数据添加到结果集中\r\n		result[rowIndex] = rowData\r\n		rowIndex++\r\n	}\r\n	// 检查是否有查询过程中的错误\r\n	if err = rows.Err(); err != nil {\r\n		return nil\r\n	}\r\n	return result\r\n}\r\n\r\n// fail返回0 success返回 受影响行的个数\r\nfunc (ggg *GoSql) Execute() int64 {\r\n	crow, err := ggg.stmt.Exec(ggg.arr...)\r\n	if err != nil {\r\n		return 0\r\n	}\r\n	re, err1 := crow.RowsAffected()\r\n	if err1 != nil {\r\n		return 0\r\n	}\r\n	return re\r\n}\r\n\r\nfunc (ggg *GoSql) AutoInsert(table string, m map[string]interface{}) int64 {\r\n	sql := \"INSERT INTO \" + table + \" (\"\r\n	//(rid,user,password) VALUES (?,?,?)\r\n	ik := \"\"\r\n	iv := \"\"\r\n	var mv []interface{}\r\n	for k, v := range m {\r\n		if ik == \"\" {\r\n			ik = k + \",\"\r\n		} else {\r\n			ik = ik + k + \",\"\r\n		}\r\n		if iv == \"\" {\r\n			iv = \"?,\"\r\n		} else {\r\n			iv = iv + \"?\" + \",\"\r\n		}\r\n		mv = append(mv, v)\r\n	}\r\n	ik = ik[0 : len(ik)-1]\r\n	iv = iv[0 : len(iv)-1]\r\n	sql = sql + ik + \") VALUES (\" + iv + \")\"\r\n	return ggg.Sql(sql, mv...).Execute()\r\n}\r\nfunc (ggg *GoSql) Count(table string) int64 {\r\n	count := int64(0)\r\n	sql := \"SELECT count(id) FROM \" + table\r\n	ggg.Sql(sql).Row(&count)\r\n	return count\r\n}\r\n','',1),
(54,3,'bee 分页','package models\r\n\r\nimport (\r\n	\"bytes\"\r\n	\"strconv\"\r\n	\"strings\"\r\n)\r\n\r\ntype Pages struct {\r\n	PageNo     int    //当前页\r\n	PageSize   int    //每页多少数据\r\n	TotalPage  int    //总共多少页\r\n	TotalCount int    //总共多少条数据\r\n	FirstPage  int    //第一页\r\n	LastPage   int    //最后一页\r\n	Url        string //链接\r\n}\r\n\r\nfunc NewPage(PageNo int, PageSize int, TotalCount int, Url string) Pages {\r\n	return Pages{PageNo: PageNo, PageSize: PageSize, TotalCount: TotalCount, Url: Url}\r\n}\r\n\r\n//计算总页数\r\nfunc (c *Pages) getPageCount() {\r\n	var tp float32 = float32(c.TotalCount) / float32(c.PageSize)\r\n	if tp < 1 {\r\n		c.TotalPage = 1\r\n	}\r\n	var tpint float32 = float32(int(tp))\r\n\r\n	if tp > tpint {\r\n		tpint += 1\r\n	}\r\n	c.TotalPage = int(tpint)\r\n	c.LastPage = int(tpint)\r\n	c.FirstPage = 1\r\n	c.execUrl()\r\n}\r\n\r\n//格式化URL地址\r\nfunc (c *Pages) execUrl() {\r\n	if strings.Contains(c.Url, \"?\") {\r\n		c.Url = strings.Join([]string{c.Url, \"&page=\"}, \"\")\r\n	} else {\r\n		c.Url = strings.Join([]string{c.Url, \"?page=\"}, \"\")\r\n	}\r\n}\r\n\r\n//获取URL组织\r\nfunc (c *Pages) getUrl(page int) string {\r\n	return strings.Join([]string{c.Url, strconv.Itoa(page)}, \"\")\r\n}\r\n\r\nfunc (c *Pages) getNum(page int, num int) (int, int) {\r\n	var k = 1\r\n	//分布显示数量\r\n	var v = 5\r\n	if page > 3 {\r\n		k = page - 2\r\n		v = page + 2\r\n		if v > num {\r\n			k = num - 4\r\n			v = num\r\n		}\r\n	} else {\r\n		if v > num {\r\n			v = num\r\n		}\r\n	}\r\n	return k, v\r\n}\r\nfunc (c *Pages) LimitStart() int {\r\n	return (c.PageNo - 1) * c.PageSize\r\n}\r\nfunc (c *Pages) Show() string {\r\n	c.getPageCount()\r\n	var style bytes.Buffer\r\n	style.WriteString(\"<style> .pageing{ width:360px; list-style-type:none; margin: 0px;padding: 0px; } .pageing>li {  float: left; width: 30px; line-height:23px; text-align: center; border: 1px solid #7B7B7B; margin:3px; }  </style>\")\r\n	var buf bytes.Buffer\r\n	str := \"<div style=\\\"clear:both;\\\"></div><ul class=\\\"pageing\\\"><li><a href=\\\"\" + c.getUrl(1) + \"\\\">1</a></li>\"\r\n	buf.WriteString(str)\r\n	if c.PageNo > 1 {\r\n		buf.WriteString(\"<li><a href=\\\"\" + c.getUrl(c.PageNo-1) + \"\\\"><<</a></li>\")\r\n	}\r\n\r\n	k, v := c.getNum(c.PageNo, c.TotalPage)\r\n\r\n	for i := k; i <= v; i++ {\r\n		if i == c.PageNo {\r\n			buf.WriteString(\"<li style=\\\"background-color: green;\\\">\")\r\n			buf.WriteString(strconv.Itoa(i))\r\n		} else {\r\n			buf.WriteString(\"<li><a href=\\\"\" + c.getUrl(i) + \"\\\">\")\r\n			buf.WriteString(strconv.Itoa(i))\r\n		}\r\n		buf.WriteString(\"</a></li>\")\r\n	}\r\n\r\n	if c.PageNo < c.TotalPage {\r\n		var nextPage int = c.PageNo + 1\r\n		buf.WriteString(\"<li><a href=\\\"\" + c.getUrl(nextPage) + \"\\\">>></a></li>\")\r\n	}\r\n\r\n	buf.WriteString(\"<li><a href=\\\"\" + c.getUrl(c.TotalPage) + \"\\\">\" + strconv.Itoa(c.TotalPage) + \"</a></li></ul>\")\r\n	return style.String() + buf.String()\r\n}\r\n','',1),
(55,3,'beego 验证码','import (\r\n	\"beego/models\"\r\n	\"encoding/base64\"\r\n	\"encoding/json\"\r\n	\"fmt\"\r\n	\"strings\"\r\n\r\n	\"github.com/astaxie/beego\"\r\n	\"github.com/astaxie/beego/cache\"\r\n	captcha2 \"github.com/astaxie/beego/utils/captcha\"\r\n)\r\n\r\ntype VcodeController struct {\r\n	beego.Controller\r\n}\r\n\r\n// 全局验证码结构体\r\nvar captcha *captcha2.Captcha\r\n\r\n// init函数初始化captcha\r\nfunc init() {\r\n	// 验证码功能\r\n	// 使用Beego缓存存储验证码数据\r\n	store := cache.NewMemoryCache()\r\n	// 创建验证码\r\n	captcha = captcha2.NewWithFilter(\"/captcha\", store)\r\n	// 设置验证码长度\r\n	captcha.ChallengeNums = 4\r\n	// 设置验证码模板高度\r\n	captcha.StdHeight = 50\r\n	// 设置验证码模板宽度\r\n	captcha.StdWidth = 120\r\n}\r\n\r\n\r\n <p> {{create_captcha}}<--刷新 </p> \r\n\r\n// if !captcha.VerifyReq(c.Ctx.Request) {\r\n	// 	c.Ctx.WriteString(\"验证码错误\")\r\n	// 	return\r\n	// }','',1),
(56,3,'map数组','make(map[string]interface{})\r\n\r\nmap[string]string{ \"k\":\"v\", } //map数组 初始值声明方式','',1),
(57,3,'map转换  json','data, _ := json.Marshal(map_array)\r\nc.Ctx.WriteString(string(data))  //返回json响应','',1),
(58,3,'* 和 & 的区别','* 代表取指针地址中存的值\r\n& 代表取一个值的内存地址\r\nfunc main() {\r\n	a := 100\r\n	var ptr *int\r\n\r\n	ptr = &a\r\n	fmt.Println(ptr)\r\n	fmt.Println(*ptr)//获取值\r\n	fmt.Println(*&a)//获取值\r\n}\r\n','',1),
(59,3,'管道 chan','chan   \r\nchan:=make(chan int,3) //(管道 类型,容量 ) 这个是双向管道 \r\nchan<-20  //管道赋值\r\naa:=<-chan //管道赋值给变量\r\nmake(chan<- int,3) //单向只写 只能这与不能取\r\nmake(<-chan int,3) //单向只读 只能取不能写\r\n管道特性 不管使用协程与否，管道都是排顺序 存取 主要应用于 协程+管道\r\n特别注意 chan存多少次就要取多少次\r\n\r\nchan<-10\r\nchan<-20\r\nchan<-30\r\n<-chan\r\n<-chan\r\n<-chan','',1),
(62,3,'go 浏览文件夹','import (\r\n	\"fmt\"\r\n	\"io/ioutil\"\r\n)\r\n\r\nfunc readDir(dirPath string) {\r\n	str := []string{}\r\n	files, err := ioutil.ReadDir(dirPath)\r\n	if err != nil {\r\n		fmt.Println(\"文件打开失败\")\r\n	}\r\n	for _, v := range files {\r\n		if v.IsDir() {\r\n			str = append(str, \"<\"+v.Name()+\">\")\r\n		} else {\r\n			str = append(str, v.Name())\r\n		}\r\n	}\r\n	fmt.Println(str)\r\n}','',1),
(63,3,'go编译后的程序关联详情','编译后 可删除的文件夹\r\n1.控制器 controllers 文件夹\r\n2.static文件夹\r\n但是views是不可以删除的','',1),
(64,3,'go 删除文件','os.Remove(\"123123.jpg\")','',1),
(65,3,'go 发送邮件','package models\r\n\r\nimport (\r\n	\"strconv\"\r\n\r\n	\"gopkg.in/gomail.v2\"\r\n)\r\n\r\ntype MyMail struct {\r\n	to     []string\r\n	title  string\r\n	body   string\r\n	attach string\r\n}\r\n\r\nfunc (class *MyMail) To(to string) *MyMail {\r\n	class.attach = \"\"\r\n	class.to = append(class.to, to)\r\n	return class\r\n}\r\nfunc (class *MyMail) Title(str string) *MyMail {\r\n	class.title = str\r\n	return class\r\n}\r\nfunc (class *MyMail) Body(str string) *MyMail {\r\n	class.body = str\r\n	return class\r\n}\r\nfunc (class *MyMail) Attach(path string) *MyMail {\r\n	class.attach = path\r\n	return class\r\n}\r\nfunc (class *MyMail) Send() error {\r\n	mailConn := map[string]string{\r\n		\"user\": \"282246101@qq.com\",\r\n		\"pass\": \"jwssaevivurwcbai\",\r\n		\"host\": \"smtp.qq.com\",\r\n		\"port\": \"465\",\r\n	}\r\n	port, _ := strconv.Atoi(mailConn[\"port\"]) //转换端口类型为int\r\n\r\n	m := gomail.NewMessage()\r\n\r\n	m.SetHeader(\"From\", m.FormatAddress(mailConn[\"user\"], \"360xyz\"))\r\n	//这种方式可以添加别名，即“XX官方”\r\n	//说明：如果是用网易邮箱账号发送，以下方法别名可以是中文，如果是qq企业邮箱，以下方法用中文别名，会报错，需要用上面此方法转码\r\n	//m.SetHeader(\"From\", \"FB Sample\"+\"<\"+mailConn[\"user\"]+\">\") //这种方式可以添加别名，即“FB Sample”， 也可以直接用<code>m.SetHeader(\"From\",mailConn[\"user\"])</code> 读者可以自行实验下效果\r\n	//m.SetHeader(\"From\", mailConn[\"user\"])\r\n	m.SetHeader(\"To\", class.to...)      //发送给多个用户\r\n	m.SetHeader(\"Subject\", class.title) //设置邮件主题\r\n	m.SetBody(\"text/html\", class.body)  //设置邮件正文\r\n	if class.attach != \"\" {\r\n		m.Attach(class.attach) //设置邮件附件\r\n	}\r\n	d := gomail.NewDialer(mailConn[\"host\"], port, mailConn[\"user\"], mailConn[\"pass\"])\r\n\r\n	err := d.DialAndSend(m)\r\n	return err\r\n}\r\n','',1),
(66,3,'go 防止表单重复提交','package models\r\n\r\nimport (\r\n	\"math/rand\"\r\n	\"strconv\"\r\n	\"time\"\r\n\r\n	\"github.com/astaxie/beego\"\r\n)\r\n\r\nfunc FormValidation(c *beego.Controller) {\r\n	PostFormSession, _ := strconv.Atoi(c.GetString(\"FormSession\"))\r\n	if c.GetSession(\"FormSession\") != PostFormSession {\r\n		c.Ctx.Output.ContentType(\"text/html;chart=utf8\")\r\n		c.Ctx.Output.Body([]byte(\"<script>alert(\'表单重复提交了,已被拦截,生效一个\');location.href=\'../\'</script>\"))\r\n		return\r\n	}\r\n}\r\nfunc FormSessionStart(c *beego.Controller) {\r\n	rand.Seed(time.Now().UnixNano())\r\n	t := rand.Intn(999)\r\n	c.SetSession(\"FormSession\", t)\r\n	c.Data[\"FormSession\"] = t\r\n}\r\n','',1),
(67,3,'go程序linux crontab开机后台自动运行','@reboot sleep 3;cd /opt/gogin;nohup ./man >/dev/null 2>& 1 &','',1),
(68,3,'golang 类似php php parse_str()','//类似php php parse_str()\r\nfunc parse_str(uri string) (map[string]string, error) {\r\n	m := make(map[string]string)\r\n	if len(uri) < 1 { // 空字符串\r\n		return m, errors.New(\"uri is none\")\r\n	}\r\n	if uri[0:1] == \"?\" { // 有没有包含？,有的话忽略。\r\n		uri = uri[1:]\r\n	}\r\n\r\n	// 首先分解&（sessionid=22222&token=3333 )变成\r\n	// sessionid=222222 和 token=3333\r\n	pars := strings.Split(uri, \"&\")\r\n	for _, par := range pars {\r\n		// 然后分解 sessionid=222222 和 token=3333\r\n		parkv := strings.Split(par, \"=\")\r\n		m[parkv[0]] = parkv[1] // 等号前面是key,后面是value\r\n	}\r\n	return m, nil\r\n}','',1),
(69,3,'golang time date 详细',' //时间 to 时间戳\r\n   loc, _ := time.LoadLocation(\"Asia/Shanghai\")        //设置时区\r\n   tt, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", \"2018-07-11 15:07:51\", loc) //2006-01-02 15:04:05是转换的格式如php的\"Y-m-d H:i:s\"\r\n   fmt.Println(tt.Unix())                             //1531292871\r\n  \r\n   //时间戳 to 时间\r\n   tm := time.Unix(1531293019, 0)\r\n   fmt.Println(tm.Format(\"2006-01-02 15:04:05\")) //2018-07-11 15:10:19\r\n//12小时制\r\ntime.Now().Format(\"2006-01-02 03:04:05\")\r\n\r\n//24小时制 15刚好是下午3点\r\ntime.Now().Format(\"2006-01-02 15:04:05\")\r\n//当天0点时间戳\r\n	a := time.Now().Format(\"2006-01-02\")\r\n	tt, _ := time.Parse(\"2006-01-02\", a)\r\n	timeNumber := tt.Unix()\r\n	today_start := timeNumber - 28800\r\n	//当天23:59:59 时间戳\r\n	today_end := today_start + 86399\r\n	fmt.Print(today_end)','',1),
(70,3,'golan map range 随机问题','golan map range 每次输出都是随机顺序的\r\n如果需要 map[int]map[string]interface{}\r\n这种 map 前面或后面添加map 可以使用 range k,v 中的k 方法如下\r\n			arr[0] = make(map[string]interface{})\r\n			for k, _ := range result {\r\n				m := make(map[string]interface{})\r\n				m[\"date\"] = result[k][\"date\"]\r\n				m[\"kuaidi\"] = result[k][\"kuaidi\"]\r\n				m[\"kuaidi_number\"] = result[k][\"kuaidi_number\"]\r\n				if send == true {\r\n					m[\"name\"] = result[k][\"name\"]\r\n				}\r\n				arr[k+1] = m\r\n			}','',1),
(72,3,'golang 图片上传','file,h,err:=c.Ctx.Request.FormFile(\"imgaaa\")\r\nif err != nil {\r\nfmt.Println(\"获取上传文件失败\")\r\nreturn \r\n}\r\ndefer file.Close()\r\nf, err := os.OpenFile(\"vvwd/\"+h.Filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)\r\nif err != nil {\r\nfmt.Println(\"创建文件失败\")\r\n}\r\ndefer f.Close()\r\nio.Copy(f, file)\r\n\r\nc.TplName = \"index.html\"','',1),
(73,3,'js POST GET 两边空格','request过来的字符串两边都有好多空格\r\n必须用 js 处理一下 str.replace(/\\s+/g, \' \')\r\n清除两边空格才正常','',1),
(74,3,'跨域请求','跨域请求要在被请求服务器上设置\r\nc.Ctx.ResponseWriter.Header().Set(\"Access-Control-Allow-Origin\", \"*\")\r\n微信小程序为什么不设置Access-control-allow-origin也可以实现跨域请求？\r\n跨域请求限制是浏览器做的事情，而小程序的『浏览器』是微信，它想限制就限制不想限制就不限制','',1),
(75,3,'复制字符串到剪贴板','import \"github.com/atotto/clipboard\"\r\nclipboard.WriteAll(str)','',1),
(76,3,'golang程序开机启动方法','@reboot sleep 3; cd /var/www/html; nohup ./main &\r\n','',1),
(77,3,'go判断目录或文件是否存在，并创建','	d := time.Now().Format(\"2006-1-02\")\r\n	_, err := os.Stat(d)\r\n	if err != nil {\r\n		//fmt.Println(\"目录不存在\")\r\n		os.Mkdir(d, os.ModePerm)\r\n		fmt.Println(\"创建目录\")\r\n	}\r\n','',1),
(78,3,'go拍照自动填快递单号','package main\r\n\r\nimport (\r\n	\"bytes\"\r\n	\"encoding/base64\"\r\n	\"fmt\"\r\n	\"io\"\r\n	\"io/ioutil\"\r\n	\"net/http\"\r\n	\"os\"\r\n	\"time\"\r\n)\r\n\r\nfunc JsonPost() {\r\n	d := time.Now().Format(\"2006-1-02\")\r\n	_, err := os.Stat(d)\r\n	if err != nil {\r\n		//fmt.Println(\"目录不存在\")\r\n		os.Mkdir(d, os.ModePerm)\r\n		fmt.Println(\"创建目录\")\r\n	}\r\n	url := \"https://tysbgpu.market.alicloudapi.com/api/predict/ocr_general\"\r\n	appcode := \"5bdfc02ebd4c4f31bc9d3e0b62b8ec49\"\r\n	f, err1 := os.Open(\"a.jpg\")\r\n	if err1 != nil {\r\n		fmt.Println(\"err1\")\r\n		fmt.Println(err1)\r\n		return\r\n	}\r\n\r\n	defer f.Close()\r\n	buf := bytes.NewBuffer(nil)\r\n	io.Copy(buf, f)\r\n	//buf.Bytes()\r\n	imgstr := base64.StdEncoding.EncodeToString(buf.Bytes())\r\n	bodys := \"{\\\"image\\\": \\\"\" + imgstr + \"\\\",\\\"configure\\\":{\\\"min_size\\\":16,\\\"output_prob\\\":true,\\\"output_keypoints\\\":false,\\\"skip_detection\\\":false,\\\"without_predicting_direction\\\":false}}\"\r\n	req, _ := http.NewRequest(\"POST\", url, bytes.NewBuffer([]byte(bodys)))\r\n	req.Header.Set(\"Content-Type\", \"application/json; charset=UTF-8\")\r\n	req.Header.Set(\"Authorization\", \"APPCODE \"+appcode)\r\n	client := &http.Client{}\r\n	resp, err2 := client.Do(req)\r\n	if err2 != nil {\r\n		fmt.Println(\"err2\")\r\n		fmt.Println(err2)\r\n		return\r\n	}\r\n	defer resp.Body.Close()\r\n	// fmt.Println(\"status\", resp.Status)\r\n	// fmt.Println(\"headers\", resp.Header)\r\n	body, _ := ioutil.ReadAll(resp.Body)\r\n	fmt.Println(string(body))\r\n}\r\n\r\nfunc main() {\r\n	JsonPost()\r\n\r\n}\r\n','',1),
(79,3,'windows下编译linux GO程序','cmd cd到GO程序根目录下\r\nset GOARCH=amd64\r\nset GOOS=linux\r\n然后直接  go build main.go\r\n----------------------------------\r\ngo env -w CGO_ENABLED=0\r\ngo env -w GOARCH=amd64\r\ngo env -w GOOS=windows\r\n','',1),
(80,3,'golang 定时任务','func init() {\r\n	go func() {\r\n		MyCron()\r\n	}()\r\n}\r\n/*\r\n*内置定时任务 非使用linux crontab 比linux crontab 多一位定时时间 秒 这个是6位\r\n*定时每天早上6点查询定时任务\r\n*每周六夜里1.30分数据库导出到sql文件\r\n*每周六早上9点提取数据库备份sql附件形式发给QQ邮箱\r\n*每天早上6点40 开广告牌   19点关广告牌\r\n*只能放在init() 初始化 方法里，如果放在request是无效的\r\n */\r\nfunc MyCron() {\r\n	mycron := cron.New()\r\n	//服务器为arm64\r\n	if runtime.GOARCH == \"arm64\" {\r\n		//周六夜里1点备份远程数据库到本地\r\n		mycron.AddFunc(\"0 0 1 * * 6\", func() {\r\n			beegoPath, _ := os.Getwd()\r\n			cmd := exec.Command(\"/bin/sh\", \"-c\", beegoPath+\"/RemoteToMysql.sh\")\r\n			cmd.StdoutPipe()\r\n			cmd.StderrPipe()\r\n			cmd.Start()\r\n		})\r\n		//周六夜里1点半 导出本地数据库\r\n		mycron.AddFunc(\"0 30 1 * * 6\", func() {\r\n			beegoPath, _ := os.Getwd()\r\n			cmd := exec.Command(\"/bin/sh\", \"-c\", beegoPath+\"/mysql.sh\")\r\n			cmd.StdoutPipe()\r\n			cmd.StderrPipe()\r\n			cmd.Start()\r\n		})\r\n		//周六早上9点 邮件附件备份数据库\r\n		mycron.AddFunc(\"0 0 9 * * 6\", func() {\r\n			date := time.Now().Format(\"2006-01-02\")\r\n			date = strings.Replace(date, \"-\", \"\", -1)\r\n			date = strings.Replace(date, \"-\", \"\", -1)\r\n			sqldate := \"./tool/sql/\" + date + \".sql\"\r\n			m := models.MyMail{}\r\n			m.SendMail([]string{\"282246101@qq.com\"}, \"树莓派数据库定时附件备份\", \"数据库定时附件备份\", sqldate)\r\n		})\r\n		//每天早上6点40分 开启广告牌灯箱  多加参数  email=true 表示发邮件提醒自己\r\n		mycron.AddFunc(beego.AppConfig.String(\"BillboardStart\"), func() {\r\n			models.MyHttpGet(\"http://localhost/service/GetToPostWebsoket?room=admin&message=mydoor1->灯箱开&key=www.360xyz.cn\")\r\n		})\r\n		//每天晚上19点 关闭广告牌灯箱\r\n		mycron.AddFunc(beego.AppConfig.String(\"BillboardEnd\"), func() {\r\n			models.MyHttpGet(\"http://localhost/service/GetToPostWebsoket?room=admin&message=mydoor1->灯箱关&key=www.360xyz.cn\")\r\n		})\r\n	} else {\r\n		mycron.AddFunc(\"0 0 6 * * *\", selectRemind)\r\n		//每天早上6点40分 开启广告牌灯箱  多加参数  email=true 表示发邮件提醒自己\r\n		mycron.AddFunc(beego.AppConfig.String(\"BillboardStart\"), func() {\r\n			models.MyHttpGet(\"http://www.360xyz.cn/service/GetToPostWebsoket?room=admin&message=mydoor1->灯箱开&key=www.360xyz.cn\")\r\n		})\r\n		//每天晚上19点 关闭广告牌灯箱\r\n		mycron.AddFunc(beego.AppConfig.String(\"BillboardEnd\"), func() {\r\n			models.MyHttpGet(\"http://www.360xyz.cn/service/GetToPostWebsoket?room=admin&message=mydoor1->灯箱关&key=www.360xyz.cn\")\r\n		})\r\n		mycron.AddFunc(\"0 * * * * *\", func() {\r\n			fmt.Println(\"每分钟执行一次\")\r\n		})\r\n	}\r\n	fmt.Println(\"cron ---> start\")\r\n	mycron.Run()\r\n}','',1),
(81,3,'golang windows关机命令','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"log\"\r\n	\"net/url\"\r\n	\"os\"\r\n	\"os/exec\"\r\n	\"time\"\r\n\r\n	\"github.com/gorilla/websocket\"\r\n)\r\n\r\ntype websocketClientManager struct {\r\n	conn        *websocket.Conn\r\n	addr        *string\r\n	path        string\r\n	Userinfo    interface{}\r\n	sendMsgChan chan string\r\n	recvMsgChan chan string\r\n	isAlive     bool\r\n	timeout     int\r\n	wtype       string\r\n	user        string\r\n	password    string\r\n	room        string\r\n}\r\n\r\n// 构造函数\r\nfunc NewWsClientManager(addrIp, addrPort, path string, timeout int, wtype string, password string, room string) *websocketClientManager {\r\n	addrString := addrIp + \":\" + addrPort\r\n	var sendChan = make(chan string, 10)\r\n	var recvChan = make(chan string, 10)\r\n	var conn *websocket.Conn\r\n	//获取本机电脑名\r\n	usertemp, _ := os.Hostname()\r\n	user := usertemp\r\n\r\n	return &websocketClientManager{\r\n		addr:        &addrString,\r\n		path:        path,\r\n		conn:        conn,\r\n		sendMsgChan: sendChan,\r\n		recvMsgChan: recvChan,\r\n		isAlive:     false,\r\n		timeout:     timeout,\r\n		wtype:       wtype,\r\n		user:        user,\r\n		password:    password,\r\n		room:        room,\r\n	}\r\n}\r\n\r\n// 链接服务端\r\nfunc (this *websocketClientManager) dail(wtype string, user string, password string, room string) {\r\n	var err error\r\n\r\n	u := url.URL{Scheme: \"wss\", Host: *this.addr, Path: this.path, ForceQuery: true, RawQuery: \"user=\" + user + \"&password=\" + password + \"&room=\" + room}\r\n	log.Printf(\"connecting to %s\", u.String())\r\n	this.conn, _, err = websocket.DefaultDialer.Dial(u.String(), nil)\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		os.Exit(1)\r\n		return\r\n	}\r\n	this.isAlive = true\r\n	log.Printf(\"connecting to %s 链接成功！！！\", u.String())\r\n	//主动向服务端发送断开连接消息\r\n	this.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(4001, \"close\"), time.Now().Add(time.Second))\r\n	ShutDownEXE()\r\n}\r\n\r\nfunc ShutDownEXE() {\r\n	fmt.Println(\"关闭主机\")\r\n	arg := []string{\"-s\", \"-t\", \"0\"}\r\n	cmd := exec.Command(\"shutdown\", arg...)\r\n	_, err := cmd.CombinedOutput()\r\n	if err != nil {\r\n		fmt.Println(\"Error:\", err)\r\n		return\r\n	}\r\n}\r\nfunc main() {\r\n	wss := \"wss\"\r\n	password := \"efghijk\"\r\n	room := \"admin\"\r\n	t := NewWsClientManager(\"www.360xyz.cn\", \"443\", \"/service/wss\", 10, wss, password, room)\r\n	t.dail(t.wtype, t.user, t.password, t.room)\r\n}\r\n','',1),
(82,3,'go 短时间定时循环','	//设置定时器为15秒\r\n	timer := time.NewTimer(15 * time.Second)\r\n	fmt.Println(\"定时开始\")\r\n	for {\r\n		<-timer.C\r\n\r\n		//15秒后执行这条\r\n		fmt.Println(\"send\")\r\n		//重设定时时间\r\n		timer.Reset(15 * time.Second)\r\n		fmt.Println(\"已经重设定时时间，正在回滚for 循环\")\r\n	}','',1),
(83,3,'golang websocket 客户端','package main\r\n\r\nimport (\r\n	\"encoding/json\"\r\n	\"fmt\"\r\n	\"net\"\r\n	\"net/url\"\r\n	\"os\"\r\n	\"os/exec\"\r\n	\"strings\"\r\n	\"syscall\"\r\n	\"time\"\r\n	\"unsafe\"\r\n\r\n	\"github.com/gorilla/websocket\"\r\n)\r\n\r\n/*\r\ngo build -o xxx.exe -ldflags \"-s -w -H=windowsgui\"\r\n运行命令\r\nshell:startup\r\n把程序扔到里面\r\n*/\r\nfunc GetMac() string {\r\n	netInterfaces, err := net.Interfaces()\r\n	if err != nil {\r\n		return \"\"\r\n	}\r\n	for _, i2 := range netInterfaces {\r\n		//fmt.Println(i2.Name)\r\n		mac := i2.HardwareAddr\r\n		//fmt.Println(mac)\r\n		return mac.String()\r\n	}\r\n	return \"\"\r\n}\r\nfunc main() {\r\n	wss := \"ws\"\r\n	//获取电脑主机名\r\n	mac := GetMac()\r\n	mac = strings.TrimSpace(mac)\r\n	passwd := \"abcdefg\"\r\n	room := \"computer\"\r\n	w := WebsocketClient{}\r\n	w.Setup(\"192.168.0.254\", 80, \"/websocket\", 10, wss, mac, passwd, room, true).Start()\r\n\r\n}\r\n\r\ntype WebsocketClient struct {\r\n	conn          *websocket.Conn\r\n	addr          *string\r\n	path          string\r\n	Userinfo      interface{}\r\n	sendMsgChan   chan string\r\n	isAlive       bool //联网状态\r\n	timeout       int\r\n	wstype        string //连接 wss 还是ws\r\n	user          string\r\n	passwd        string\r\n	room          string\r\n	StartDate     string // 上线时间\r\n	Ch            chan os.Signal\r\n	authorization bool\r\n}\r\n\r\n// 初始化 Setup(\"192.168.0.254\", 443, \"/websocket\", 10, wss,user, password, room,true).Start()\r\nfunc (ggg *WebsocketClient) Setup(addrIp string, addrPort int, path string, timeout int, wstype, user, passwd, room string, authorization bool) *WebsocketClient {\r\n	ggg.authorization = authorization\r\n	var conn *websocket.Conn\r\n	ggg.conn = conn\r\n	temp := addrIp + \":\" + fmt.Sprintf(\"%d\", addrPort)\r\n	ggg.addr = &temp\r\n	ggg.path = path\r\n	ggg.sendMsgChan = make(chan string, 10)\r\n	ggg.isAlive = false\r\n	ggg.timeout = timeout\r\n	ggg.wstype = wstype\r\n	ggg.user = user\r\n	ggg.passwd = passwd\r\n	ggg.room = room\r\n	ggg.Ch = make(chan os.Signal, 1)\r\n	ggg.StartDate = time.Now().Format(\"2006-01-02 15:04\")\r\n\r\n	return ggg\r\n}\r\n\r\n// 开启服务并重连\r\nfunc (ggg *WebsocketClient) Start() {\r\n	for {\r\n		if !ggg.isAlive {\r\n			if ggg.authorization {\r\n				ggg.AuthorizationDail() //Authorization 头信息登录方式\r\n			} else {\r\n				ggg.dail()\r\n			}\r\n			if ggg.isAlive {\r\n				ggg.sendMsgThread()\r\n				ggg.readMsgThread()\r\n			}\r\n		}\r\n		time.Sleep(time.Second * time.Duration(ggg.timeout))\r\n	}\r\n}\r\n\r\n// 链接服务端\r\nfunc (ggg *WebsocketClient) AuthorizationDail() {\r\n	// 替换为实际的 WebSocket 服务器地址\r\n	url := ggg.wstype + \"://\" + *ggg.addr + ggg.path\r\n	fmt.Println(url)\r\n	var err error\r\n	// 创建自定义请求头，包含 Authorization 信息\r\n	header := make(map[string][]string)\r\n	header[\"Authorization\"] = []string{\"user=\" + ggg.user + \"&passwd=\" + ggg.passwd + \"&room=\" + ggg.room}\r\n	ggg.conn, _, err = websocket.DefaultDialer.Dial(url, header)\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		ggg.isAlive = false\r\n		//os.Exit(1)\r\n		return\r\n	}\r\n	ggg.isAlive = true\r\n	fmt.Println(\"链接成功！！！\")\r\n	ggg.StartDate = time.Now().Format(\"2006-01-02 15:04\")\r\n	ggg.conn.WriteMessage(websocket.TextMessage, []byte(\"上线时间\"+ggg.StartDate))\r\n	ggg.conn.PongHandler()\r\n	ggg.conn.SetPingHandler(func(appData string) error {\r\n		fmt.Println(\"单片机返回ping 消息是\" + appData)\r\n		//设置pong超时时间 因为这个只能生效一次,所以每次接受到pong都设置一次\r\n		ggg.conn.SetReadDeadline(time.Now().Add(time.Second * 50)) //20秒ping一次50秒2次没收到返回pong认定超时\r\n		return nil\r\n	})\r\n}\r\n\r\n// 链接服务端\r\nfunc (ggg *WebsocketClient) dail() {\r\n	var err error\r\n	u := url.URL{Scheme: ggg.wstype, Host: *ggg.addr, Path: ggg.path, ForceQuery: true, RawQuery: \"user=\" + ggg.user + \"&passwd=\" + ggg.passwd + \"&room=\" + ggg.room}\r\n	fmt.Println(\"connecting to \" + u.String())\r\n	ggg.conn, _, err = websocket.DefaultDialer.Dial(u.String(), nil)\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		ggg.isAlive = false\r\n		//os.Exit(1)\r\n		return\r\n	}\r\n\r\n	ggg.isAlive = true\r\n	fmt.Println(\"链接成功！！！\")\r\n	ggg.StartDate = time.Now().Format(\"2006-01-02 15:04\")\r\n	ggg.conn.WriteMessage(websocket.TextMessage, []byte(\"上线时间\"+ggg.StartDate))\r\n\r\n}\r\n\r\n// 发送消息\r\nfunc (ggg *WebsocketClient) sendMsgThread() {\r\n	go func() {\r\n		for {\r\n			msg := <-ggg.sendMsgChan\r\n			err := ggg.conn.WriteMessage(websocket.TextMessage, []byte(msg))\r\n			if err != nil {\r\n				fmt.Println(\"write:\", err)\r\n				continue\r\n			}\r\n		}\r\n	}()\r\n}\r\n\r\n// 读取消息\r\nfunc (ggg *WebsocketClient) readMsgThread() {\r\n	go func() {\r\n		for {\r\n			if ggg.conn != nil {\r\n				msgType, msg, err := ggg.conn.ReadMessage()\r\n				if err != nil {\r\n					fmt.Println(\"read:超时\", err)\r\n					ggg.isAlive = false\r\n					return\r\n				}\r\n				if msgType == 9 {\r\n					//响应服务器主动发来的pong 表示我还在线\r\n					//ggg.conn.WriteMessage(websocket.PongMessage, []byte{})\r\n					ggg.conn.WriteControl(websocket.PongMessage, []byte{}, time.Now().Add(time.Second))\r\n				}\r\n				var msgs map[string]string\r\n				json.Unmarshal(msg, &msgs)\r\n				fmt.Println(msgs[\"message\"])\r\n				if len(msgs[\"message\"]) != 0 {\r\n					if strings.Contains(msgs[\"message\"], ggg.user+\".\") {\r\n						if msgs[\"message\"] == ggg.user+\".shutdown\" {\r\n							ggg.conn.WriteMessage(websocket.TextMessage, []byte(\"执行关机中...\"))\r\n							//主动向服务端发送断开连接消息\r\n							ggg.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(4001, \"close\"), time.Now().Add(time.Second))\r\n							time.Sleep(time.Millisecond * 200)\r\n							ShutDown()\r\n							return\r\n						}\r\n						x := WindowsAlert{}\r\n						a := []rune(msgs[\"message\"])\r\n						x.ShowMessage(\"弹窗提示\", string(a))\r\n					}\r\n				}\r\n			}\r\n		}\r\n	}()\r\n	go func() {\r\n		for {\r\n			s := <-ggg.Ch\r\n			switch s {\r\n			case syscall.SIGINT:\r\n				ggg.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(4001, \"close\"), time.Now().Add(time.Millisecond*100))\r\n				//fmt.Println(\"退出前执行\")\r\n			case syscall.SIGILL:\r\n				//fmt.Println(\"null\")\r\n			default:\r\n				//fmt.Println(\"default\")\r\n			}\r\n		}\r\n	}()\r\n}\r\n\r\nfunc ShutDown() {\r\n	arg := []string{\"-s\", \"-t\", \"0\"}\r\n	cmd := exec.Command(\"shutdown\", arg...)\r\n	cmd.CombinedOutput()\r\n}\r\n\r\ntype WindowsAlert struct {\r\n}\r\n\r\nfunc (ggg *WindowsAlert) StrPtr(s string) uintptr {\r\n	utf16Ptr, _ := syscall.UTF16PtrFromString(s)\r\n	return uintptr(unsafe.Pointer(utf16Ptr))\r\n}\r\nfunc (ggg *WindowsAlert) ShowMessage(title, text string) {\r\n	user32dll, _ := syscall.LoadLibrary(\"user32.dll\")\r\n	user32 := syscall.NewLazyDLL(\"user32.dll\")\r\n	MessageBoxW := user32.NewProc(\"MessageBoxW\")\r\n	defer syscall.FreeLibrary(user32dll)\r\n	MessageBoxW.Call(uintptr(0), ggg.StrPtr(text), ggg.StrPtr(title), uintptr(0))\r\n	time.Sleep(time.Second * 3)\r\n}\r\n','',1),
(84,3,'golang windows开机自启动隐藏窗口','go build -o xxx.exe -ldflags \"-s -w -H=windowsgui\"\r\n运行命令\r\nshell:startup\r\n把程序扔到里面','',1),
(85,3,'go.sum','github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\r\ngithub.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=\r\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\r\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\r\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\r\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\r\ngithub.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=\r\ngithub.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=\r\ngithub.com/astaxie/beego v1.12.3 h1:SAQkdD2ePye+v8Gn1r4X6IKZM1wd28EyUOVQ3PDSOOQ=\r\ngithub.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=\r\ngithub.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=\r\ngithub.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=\r\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\r\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\r\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\r\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\r\ngithub.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=\r\ngithub.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=\r\ngithub.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=\r\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\r\ngithub.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=\r\ngithub.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=\r\ngithub.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=\r\ngithub.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=\r\ngithub.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=\r\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\r\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\r\ngithub.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=\r\ngithub.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=\r\ngithub.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=\r\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\r\ngithub.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=\r\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\r\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\r\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\r\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\r\ngithub.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=\r\ngithub.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\r\ngithub.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=\r\ngithub.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=\r\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\r\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\r\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\r\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\r\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\r\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\r\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\r\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\r\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\r\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\r\ngithub.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=\r\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\r\ngithub.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\r\ngithub.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\r\ngithub.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=\r\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\r\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\r\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\r\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\r\ngithub.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=\r\ngithub.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=\r\ngithub.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=\r\ngithub.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=\r\ngithub.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=\r\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\r\ngithub.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\r\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\r\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\r\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\r\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\r\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\r\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\r\ngithub.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=\r\ngithub.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=\r\ngithub.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=\r\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\r\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\r\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\r\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\r\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\r\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\r\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\r\ngithub.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=\r\ngithub.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=\r\ngithub.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=\r\ngithub.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=\r\ngithub.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\r\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\r\ngithub.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=\r\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\r\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\r\ngithub.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\r\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\r\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\r\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\r\ngithub.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=\r\ngithub.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=\r\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\r\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\r\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\r\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\r\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\r\ngithub.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=\r\ngithub.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=\r\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\r\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\r\ngithub.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=\r\ngithub.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=\r\ngithub.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=\r\ngithub.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=\r\ngithub.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=\r\ngithub.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=\r\ngithub.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=\r\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\r\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\r\ngithub.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=\r\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\r\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\r\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\r\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\r\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\r\ngithub.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=\r\ngithub.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=\r\ngithub.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=\r\ngithub.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=\r\ngithub.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=\r\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\r\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\r\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=\r\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\r\ngolang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\r\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\r\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\r\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\r\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=\r\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\r\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\r\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\r\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\r\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\r\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\r\ngolang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\r\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\r\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\r\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\r\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\r\ngolang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\r\ngolang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\r\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=\r\ngolang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\r\ngolang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=\r\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\r\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\r\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\r\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\r\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\r\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\r\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\r\ngoogle.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=\r\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\r\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\r\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\r\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\r\ngopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\r\ngopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=\r\ngopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=\r\ngopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=\r\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\r\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\r\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\r\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\r\ngopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=\r\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\r\ngithub.com/nosixtools/solarlunar@v0.0.0-20211112060703-1b6dea7b4a19','',1),
(86,3,'golang 阳历 阴历互转换','import (\r\n	\"fmt\"\r\n	\"time\"\r\n\r\n	\"github.com/nosixtools/solarlunar\"\r\n)\r\n\r\nfunc main() {\r\n	//阳历转阴历 中文\r\n	solarDate := time.Now().Format(\"2006-01-02\")\r\n	fmt.Println(solarlunar.SolarToChineseLuanr(solarDate))\r\n\r\n	//阳历转阴历 数字\r\n	fmt.Println(solarlunar.SolarToSimpleLuanr(solarDate))\r\n\r\n	//阴历转阳历\r\n	lunarDate := \"2022-02-26\"\r\n	fmt.Println(solarlunar.LunarToSolar(lunarDate, false))\r\n}','',1),
(87,3,'git 使用','cd 到仓库目录 \r\ngit init 初始化成本地仓库\r\ngit add .   //添加所有\r\n\r\ngit config --global user.email \"任意邮箱名都行\"\r\ngit config --global user.name \"\"\r\n\r\ngit commit -m \"添加到仓库的备注\"\r\ngit branch -M  分支名\r\ngit push -u origin main\r\n\r\n//-b 表示从分支下载\r\ngit clone -b 分支名 url','',1),
(88,3,'go 抽奖','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"math/rand\"\r\n	\"time\"\r\n)\r\n\r\n//查询数组是否有重复 返回重复数组位置 没有重复返回0\r\nfunc RepeatInt(arr []int) int {\r\n	m := make(map[int]int)\r\n	for k, v := range arr {\r\n		_, ok := m[v]\r\n		if ok {\r\n			return k\r\n		} else {\r\n			m[v] = 1\r\n		}\r\n\r\n	}\r\n	return 0\r\n}\r\n\r\n//从 ii 个数随机取 getCount个 随机数\r\nfunc IntRan(ii int, getCount int) []int {\r\n	a := time.Now().Unix()\r\n	rand.Seed(a)\r\n	arr := []int{}\r\n	for i := 0; i < getCount; i++ {\r\n		a := rand.Intn(ii) + 1\r\n		arr = append(arr, a)\r\n	}\r\n	return arr\r\n}\r\nfunc GetCj() []int {\r\n	arr := []int{}\r\n	for {\r\n		arr = IntRan(99, 10)\r\n		if RepeatInt(arr) == 0 {\r\n			break\r\n		}\r\n	}\r\n	fmt.Println(arr)\r\n	a := []int{}\r\n	for {\r\n		a = IntRan(9, 3)\r\n		//fmt.Println(a)\r\n		if RepeatInt(a) == 0 {\r\n			break\r\n		}\r\n	}\r\n	fmt.Println(a)\r\n	result := []int{}\r\n	for _, v := range a {\r\n		result = append(result, arr[v])\r\n	}\r\n	return result\r\n}\r\nfunc main() {\r\n	a := GetCj()\r\n	fmt.Println(a)\r\n}\r\n','',1),
(89,3,'用fmt.Sprintf 其它类型转换 string','格  式 	描  述\r\n%v 	按值的本来值输出\r\n%+v 	在 %v 基础上，对结构体字段名和值进行展开\r\n%#v 	输出 Go 语言语法格式的值\r\n%T 	输出 Go 语言语法格式的类型和值\r\n%% 	输出 % 本体\r\n%b 	整型以二进制方式显示\r\n%o 	整型以八进制方式显示\r\n%d 	整型以十进制方式显示\r\n%x 	整型以十六进制方式显示\r\n%X 	整型以十六进制、字母大写方式显示\r\n%U 	Unicode 字符\r\n%f 	浮点数\r\n%p 	指针，十六进制方式显示\r\n\r\nint 转string  fmt.Sprintf(\"%d\",int)\r\nfloat 转string  fmt.Sprintf(\"%f\",float) //保留6位小数，如果要只保留两位小数  fmt.Sprintf(\"%.2f\",float)\r\nbool 转string  fmt.Sprintf(\"%t\",float)\r\nbyte 转string  fmt.Sprintf(\"%c\",float) //单字符\r\n一般常用的是用 strconv 包转换','',1),
(90,3,'字符串修改 ','一个英文字母占用一个字节，一个汉字占用三个字节\r\nbyte  //支持英文\r\ns2:=\"big\"\r\nbyte2:=[]byte(s2)\r\nbyte2[0]=\"p\"\r\nfmt.Println(string(byte2)) //pig\r\nnune //支持utf-8 \r\ns2:=\"大家好golang\"\r\nrune2:=[]rune(s2)\r\nrune2[0]=\"家\"\r\nfmt.println(string(rune2))   //家家好golang','',1),
(91,3,'获取当前项目根目录路径','beegoPath, _ := os.Getwd()','',1),
(92,3,'golang yaml读取配置文件类','package models\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"io/ioutil\"\r\n\r\n	\"gopkg.in/yaml.v2\"\r\n)\r\n\r\ntype YmlRead struct {\r\n}\r\n\r\nfunc (this *YmlRead) Read(filePath string) (map[string]interface{}, error) {\r\n	data, err := ioutil.ReadFile(filePath)\r\n	if err != nil {\r\n		fmt.Println(\"err\")\r\n		return nil, err\r\n	}\r\n	a := make(map[string]interface{})\r\n	err1 := yaml.Unmarshal([]byte(data), &a)\r\n	if err1 != nil {\r\n		fmt.Println(\"err1\")\r\n		return nil, err1\r\n	}\r\n	return a, nil\r\n}\r\n','',1),
(93,3,'go 递归删除全部文件','package models\r\n\r\nimport (\r\n	\"io/ioutil\"\r\n	\"os\"\r\n	\"runtime\"\r\n)\r\n\r\ntype DeleteAll struct {\r\n}\r\n\r\n// 递归循环删除目录及文件\r\nfunc (this *DeleteAll) Dir(d string) bool {\r\n	if d[len(d)-1:] == \"/\" {\r\n		d = d[0 : len(d)-1]\r\n	}\r\n	files, err := ioutil.ReadDir(d)\r\n	if err != nil {\r\n		return false\r\n	}\r\n	fuhk := \"/\"\r\n	if runtime.GOOS == \"windows\" {\r\n		fuhk = \"\\\\\"\r\n	}\r\n	for _, v := range files {\r\n		if v.IsDir() {\r\n			path := d + fuhk + v.Name()\r\n			this.Dir(path)\r\n		} else {\r\n			os.Remove(v.Name())\r\n		}\r\n	}\r\n	return true\r\n}\r\n','',1),
(94,3,'获取变量类型','两种方法\r\nfmt.Println(fmt.Sprintf(\"%T\", a))\r\nfmt.Println(reflect.TypeOf(a))','',1),
(95,3,'golang get post请求','package models\r\n\r\nimport (\r\n	\"bytes\"\r\n	\"io\"\r\n	\"time\"\r\n\r\n	\"net/http\"\r\n	\"strings\"\r\n)\r\n\r\ntype XyzRequest struct {\r\n}\r\n\r\n// Get请求 url里携带参数\r\nfunc (class *XyzRequest) Get(url string) (string, error) {\r\n	var err error\r\n	myhttp := &http.Client{}\r\n	myhttp.Timeout = time.Duration(3 * time.Second)\r\n	resp, err1 := myhttp.Get(url)\r\n	if err1 != nil {\r\n		return \"\", err\r\n	}\r\n	defer resp.Body.Close()\r\n	body, err2 := io.ReadAll(resp.Body)\r\n	if err2 != nil {\r\n		return \"\", err\r\n	}\r\n	return string(body), nil\r\n}\r\n\r\n// post地址 请求参数，string格式\r\nfunc (class *XyzRequest) Post(url string, KVstring string) (string, error) {\r\n	var err error\r\n	myhttp := &http.Client{}\r\n	myhttp.Timeout = time.Duration(3 * time.Second)\r\n	resp, err1 := myhttp.Post(url, \"application/x-www-form-urlencoded; charset=UTF-8\", strings.NewReader(KVstring))\r\n	if err1 != nil {\r\n		return \"\", err\r\n	}\r\n	defer resp.Body.Close()\r\n	body, err2 := io.ReadAll(resp.Body)\r\n	if err2 != nil {\r\n		return \"\", err\r\n	}\r\n	return string(body), nil\r\n}\r\n\r\n// post地址 请求参数，json格式 返回json\r\nfunc (class *XyzRequest) PostJson(url string, strJson string) (string, error) {\r\n	var err error\r\n	req, _ := http.NewRequest(\"POST\", url, bytes.NewBuffer([]byte(strJson)))\r\n	req.Header.Set(\"Content-Type\", \"application/json; charset=UTF-8\")\r\n	client := &http.Client{}\r\n	client.Timeout = time.Duration(3 * time.Second)\r\n	resp, err2 := client.Do(req)\r\n	if err2 != nil {\r\n		return \"\", err\r\n	}\r\n	defer resp.Body.Close()\r\n	// fmt.Println(\"status\", resp.Status)\r\n	// fmt.Println(\"headers\", resp.Header)\r\n	body, err3 := io.ReadAll(resp.Body)\r\n	if err3 != nil {\r\n		return \"\", err\r\n	}\r\n	return string(body), nil\r\n}\r\n','',1),
(96,3,'golang 连接数据库类','package models\r\n\r\nimport (\r\n	\"database/sql\"\r\n	\"fmt\"\r\n	\"reflect\"\r\n\r\n	_ \"github.com/go-sql-driver/mysql\"\r\n)\r\n\r\ntype Gdo struct {\r\n	conn *sql.DB\r\n	arr  []interface{}\r\n	stmt *sql.Stmt\r\n}\r\n\r\nfunc NewGdo(dbDatabase string) *Gdo {\r\n	conn, err := sql.Open(\"mysql\", \"root:qq282246101@tcp(localhost:3306)/\"+dbDatabase+\"?charset=utf8\")\r\n	if err != nil {\r\n		fmt.Println(\"连接数据库失败\")\r\n		conn.Close()\r\n	}\r\n	conn.SetConnMaxLifetime(100)\r\n	conn.SetMaxOpenConns(30)\r\n	g := &Gdo{}\r\n	g.conn = conn\r\n	return g\r\n}\r\nfunc (this *Gdo) Sql(sql string, arr ...interface{}) *Gdo {\r\n	Stmt, err := this.conn.Prepare(sql)\r\n	if err != nil {\r\n		fmt.Printf(\"prepare sql failed, err:%v\\n\", err)\r\n		this.conn.Close()\r\n		return nil\r\n	}\r\n	this.stmt = Stmt\r\n	this.arr = arr\r\n	return this\r\n}\r\n\r\n// 查询成功 返回 true 返回值是 bool 手动写 指针取值\r\nfunc (this *Gdo) Row(show ...interface{}) bool {\r\n	row, _ := this.stmt.Query(this.arr...)\r\n	defer row.Close()\r\n	bl := row.Next()\r\n	if bl == false {\r\n		return false\r\n	}\r\n	row.Scan(show...)\r\n\r\n	return true\r\n}\r\n\r\n// 返回*sql.Rows, error 手动写 指针取值\r\nfunc (this *Gdo) RowS() (*sql.Rows, error) {\r\n	rows, err := this.stmt.Query(this.arr...)\r\n	return rows, err\r\n}\r\n\r\n// 失败返回空MAP 返回数据全部是string 数据库字段默认null即sql.NullString之类不能使用该方法\r\nfunc (this *Gdo) Fetch() map[string]string {\r\n	result := make(map[string]string)\r\n	row, _ := this.stmt.Query(this.arr...)\r\n	column, err := row.Columns()\r\n	if err != nil {\r\n		return result\r\n	}\r\n	values := make([][]byte, len(column))\r\n	scans := make([]interface{}, len(column))\r\n	for i, _ := range values {\r\n		scans[i] = &values[i]\r\n	}\r\n	defer row.Close()\r\n	bl := row.Next()\r\n	if bl == false {\r\n		return result\r\n	}\r\n	row.Scan(scans...)\r\n	for i, v := range values {\r\n		key := column[i]\r\n		result[key] = string(v)\r\n	}\r\n	return result\r\n}\r\n\r\n// 失败返回空MAP 返回数据全部是string 数据库字段默认null即sql.NullString之类不能使用该方法\r\nfunc (this *Gdo) FetchAll() map[int]map[string]string {\r\n	result := make(map[int]map[string]string)\r\n	rows, _ := this.stmt.Query(this.arr...)\r\n	//得到 select 查询字段名与个数\r\n	column, err := rows.Columns()\r\n	if err != nil {\r\n		return result\r\n	}\r\n	values := make([][]byte, len(column))\r\n	//fmt.Println(values)\r\n	scans := make([]interface{}, len(column))\r\n	for i, _ := range values {\r\n		scans[i] = &values[i]\r\n	}\r\n	//fmt.Println(scans)\r\n	i := 0\r\n	defer rows.Close()\r\n	for rows.Next() {\r\n		rows.Scan(scans...)\r\n		row := make(map[string]string)\r\n		for i, v := range values {\r\n			key := column[i]\r\n			row[key] = string(v)\r\n		}\r\n		result[i] = row\r\n		i++\r\n	}\r\n	return result\r\n}\r\n\r\n// 失败返回0 成功返回 受影响行的个数\r\nfunc (this *Gdo) Execute() int64 {\r\n	crow, _ := this.stmt.Exec(this.arr...)\r\n	re, err := crow.RowsAffected()\r\n	if err != nil {\r\n		return 0\r\n	}\r\n	return re\r\n}\r\n\r\n// 失败返回0 成功返回 行的id\r\nfunc (this *Gdo) Insert() int64 {\r\n	crow, _ := this.stmt.Exec(this.arr...)\r\n	re, err := crow.LastInsertId()\r\n	if err != nil {\r\n		return 0\r\n	}\r\n	return re\r\n}\r\nfunc (this *Gdo) AutoInsert(table string, m map[string]interface{}) int64 {\r\n	sql := \"INSERT INTO \" + table + \" (\"\r\n	//(rid,user,password) VALUES (?,?,?)\r\n	ik := \"\"\r\n	iv := \"\"\r\n	var mv []interface{}\r\n	for k, v := range m {\r\n		if ik == \"\" {\r\n			ik = k + \",\"\r\n		} else {\r\n			ik = ik + k + \",\"\r\n		}\r\n		if iv == \"\" {\r\n			iv = \"?,\"\r\n		} else {\r\n			iv = iv + \"?\" + \",\"\r\n		}\r\n		mv = append(mv, v)\r\n	}\r\n	ik = ik[0 : len(ik)-1]\r\n	iv = iv[0 : len(iv)-1]\r\n	sql = sql + ik + \") VALUES (\" + iv + \")\"\r\n	return this.Sql(sql, mv...).Insert()\r\n}\r\nfunc StructToMap(obj interface{}) map[string]interface{} {\r\n	t := reflect.TypeOf(obj)\r\n\r\n	//获取到里面的值 一维数组 {100 beego gobee}\r\n	v := reflect.ValueOf(obj)\r\n	data := make(map[string]interface{})\r\n	for i := 0; i < t.NumField(); i++ {\r\n		//得到键名                //得到里面的值\r\n		data[t.Field(i).Name] = v.Field(i)\r\n	}\r\n	return data\r\n}\r\nfunc StructToMapS(obj interface{}) map[string]string {\r\n	t := reflect.TypeOf(obj)\r\n\r\n	//获取到里面的值 一维数组 {100 beego gobee}\r\n	v := reflect.ValueOf(obj)\r\n	data := make(map[string]string)\r\n	for i := 0; i < t.NumField(); i++ {\r\n		//得到键名                //得到里面的值\r\n		data[t.Field(i).Name] = v.Field(i).String()\r\n	}\r\n	return data\r\n}\r\n','',1),
(97,3,'go 泛型 ','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n)\r\n\r\n// 定义一个inteface 里面包含多个数据类型\r\ntype Cde interface {\r\n	int64 | float64 | ~string\r\n}\r\n\r\nfunc add[T Cde](x, y T) T {\r\n	return x + y\r\n}\r\nfunc main() {\r\n	var c, d int64\r\n	c = 3\r\n	d = 8\r\n	a := add(c, d)\r\n	fmt.Println(a)\r\n}\r\n','',1),
(98,3,'重定向301 302区别','301是永久访问a直接跳转b， 缓存了跳转连接\r\n下次访问a直接跳转b了,不会经过b后台程序\r\n\r\n302是临时的 关了网页就没了,用302多','',1),
(99,3,'获取随机字符串','//获取随机字符串\r\nfunc GetRandString(length int) string {\r\n	if length < 1 {\r\n		return \"\"\r\n	}\r\n	char := \"abcdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWSYZ0123456789\"\r\n	charArr := strings.Split(char, \"\")\r\n	//fmt.Println(charArr)\r\n	charlen := len(charArr)\r\n\r\n	b := rand.New(rand.NewSource(time.Now().Unix()))\r\n	//fmt.Println(b)\r\n	str := \"\"\r\n	for i := 1; i <= length; i++ {\r\n		r := b.Intn(charlen)\r\n		str = str + charArr[r]\r\n	}\r\n	return str\r\n}\r\n','',1),
(100,3,'go 微信小程序登录解密','package main\r\n\r\nimport (\r\n	\"crypto/aes\"\r\n	\"crypto/cipher\"\r\n	\"encoding/base64\"\r\n	\"fmt\"\r\n	\"strings\"\r\n)\r\n\r\nfunc main() {\r\n	var appid = \"wx4f4bc4dec97d474b\"\r\n	var sessionKey = \"tiihtNczf5v6AKRyjwEUhQ==\"\r\n	var iv = \"r7BXXKkLb8qrSNn05n0qiA==\"\r\n	var encryptedData = \"CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew==\"\r\n	str := DecryptWXOpenData(sessionKey, encryptedData, iv)\r\n	if strings.Index(str, appid) != -1 {\r\n		fmt.Println(\"解析成功\")\r\n	} else {\r\n		fmt.Println(\"失败\")\r\n	}\r\n\r\n}\r\nfunc DecryptWXOpenData(sessionKey, encryptData, iv string) string {\r\n	decodeBytes, err := base64.StdEncoding.DecodeString(encryptData)\r\n	if err != nil {\r\n		return \"\"\r\n	}\r\n	sessionKeyBytes, err := base64.StdEncoding.DecodeString(sessionKey)\r\n	if err != nil {\r\n		return \"\"\r\n	}\r\n	ivBytes, err := base64.StdEncoding.DecodeString(iv)\r\n	if err != nil {\r\n		return \"\"\r\n	}\r\n	dataBytes, err := AesDecrypt(decodeBytes, sessionKeyBytes, ivBytes)\r\n	return string(dataBytes)\r\n}\r\n\r\nfunc AesDecrypt(crypted, key, iv []byte) ([]byte, error) {\r\n	block, err := aes.NewCipher(key)\r\n	if err != nil {\r\n		return nil, err\r\n	}\r\n	//blockSize := block.BlockSize()\r\n	blockMode := cipher.NewCBCDecrypter(block, iv)\r\n	origData := make([]byte, len(crypted))\r\n	blockMode.CryptBlocks(origData, crypted)\r\n	//获取的数据尾端有\'/x0e\'占位符,去除它\r\n	for i, ch := range origData {\r\n		if ch == \'\\x0e\' {\r\n			origData[i] = \' \'\r\n		}\r\n	}\r\n	//{\"phoneNumber\":\"15082726017\",\"purePhoneNumber\":\"15082726017\",\"countryCode\":\"86\",\"watermark\":{\"timestamp\":1539657521,\"appid\":\"wx4c6c3ed14736228c\"}}//<nil>\r\n	return origData, nil\r\n}\r\n','',1),
(101,3,'rune 的作用','rune 是把中文也计算进字符串，不会出现乱码报错\r\n[]rune(\"\")','',1),
(102,3,'* 和 & 的区别 ','任何变量都有 内存地址和值 组成\r\n指针也是\r\n\r\n指针的值 是一个变量的内存地址\r\n这个指针它也有自己的内存地址\r\n\r\n* 代表取指针地址中存的值\r\n& 代表取一个值的内存地址\r\nfunc main() {\r\n	a := 100\r\n	var ptr *int\r\n\r\n	ptr = &a\r\n	fmt.Println(ptr)\r\n	fmt.Println(*ptr)//获取值\r\n	fmt.Println(*&a)//获取值\r\n}\r\n','',1),
(103,3,'golang file_get_content','	res, err := http.Get(\"https://img2.baidu.com/it/u=9107913,2560446129&fm=253&fmt=auto&app=138&f=JPEG?w=281&h=500\")\r\n	if err != nil {\r\n		fmt.Println(\"err\")\r\n	}\r\n	robots, _ := ioutil.ReadAll(res.Body)\r\n	res.Body.Close(','',1),
(104,3,'移动ORC ','package models\r\n\r\nimport (\r\n	\"bytes\"\r\n	\"crypto/hmac\"\r\n	\"crypto/sha1\"\r\n	\"crypto/sha256\"\r\n	\"encoding/hex\"\r\n	\"errors\"\r\n	\"fmt\"\r\n	\"io\"\r\n	\"io/ioutil\"\r\n	\"net/http\"\r\n	\"net/url\"\r\n	\"strconv\"\r\n	\"strings\"\r\n	\"time\"\r\n)\r\n\r\n/* 	ocr := YiDsOcr{}\r\nresultM := ocr.New().UrlAddSignIsPostUrl().PostGetAllJson(this.GetString(\"image\")).RemoveOtherGetItems().GetItemM()\r\nfmt.Println(resultM) */\r\n\r\ntype YiDsOcr struct {\r\n	host        string\r\n	urlPath     string\r\n	url         string\r\n	query       string\r\n	AccessKey   string\r\n	Secretkey   string\r\n	Sign        string\r\n	RequestType string\r\n	PostUrl     string\r\n	AllJson     string\r\n\r\n	items  string\r\n	i      int\r\n	itemsM map[int]string\r\n}\r\n\r\n// ok\r\nfunc (this *YiDsOcr) New() *YiDsOcr {\r\n	this.RequestType = \"GET\"\r\n	this.AllJson = \"\"\r\n	this.host = \"https://api-wuxi-1.cmecloud.cn:8443\"\r\n	this.urlPath = \"/api/ocr/v1/general\"\r\n	this.url = this.host + this.urlPath\r\n	this.AccessKey = \"566fb5cc631047c9b8e330246522c6a9\"\r\n	this.Secretkey = \"cbea3dde4d414ef3915a570d1f61afb0\"\r\n	bq := \"AccessKey=\" + this.AccessKey +\r\n		\"&SignatureMethod=HmacSHA1&SignatureNonce=\" + this.Sha1(strconv.Itoa(int(time.Now().Unix()))) +\r\n		\"&SignatureVersion=V2.0&Timestamp=\" + time.Now().Format(\"2006-01-02T15:04:05Z\") +\r\n		\"&Version=2016-12-05\"\r\n	this.query = bq\r\n\r\n	this.items = \"\"\r\n	this.i = 0\r\n	this.itemsM = make(map[int]string)\r\n	return this\r\n}\r\n\r\nfunc (this *YiDsOcr) Sha256(str string) string {\r\n	m := sha256.New()\r\n	m.Write([]byte(str))\r\n	res := hex.EncodeToString(m.Sum(nil))\r\n	return res\r\n}\r\n\r\nfunc (this *YiDsOcr) Sha1(s string) string {\r\n	o := sha1.New()\r\n	o.Write([]byte(s))\r\n	res := hex.EncodeToString(o.Sum(nil))\r\n	return res\r\n}\r\n\r\nfunc (this *YiDsOcr) HmacSha1(v, keyStr string) string {\r\n	h := sha1.New()\r\n	io.WriteString(h, v)\r\n	h.Sum(nil)\r\n	//hmac ,use sha1\r\n	key := []byte(keyStr)\r\n	mac := hmac.New(sha1.New, key)\r\n	// mac := hmac.New(md5.New, key)\r\n	mac.Write([]byte(v))\r\n	a := fmt.Sprintf(\"%x\", mac.Sum(nil))\r\n	return a\r\n}\r\n\r\nfunc (this *YiDsOcr) UrlAddSignIsPostUrl() *YiDsOcr {\r\n	this.RequestType = \"POST\"\r\n	Urr := this.url + \"?\" + this.query + \"&Signature=\" + this.GetSign()\r\n	this.PostUrl = Urr\r\n	return this\r\n\r\n}\r\n\r\nfunc (this *YiDsOcr) Pencode(str string) string {\r\n	str = strings.Replace(str, \"+\", \"%20\", -1)\r\n	str = strings.Replace(str, \"*\", \"%2A\", -1)\r\n	str = strings.Replace(str, \"%7E\", \"~\", -1)\r\n	return str\r\n\r\n}\r\n\r\nfunc (this *YiDsOcr) ToASCII(str string) string {\r\n	s := strconv.QuoteToASCII(str)\r\n	true_utf := s[1 : len(s)-1]\r\n	return true_utf\r\n}\r\n\r\nfunc (this *YiDsOcr) GetSign() string {\r\n	m := make(map[int]map[string]string)\r\n	uri := this.query\r\n	if len(uri) < 1 { // 空字符串\r\n		return \"error\"\r\n	}\r\n	if uri[0:1] == \"?\" { // 有没有包含？,有的话忽略。\r\n		uri = uri[1:]\r\n	}\r\n\r\n	// 首先分解&（sessionid=22222&token=3333 )变成\r\n	// sessionid=222222 和 token=3333\r\n	pars := strings.Split(uri, \"&\")\r\n	i := 0\r\n	for _, par := range pars {\r\n		mm := make(map[string]string)\r\n		// 然后分解 sessionid=222222 和 token=3333\r\n		parkv := strings.Split(par, \"=\")\r\n		mm[parkv[0]] = parkv[1] // 等号前面是key,后面是value\r\n		m[i] = mm\r\n		i++\r\n	}\r\n	result := \"\"\r\n	for i := 0; i < len(m); i++ {\r\n		for k, v := range m[i] {\r\n			result = result + this.Pencode(url.QueryEscape(this.ToASCII(k))) + \"=\" + this.Pencode(url.QueryEscape(this.ToASCII(v))) + \"&\"\r\n		}\r\n	}\r\n	result = result[0 : len(result)-1]\r\n\r\n	//url utf8编码\r\n	re := this.RequestType + \"\\n\" +\r\n		this.Pencode(url.QueryEscape(this.urlPath)) + \"\\n\" +\r\n		this.Sha256(result)\r\n	key := this.ToASCII(\"BC_SIGNATURE&\" + this.Secretkey)\r\n	res := this.HmacSha1(re, key)\r\n\r\n	return url.QueryEscape(res)\r\n}\r\n\r\n// ok\r\nfunc (this *YiDsOcr) Parse_str(uri string) (map[string]string, error) {\r\n	m := make(map[string]string)\r\n	if len(uri) < 1 { // 空字符串\r\n		return m, errors.New(\"uri is none\")\r\n	}\r\n	if uri[0:1] == \"?\" { // 有没有包含？,有的话忽略。\r\n		uri = uri[1:]\r\n	}\r\n\r\n	// 首先分解&（sessionid=22222&token=3333 )变成\r\n	// sessionid=222222 和 token=3333\r\n	pars := strings.Split(uri, \"&\")\r\n	for _, par := range pars {\r\n		// 然后分解 sessionid=222222 和 token=3333\r\n		parkv := strings.Split(par, \"=\")\r\n		m[parkv[0]] = parkv[1] // 等号前面是key,后面是value\r\n	}\r\n	return m, nil\r\n}\r\n\r\n// 注意一点js 发送的Base64必须把头文件去除 不然报错 这API要求不能包含有头文件\r\nfunc (this *YiDsOcr) PostGetAllJson(base64 string) *YiDsOcr {\r\n	bodys := \"{\\\"image\\\": \\\"\" + base64 + \"\\\"}\"\r\n	//fmt.Println(bodys)\r\n	req, _ := http.NewRequest(\"POST\", this.PostUrl, bytes.NewBuffer([]byte(bodys)))\r\n	req.Header.Set(\"Content-Type\", \"application/json; charset=UTF-8\")\r\n	client := &http.Client{}\r\n	resp, err2 := client.Do(req)\r\n	if err2 != nil {\r\n		return nil\r\n	}\r\n	defer resp.Body.Close()\r\n	// fmt.Println(\"status\", resp.Status)\r\n	// fmt.Println(\"headers\", resp.Header)\r\n	body, _ := ioutil.ReadAll(resp.Body)\r\n	this.AllJson = string(body)\r\n	return this\r\n}\r\n\r\n// 过滤掉不需要的 只要返回内容 items\r\nfunc (this *YiDsOcr) RemoveOtherGetItems() *YiDsOcr {\r\n	//fmt.Println(restr)\r\n	start := strings.Index(this.AllJson, \"items\")\r\n	end := strings.Index(this.AllJson, \"class\")\r\n	this.items = this.AllJson[start+7 : end-2]\r\n	this.items = strings.ReplaceAll(this.items, \" \", \"\")\r\n	return this\r\n}\r\n\r\n// items 长在3000多个字符串中 找到对应 \"itemstring\":后面的值 合并到一个 map[int]string 想要的数据都在这里面\r\nfunc (this *YiDsOcr) GetItemM() map[int]string {\r\n	start := -1\r\n	end := 0\r\n	if strings.Index(this.items, \"itemstring\") != -1 {\r\n		start = strings.Index(this.items, \"itemstring\") + 12\r\n		this.items = this.items[start:]\r\n		end = strings.Index(this.items, \",\")\r\n		this.itemsM[this.i] = this.items[0:end]\r\n		this.items = this.items[end+1:]\r\n		this.i++\r\n		this.GetItemM()\r\n	}\r\n	this.AllJson = \"\"\r\n	this.i = 0\r\n	return this.itemsM\r\n}\r\n','',1),
(105,3,'HmacSha1 加密 ','func HmacSha1(v, keyStr string) string {\r\n	h := sha1.New()\r\n	io.WriteString(h, v)\r\n	h.Sum(nil)\r\n	//hmac ,use sha1\r\n	key := []byte(keyStr)\r\n	mac := hmac.New(sha1.New, key)\r\n	// mac := hmac.New(md5.New, key)\r\n	mac.Write([]byte(v))\r\n	a := fmt.Sprintf(\"%x\", mac.Sum(nil))\r\n	return a\r\n}','',1),
(106,3,'sha1 加密 ','func Sha1(s string) string {\r\n	o := sha1.New()\r\n	o.Write([]byte(s))\r\n	res := hex.EncodeToString(o.Sum(nil))\r\n	return res\r\n}','',1),
(107,3,'sha256 加密 ','func Sha256(str string) string {\r\n	m := sha256.New()\r\n	m.Write([]byte(str))\r\n	res := hex.EncodeToString(m.Sum(nil))\r\n	return res\r\n}','',1),
(108,3,'utf8编码','func ToASCII(str string) string {\r\n	s := strconv.QuoteToASCII(str)\r\n	true_utf := s[1 : len(s)-1]\r\n	return true_utf\r\n}','',1),
(109,3,'Ocr遍历items放到MAP','/*\r\nocr := OcrItems{}\r\nm := ocr.New().Getitems(jsonS)\r\n*/\r\ntype OcrItems struct {\r\n	items string\r\n	i     int\r\n	m     map[int]string\r\n}\r\n\r\nfunc (this *OcrItems) New() *OcrItems {\r\n	this.items = \"\"\r\n	this.i = 0\r\n	this.m = make(map[int]string)\r\n	return this\r\n}\r\n\r\nfunc (this *OcrItems) Getitems(str string) map[int]string {\r\n	start := -1\r\n	end := 0\r\n	this.items = str\r\n	if strings.Index(this.items, \"itemstring\") != -1 {\r\n		start = strings.Index(this.items, \"itemstring\") + 12\r\n		this.items = this.items[start:]\r\n		end = strings.Index(this.items, \",\")\r\n		this.m[this.i] = this.items[0:end]\r\n		this.items = this.items[end+1:]\r\n		this.i++\r\n		this.Getitems(this.items)\r\n	}\r\n	return this.m\r\n}\r\n','',1),
(110,3,'数据库导出成Excel或Excel导入数据库类','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"strconv\"\r\n	\"strings\"\r\n\r\n	\"github.com/xuri/excelize/v2\"\r\n)\r\n\r\ntype MyExcel struct {\r\n	f *excelize.File\r\n}\r\n\r\n// pages 文件里生成几页 默认1 生成两页写2\r\nfunc (this *MyExcel) WriteBegin(pages int) *MyExcel {\r\n	f := excelize.NewFile()\r\n	this.f = f\r\n	if pages > 1 {\r\n		//创建工作表\r\n		for i := 2; i <= pages; i++ {\r\n			f.NewSheet(\"Sheet\" + strconv.Itoa(i))\r\n		}\r\n	}\r\n	return this\r\n}\r\n\r\n/*\r\ncurrent当前执行插入页 不能超过总页数\r\ntableK插入到表格的哪行哪列\r\ntableV插入的值\r\n*/\r\nfunc (this *MyExcel) WriteExcel(current int, tableK string, tableV string) *MyExcel {\r\n	this.f.SetCellValue(\"Sheet\"+strconv.Itoa(current), tableK, tableV)\r\n	return this\r\n}\r\n\r\n// Save 生成Excel文件名(路径)\r\nfunc (this *MyExcel) Save(filaname string) error {\r\n	//设置打开后默认 页\r\n	//f.SetActiveSheet(index)\r\n	err := this.f.SaveAs(filaname)\r\n	if err != nil {\r\n		return err\r\n	}\r\n	return nil\r\n}\r\n\r\n// filename 文件名  readCount代表要读取Excel第几页（如果多页的话）\r\nfunc (this *MyExcel) ReadExcel(filename string, readCount int) ([][]string, error) {\r\n	f, err := excelize.OpenFile(filename)\r\n\r\n	if err != nil {\r\n		fmt.Println(err)\r\n	}\r\n	if readCount > 0 {\r\n		readCount--\r\n	} else {\r\n		readCount = 0\r\n	}\r\n	//f.GetSheetName(0)里面的012分别代表是123页\r\n	firstSheet := f.GetSheetName(readCount)\r\n	defer f.Close()\r\n	rows, err1 := f.GetRows(firstSheet)\r\n	return rows, err1\r\n}\r\n\r\n// strArr  := []string{\"name\", \"phone\", \"address\", \"quantity\"} Map字段   再通过map[int]map[string]interface{} 遍历插入数据库\r\nfunc (this *MyExcel) ExcelToMaps(filename string, readCount int, strArr []string) map[int]map[string]interface{} {\r\n	rows1, _ := this.ReadExcel(filename, 13)\r\n	mm := make(map[int]map[string]interface{})\r\n	mmi := 0\r\n	for _, v := range rows1 {\r\n		i := 0\r\n		m := make(map[string]interface{})\r\n		for _, v2 := range v {\r\n			strS := strings.Split(v2, \" \")\r\n			switch i {\r\n			case 0:\r\n				m[strArr[i]] = strS[0]\r\n			case 1:\r\n				m[strArr[i]] = strS[0]\r\n			case 2:\r\n				m[strArr[i]] = strS[0]\r\n			case 3:\r\n				m[strArr[i]] = strS[0]\r\n			}\r\n			i++\r\n		}\r\n		mm[mmi] = m\r\n		mmi++\r\n	}\r\n	return mm\r\n}\r\n\r\n/*  //数据库导出Excel\r\ne := MyExcel{}\r\nvar name, phone, address string\r\nvar quantity, cid int\r\ni := 1\r\nthisI := 1\r\nDb := NewGdo(\"xyz\")\r\nDb.Sql(\"SELECT count(id) FROM CommerceCustomer WHERE user=?\", \"webserver\").Fetch(&cid)\r\npage := cid / 40\r\nif cid > (page * 40) {\r\n	page++\r\n}\r\nfmt.Println(cid)\r\nfmt.Println(page)\r\ne.WriteBegin(page)\r\nrows, _ := Db.Sql(\"SELECT name,phone,address,quantity FROM CommerceCustomer WHERE user=?\", \"webserver\").FetchAll()\r\n\r\ndefer rows.Close()\r\nfor rows.Next() {\r\n	rows.Scan(&name, &phone, &address, &quantity)\r\n	e.WriteExcel(thisI, \"A\"+strconv.Itoa(i), name)\r\n	e.WriteExcel(thisI, \"B\"+strconv.Itoa(i), phone)\r\n	e.WriteExcel(thisI, \"C\"+strconv.Itoa(i), address)\r\n	e.WriteExcel(thisI, \"D\"+strconv.Itoa(i), strconv.Itoa(quantity))\r\n	//就翻页插入\r\n	if i == 40 {\r\n		//翻页第几页\r\n		thisI++\r\n		i = 0\r\n	}\r\n	i++\r\n}\r\ne.Save(\"xyz.xlsx\")\r\n*/\r\n','',1),
(111,3,'gorilla/websocket 客户端主动关闭连接','this.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(4001, \"close\"), time.Now().Add(time.Second))','',1),
(112,3,'网络传输原理','网卡MAC   链路层 \r\nip        网络层\r\n端口      传输层\r\n程序      应用层','',1),
(113,3,'golang获取MAC地址','func GetMac() string {\r\n	netInterfaces, err := net.Interfaces()\r\n	if err != nil {\r\n		return \"\"\r\n	}\r\n	for _, i2 := range netInterfaces {\r\n		//fmt.Println(i2.Name)\r\n		mac := i2.HardwareAddr\r\n		//fmt.Println(mac)\r\n		return mac.String()\r\n	}\r\n	return \"\"\r\n}','',1),
(114,3,'交叉编译','不支持 cgo交叉编译 sqlite数据库\r\narm64 ->  amd64\r\nexport CGO_ENABLED=0 GOOS=linux GOARCH=amd64\r\n//CGO_ENABLED=0 代表禁用CGO\r\ngo build main.go\r\n//重启系统 GOARCH 会自动变为arm64    CGO_ENABLED=1\r\ngo env  //查看是否已经更改\r\n\r\nwindows arm64 -> linux arm64\r\nset GOOS=linux\r\nset CGO_ENABLED=0\r\ngo build main.go','',1),
(115,3,'gin 微服务或mvc','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"goweb/models\"\r\n	\"goweb/routers\"\r\n	\"html/template\"\r\n	\"net/http\"\r\n\r\n	\"github.com/gin-contrib/sessions\"\r\n	\"github.com/gin-contrib/sessions/cookie\"\r\n	\"github.com/gin-gonic/gin\"\r\n	\"github.com/unrolled/secure\"\r\n)\r\n\r\nfunc main() {\r\n	yaml := models.YmlRead{}\r\n	yml, _ := yaml.Read(\"conf/app.yml\")\r\n	myttps := fmt.Sprintf(\"%v\", yml[\"HttpS\"])\r\n	if myttps == \"\" {\r\n		myttps = \"false\"\r\n	}\r\n\r\n	gin.SetMode(gin.ReleaseMode)\r\n	//r := gin.Default()\r\n	r := gin.New()\r\n	r.SetFuncMap(template.FuncMap{\r\n		\"strhtml\": func(s string) template.HTML {\r\n			return template.HTML(s)\r\n		},\r\n		\"substr\": func(s string, start int, end int) string {\r\n			return s[start:end]\r\n		},\r\n	})\r\n	//静态目录 css js\r\n	r.Static(\"static\", \"static\")\r\n	//前端多级目录views/admin/xxx.html\r\n	r.LoadHTMLGlob(\"views/**/**/*\")\r\n	//文件服务器\r\n	r.StaticFS(\"tool\", http.Dir(\"tool\"))\r\n	// 创建基于cookie的存储引擎，secret11111 参数是用于加密的密钥\r\n	Store := cookie.NewStore([]byte(\"360xyz\"))\r\n	// 设置session中间件，参数mysession，指的是session的名字，也是cookie的名字\r\n	// store是前面创建的存储引擎，我们可以替换成其他存储引擎\r\n	//session过期时间30分\r\n	Store.Options(sessions.Options{\r\n		MaxAge: 1800,\r\n		Path:   \"/\",\r\n	})\r\n\r\n	r.Use(sessions.Sessions(\"mysession\", Store))\r\n	//调用路由\r\n	routers.GinRouterInit(r)\r\n\r\n	if myttps == \"true\" {\r\n		https := gin.New()\r\n		https.SetFuncMap(template.FuncMap{\r\n			\"strhtml\": func(s string) template.HTML {\r\n				return template.HTML(s)\r\n			},\r\n			\"substr\": func(s string, start int, end int) string {\r\n				return s[start:end]\r\n			},\r\n		})\r\n		https.Static(\"static\", \"static\")\r\n		https.LoadHTMLGlob(\"views/**/**/*\")\r\n		https.Use(sessions.Sessions(\"mysession\", Store))\r\n		routers.GinRouterInit(https)\r\n		https.Use(func(ctx *gin.Context) {\r\n			secureMiddleware := secure.New(secure.Options{\r\n				SSLRedirect: true,\r\n				SSLHost:     \"localhost:443\",\r\n			})\r\n			err := secureMiddleware.Process(ctx.Writer, ctx.Request)\r\n			if err != nil {\r\n				return\r\n			}\r\n			ctx.Next()\r\n		})\r\n		go func() {\r\n			err7 := http.ListenAndServeTLS(\":\"+fmt.Sprintf(\"%v\", yml[\"HttpsPort\"]), fmt.Sprintf(\"%v\", yml[\"certFile\"]), fmt.Sprintf(\"%v\", yml[\"keyFile\"]), https)\r\n			if err7 != nil {\r\n				fmt.Println(\"httpsError\")\r\n			}\r\n		}()\r\n	}\r\n	//不指定端口，默认8080\r\n	r.Run(\":80\")\r\n\r\n}\r\n','',1),
(116,3,'验证码','package models\r\n\r\nimport (\r\n	\"bytes\"\r\n	\"net/http\"\r\n	\"time\"\r\n\r\n	\"github.com/dchest/captcha\"\r\n	\"github.com/gin-contrib/sessions\"\r\n	\"github.com/gin-gonic/gin\"\r\n)\r\n\r\ntype CaptchaXyz struct {\r\n}\r\n\r\nfunc (this *CaptchaXyz) Captcha(ctx *gin.Context, length ...int) {\r\n	l := captcha.DefaultLen\r\n	w, h := 107, 36\r\n	if len(length) == 1 {\r\n		l = length[0]\r\n	}\r\n	if len(length) == 2 {\r\n		w = length[1]\r\n	}\r\n	if len(length) == 3 {\r\n		h = length[2]\r\n	}\r\n	captchaId := captcha.NewLen(l)\r\n	session := sessions.Default(ctx)\r\n	session.Set(\"captcha\", captchaId)\r\n	_ = session.Save()\r\n	_ = this.Serve(ctx.Writer, ctx.Request, captchaId, \".png\", \"zh\", false, w, h)\r\n}\r\nfunc (this *CaptchaXyz) CaptchaVerify(c *gin.Context, code string) bool {\r\n	session := sessions.Default(c)\r\n	if captchaId := session.Get(\"captcha\"); captchaId != nil {\r\n		session.Delete(\"captcha\")\r\n		_ = session.Save()\r\n		if captcha.VerifyString(captchaId.(string), code) {\r\n			return true\r\n		} else {\r\n			return false\r\n		}\r\n	} else {\r\n		return false\r\n	}\r\n}\r\nfunc (this *CaptchaXyz) Serve(w http.ResponseWriter, r *http.Request, id, ext, lang string, download bool, width, height int) error {\r\n	w.Header().Set(\"Cache-Control\", \"no-cache, no-store, must-revalidate\")\r\n	w.Header().Set(\"Pragma\", \"no-cache\")\r\n	w.Header().Set(\"Expires\", \"0\")\r\n\r\n	var content bytes.Buffer\r\n	switch ext {\r\n	case \".png\":\r\n		w.Header().Set(\"Content-Type\", \"image/png\")\r\n		_ = captcha.WriteImage(&content, id, width, height)\r\n	case \".wav\":\r\n		w.Header().Set(\"Content-Type\", \"audio/x-wav\")\r\n		_ = captcha.WriteAudio(&content, id, lang)\r\n	default:\r\n		return captcha.ErrNotFound\r\n	}\r\n\r\n	if download {\r\n		w.Header().Set(\"Content-Type\", \"application/octet-stream\")\r\n	}\r\n	http.ServeContent(w, r, id+ext, time.Time{}, bytes.NewReader(content.Bytes()))\r\n	return nil\r\n}\r\nif !Cpt.CaptchaVerify(ctx, ctx.PostForm(\"captcha\")) {\r\n			ctx.Writer.Write([]byte(\"<script>alert(\'验证码错误\');location.href=\'../account/login\'</script>\"))\r\n		}','',1),
(117,3,'Beego  Gin 区别','Beego                             Gin区别\r\n----------------------------------------------------Context 区别---------------------------------------------\r\nContext集成在控制器controller类里        方法里转入 func xxx(ctx *gin.Context)\r\n\r\n-----------------------------------------------get请求-----------------------------------------------------------\r\nthis.Ctx.Input.Query(\"key\")                                  ctx.Query(\"key\")\r\n\r\n-----------------------------------------------post请求------------------------------------------------------------\r\nthis.Ctx.Request.PostFormValue(\"key\")              ctx.Request.PostFormValue(\"key\")\r\n\r\n------------------------------------------网页返回字符串-------------------------------------------------------\r\nthis.Ctx.WriteString(\"返回的字符串\")                 ctx.String(200,\"返回的字符串\")\r\n\r\n------------------------------------------网页弹出提示框-------------------------------------------------------\r\nthis.Ctx.Output.ContentType(\"text/html;chart=utf8\")\r\nthis.Ctx.Output.Body([]byte(\"<script>alert(\'不能重复登录\');location.href=\'../\'</script>\"))\r\n\r\nctx.Writer.Write([]byte(\"<script>alert(\'不能重复登录\');location.href=\'../\'</script>\"))\r\n-----------------------------------------------Cookie操作-------------------------------------------------------\r\nthis.Ctx.SetCookie(\"key\", \"value\", time.Now().Unix()+3600)    ctx.SetCookie(\"key\",\"value\",int(time.Now().Unix()),\"/\",ctx.Request.Host,false,true)\r\n\r\nthis.Ctx.GetCookie(\"key\")                           cookie, err := ctx.Cookie(\"key\")\r\n\r\n---------------------------------------------Session操作----------------------------------------------------------\r\n                              		//传Context获取session := sessions.Default(ctx)\r\nthis.SetSession(\"key\")                                  session.Set(\"key\", value)\r\n//必须执行保存操作session.Save()\r\n\r\nthis.GetSession(\"key\")                                      session.Get(\"key\")                 \r\n----------------------------------------------------前端加载------------------------------------------------------\r\nthis.Data[“key”]=value\r\nthis.TplName = \"test/index.html\"             ctx.HTML(200, \"test/index.html\", data)\r\n--------------------------------------获取前端提交的图片---------------------------------------------------\r\nc.Ctx.Request.FormFile(\"imageKey\")               ctx.Request.FormFile(\"imageKey\")\r\n\r\n\r\n\r\n','',1),
(118,3,'Beego VS  Gin','Beego                                           Gin区别\r\n\r\nContext 区别\r\nContext集成在控制器controller类里        方法里转入 func xxx(ctx *gin.Context)\r\n\r\n\r\nget请求\r\nthis.Ctx.Input.Query(\"key\")                                  ctx.Query(\"key\")\r\n\r\n\r\npost请求\r\nthis.Ctx.Request.PostFormValue(\"key\")              ctx.Request.PostFormValue(\"key\")\r\n\r\n\r\n网页返回字符串-\r\nthis.Ctx.WriteString(\"返回的字符串\")                 ctx.String(200,\"返回的字符串\")\r\n\r\n\r\n网页弹出提示框-\r\nthis.Ctx.Output.ContentType(\"text/html;chart=utf8\")\r\nthis.Ctx.Output.Body([]byte(\"<script>alert(\'不能重复登录\');location.href=\'../\'</script>\"))\r\n\r\nctx.Writer.Write([]byte(\"<script>alert(\'不能重复登录\');location.href=\'../\'</script>\"))\r\n\r\n\r\n-Cookie操作-\r\nthis.Ctx.SetCookie(\"key\", \"value\", time.Now().Unix()+3600)    ctx.SetCookie(\"key\",\"value\",int(time.Now().Unix()),\"/\",ctx.Request.Host,false,true)\r\n\r\nthis.Ctx.GetCookie(\"key\")                           cookie, err := ctx.Cookie(\"key\")\r\n\r\n\r\nSession操作\r\n                              		//传Context获取session := sessions.Default(ctx)\r\nthis.SetSession(\"key\")                                  session.Set(\"key\", value)\r\n//必须执行保存操作session.Save()\r\nthis.GetSession(\"key\")                                      session.Get(\"key\")   \r\n\r\n              \r\n前端加载-\r\nthis.Data[“key”]=value\r\nthis.TplName = \"test/index.html\"             ctx.HTML(200, \"test/index.html\", data)\r\n\r\n\r\n获取前端提交的图片-\r\nc.Ctx.Request.FormFile(\"imageKey\")               ctx.Request.FormFile(\"imageKey\")\r\n\r\n\r\n\r\n','',1),
(119,3,'interface 转 string','fmt.Sprintf(\"%v\", interface)','',1),
(120,3,'RESTful 风格','GET    //获取\r\nPOST  //创建\r\nPUT    //更改\r\nDELETE //删除','',1),
(121,3,'文件读写类 ','package models\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"io\"\r\n	\"os\"\r\n)\r\n\r\n// 文件读写\r\ntype FileWR struct {\r\n}\r\n\r\n// 只读\r\nfunc (this *FileWR) Open(path string) string {\r\n	file, err := os.Open(path)\r\n	defer file.Close()\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		return \"\"\r\n	}\r\n	result := []byte{}\r\n	for {\r\n		mm := make([]byte, 1024)\r\n		_, errR := file.Read(mm)\r\n		if errR != nil && errR == io.EOF {\r\n			fmt.Println(\"读取完毕\")\r\n			break\r\n		}\r\n		result = append(result, mm...)\r\n	}\r\n	return string(result)\r\n}\r\n\r\n// 清空重新写入\r\nfunc (this *FileWR) Put(path string, str string) bool {\r\n	file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0666)\r\n	defer file.Close()\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		return false\r\n	}\r\n	file.WriteString(str)\r\n	return true\r\n}\r\n','',1),
(122,3,'Windows PowerShell进行ssh服务器连接','root@xxx.xxx.xxx.x\r\nyes\r\npassword','',1),
(123,3,'停车收费系统','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"strconv\"\r\n	\"time\"\r\n	\"tyieih/models\"\r\n\r\n	\"github.com/gin-gonic/gin\"\r\n)\r\n\r\nvar Db = models.Gdo{}\r\n\r\nfunc init() {\r\n	Db = *models.NewGdo()\r\n}\r\n\r\ntype VehicleSql struct {\r\n	id      int\r\n	name    string\r\n	indate  string\r\n	outdate string\r\n	day     int\r\n	monthly string\r\n}\r\n\r\n/*\r\n车牌号     ->ocr 自动拍照识别 并存到数据库   	string\r\n进场时间   ->记录时间 并存到数据库 		date\r\n出场时间    ->\r\n\r\n	10分钟内免费   ->出场时对比时间戳 少于600秒免费\r\n	3小时内 5元     ->  大于600秒 小于10800秒\r\n	3-10小时 10元   -> 大于10800秒 小于 36000秒\r\n	10-23小时15元  -> 大于36000秒 小于82800秒\r\n	0-7点过夜5元   ->如果0点前进场并且小于3小时 5元 +5元 =10元\r\n	月票400月          直接记录充值时间 +30天的到期时间date    -> 字段 monthly  string\r\n	包月到期时 如果车子还在停车场则按非包月进行计费\r\n\r\n白天和夜晚累计计费以电脑计时为准，24小时全天封顶收费20元\r\n\r\nCREATE TABLE `vehicle` (\r\n\r\n	`id` int(11) NOT NULL AUTO_INCREMENT,\r\n	`name` varchar(30) NOT NULL DEFAULT \'\',\r\n	`indate` datetime NOT NULL DEFAULT \'1000-01-01 00:00:00\',\r\n	`outdate` datetime NOT NULL DEFAULT \'1000-01-01 00:00:00\',\r\n	 `monthly` datetime DEFAULT \'1000-01-01 00:00:00\',\r\n	PRIMARY KEY (`id`)\r\n\r\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;\r\n*/\r\nfunc main() {\r\n	r := gin.Default()\r\n	//车辆进场\r\n	r.POST(\"in\", func(ctx *gin.Context) {\r\n		//1.ocr提取车辆车牌号\r\n		numberStr := \"\"\r\n		//进场 记录车牌号 进场时间\r\n		inDate := time.Now().Format(\"2006-01-02 15:04-05\")\r\n		i64 := Db.Sql(\"INSERT INTO vehicle (name,indate) VALUES (?,?)\", numberStr, inDate).Insert()\r\n		if i64 > 0 {\r\n			ctx.String(200, \"true\")\r\n		} else {\r\n			ctx.String(200, \"false\")\r\n		}\r\n\r\n	})\r\n	//车辆出场\r\n	r.POST(\"out\", func(ctx *gin.Context) {\r\n		//1.ocr提取车辆车牌号\r\n		u := VehicleSql{}\r\n		bl := Db.Sql(\"SELECT * FROM vehicle WHERE name=?\").Row(&u.id, &u.name, &u.indate, &u.outdate, &u.day, &u.monthly)\r\n		if !bl {\r\n			ctx.String(200, \"车辆查询失败,请重新识别\")\r\n			return\r\n		}\r\n		loc, _ := time.LoadLocation(\"Asia/Shanghai\")\r\n		tt, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", u.indate, loc) //2006-01-02 15:04:05是转换的格式如php的\"Y-m-d H:i:s\"\r\n		inTime := tt.Unix()\r\n		tt1, _ := time.ParseInLocation(\"2006-01-02 15:04:05\", u.outdate, loc) //2006-01-02 15:04:05是转换的格式如php的\"Y-m-d H:i:s\"\r\n		outTime := tt1.Unix()\r\n		//停车秒数\r\n		result := outTime - inTime\r\n		if result < 600 {\r\n			ctx.String(200, \"车辆10分钟内免费\")\r\n			return\r\n		}\r\n		//包月用户\r\n		if u.monthly > time.Now().Format(\"2006-01-02 15:04:05\") {\r\n			ctx.String(200, \"车辆为包月客户,免费\")\r\n			return\r\n		}\r\n		h := int64(360)\r\n		reH := result / h\r\n		//夜里0-7点进场,出场 ,并且停车时间不大于7个小时,否则以白天和夜晚累计计费以电脑计时为准\r\n		dateH, _ := strconv.Atoi(u.outdate[5:7])\r\n		if dateH < 8 && reH <= 7 {\r\n			ctx.String(200, \"夜里0-7点停车,收费5元\")\r\n			return\r\n		}\r\n\r\n		day, h, f := Calculate(result)\r\n		//停车一天内\r\n		if day == 0 {\r\n			//3-10小时 10元\r\n			if h < 3 {\r\n				ctx.String(200, \"停车\"+fmt.Sprintf(\"%d\", reH)+\"小时\"+fmt.Sprintf(\"%d\", f)+\"分,收费5元\")\r\n				return\r\n			}\r\n			//3-10小时 10元\r\n			if h < 10 {\r\n				ctx.String(200, \"停车\"+fmt.Sprintf(\"%d\", reH)+\"小时\"+fmt.Sprintf(\"%d\", f)+\"分,收费10元\")\r\n				return\r\n			}\r\n			//10-23小时15元\r\n			if h < 24 {\r\n				ctx.String(200, \"停车\"+fmt.Sprintf(\"%d\", reH)+\"小时\"+fmt.Sprintf(\"%d\", f)+\"分,收费15元\")\r\n				return\r\n			}\r\n			return\r\n		}\r\n		dayMoney := day * 10\r\n		hMoney := int64(0)\r\n		showStr := \"\"\r\n		//3-10小时 10元\r\n		if h < 3 {\r\n			hMoney = 5\r\n			showStr = fmt.Sprintf(\"%d\", h) + \"小时\" + fmt.Sprintf(\"%d\", f) + \"分,收费\"\r\n		}\r\n		//3-10小时 10元\r\n		if h < 10 {\r\n			hMoney = 10\r\n			showStr = fmt.Sprintf(\"%d\", h) + \"小时\" + fmt.Sprintf(\"%d\", f) + \"分,收费\"\r\n		}\r\n		//10-23小时15元\r\n		if h < 24 {\r\n			hMoney = 15\r\n			showStr = fmt.Sprintf(\"%d\", h) + \"小时\" + fmt.Sprintf(\"%d\", f) + \"分,收费\"\r\n		}\r\n		Money := dayMoney + hMoney\r\n		showStr = \"停车 \" + fmt.Sprintf(\"%d\", day) + \" 天\" + showStr + \" \" + fmt.Sprintf(\"%d\", Money) + \" 元\"\r\n		ctx.String(200, showStr)\r\n	})\r\n	//管理员登录 管理车辆\r\n	r.GET(\"vehicle\", func(ctx *gin.Context) {\r\n\r\n	})\r\n	r.Run(\":80\")\r\n}\r\n\r\n// 返回 天数 小时 分钟\r\nfunc Calculate(result int64) (int64, int64, int64) {\r\n	resulD := int64(0)\r\n	resulH := int64(0)\r\n	resulF := int64(0)\r\n	//一小时3600秒\r\n	h := int64(3600)\r\n	//停车总小时数\r\n	countH := result / h\r\n	//停车一天内\r\n	if countH < 24 {\r\n		miao := result - (countH * h)\r\n		if miao > 60 {\r\n			resulF = miao / 60\r\n			return 0, resulH, resulF\r\n		}\r\n		return 0, resulH, resulF\r\n	}\r\n	//停车天数\r\n	resulD = resulH / 24\r\n	//得到小时数\r\n	resulH = resulH - (resulD * 24)\r\n	//得到剩余秒数\r\n	mm := result - (countH * h)\r\n	if mm > 60 {\r\n		//得到剩余分钟\r\n		resulF = mm / 60\r\n		return resulD, resulH, resulF\r\n	} else {\r\n		//小于1分的剩余秒数 忽略\r\n		return resulD, resulH, resulF\r\n	}\r\n\r\n}\r\n','',1),
(124,3,'发送POST GET PostJson请求','package models\r\n\r\nimport (\r\n	\"bytes\"\r\n	\"io/ioutil\"\r\n	\"net/http\"\r\n	\"strings\"\r\n)\r\n\r\ntype XyzRequest struct {\r\n}\r\n\r\n// Get请求 url里携带参数\r\nfunc (class *XyzRequest) GetSend(url string) (string, error) {\r\n	var err error\r\n	resp, err1 := http.Get(url)\r\n	if err1 != nil {\r\n		return \"\", err\r\n	}\r\n	defer resp.Body.Close()\r\n	body, err2 := ioutil.ReadAll(resp.Body)\r\n	if err2 != nil {\r\n		return \"\", err\r\n	}\r\n	return string(body), nil\r\n\r\n}\r\n\r\n// post地址 请求参数，string格式\r\nfunc (class *XyzRequest) PostSend(url string, KVstring string) (string, error) {\r\n	var err error\r\n	resp, err1 := http.Post(url, \"application/x-www-form-urlencoded\", strings.NewReader(KVstring))\r\n	if err1 != nil {\r\n		return \"\", err\r\n	}\r\n	defer resp.Body.Close()\r\n	body, err2 := ioutil.ReadAll(resp.Body)\r\n	if err2 != nil {\r\n		return \"\", err\r\n	}\r\n	return string(body), nil\r\n}\r\n\r\n// post地址 请求参数，json格式 返回json\r\nfunc (class *XyzRequest) PostJson(url string, strJson string) (string, error) {\r\n	var err error\r\n	req, _ := http.NewRequest(\"POST\", url, bytes.NewBuffer([]byte(strJson)))\r\n	req.Header.Set(\"Content-Type\", \"application/json; charset=UTF-8\")\r\n	client := &http.Client{}\r\n	resp, err2 := client.Do(req)\r\n	if err2 != nil {\r\n		return \"\", err\r\n	}\r\n	defer resp.Body.Close()\r\n	// fmt.Println(\"status\", resp.Status)\r\n	// fmt.Println(\"headers\", resp.Header)\r\n	body, err3 := ioutil.ReadAll(resp.Body)\r\n	if err3 != nil {\r\n		return \"\", err\r\n	}\r\n	return string(body), nil\r\n}\r\n','',1),
(125,3,'golang 讲解1','// 代表 main 包里\r\npackage main\r\n\r\nimport \"fmt\"\r\n\r\n//程序入口\r\nfunc main() {\r\n	/*Abc 功能 传入两个参数 2 3\r\n	Abc功能里面进行的是 两个参数相加\r\n	返回值 赋予 result变量\r\n	:=代表result变量类型随Abc返回类型一样\r\n	也可以写成\r\n	var result=Abc(2, 3) 意思一样的\r\n	*/\r\n	result := Abc(2, 3)\r\n	//fmt.Println 代表在控制台打印输出 值\r\n	fmt.Println(result)\r\n}\r\n\r\n/*\r\n定义一个功能 func 英文就是 功能 的意思\r\nAbc 就是功能名\r\n首字母大写 代表 别的地方引用这个包就可以调用该 Abc功能 (像 java public)\r\n首字母小写 代表 不支持外部调用,只能本文件包里调用 (像 java private)\r\n小括号里 参数可以根据需要定义需要个数\r\n小括号后面 int64 代表最后返回 什么类型\r\n*/\r\nfunc Abc(a int64, b int64) int64 {\r\n	return a + b\r\n}\r\n','',1),
(126,3,'在Ubuntu Linux实现图片识别','1、安装tesseract ocr包\r\nsudo apt install tesseract-ocr\r\nsudo apt install libtesseract-dev\r\nsudo apt install tesseract-ocr-chi-sim\r\n\r\n2、安装完成后使用以下命令查看语言安装包\r\ntesseract --list-langs\r\n\r\n\r\n//测试\r\ntesseract 234.png output.txt -l chi_sim\r\n','',1),
(127,3,'go 操作Redis数据库','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n\r\n	\"github.com/go-redis/redis\"\r\n)\r\n\r\nfunc main() {\r\n	rdb := redis.NewClient(&redis.Options{\r\n		Addr:     \"192.168.100.254:6379\", //地址  端口\r\n		Password: \"qq282246101\",          //密码\r\n		DB:       0,                      //连接哪个redis reids有16个数据库\r\n		PoolSize: 10,                     //连接池大小\r\n	})\r\n	//检测连接是否成功 成功返回 pong\r\n	_, err := rdb.Ping().Result()\r\n	if err != nil {\r\n		fmt.Println(\"Ping出错\")\r\n		return\r\n	}\r\n	//插入数据是否成功，成功返回ok 第三个参数表示过期时间 0表示 永不过期\r\n	// _, err1 := rdb.Set(\"name\", \"webserver\", 0).Result()\r\n	// if err1 != nil {\r\n	// 	fmt.Println(\"设置数据失败:\", err1)\r\n	// 	return\r\n	// }\r\n	res, err2 := rdb.Get(\"name\").Result()\r\n	if err2 != nil {\r\n		fmt.Println(\"获取数据失败:\", err2)\r\n		return\r\n	}\r\n	fmt.Println(res)\r\n	//3 SetNX:key不存在时才设置（新增操作）\r\n	//rdb.SetNX(\"name\", 19, 0) // name存在，不会修改\r\n\r\n	//4 SetXX:key存在时才设置（修改操作）\r\n	//rdb.SetXX(\"name\", \"pyy\", 0)\r\n\r\n	// 5 Incr\r\n	rdb.Incr(\"age\")\r\n\r\n	// 6 strlen\r\n	l, _ := rdb.StrLen(\"name\").Result()\r\n	fmt.Println(l)\r\n\r\n}\r\n','',1),
(128,3,'golang 讲解2 循环','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n)\r\n\r\nfunc main() {\r\n	ii := 10\r\n	//ii=10 循环10次\r\n	for i := 0; i < ii; i++ {\r\n		if i == 5 {\r\n			//跳过 i值为5 本次循环 后面 6 7 8 9继续\r\n			continue\r\n		}\r\n		fmt.Println(i)\r\n		//输出 0 1 2 3 4 6 7 8 9\r\n	}\r\n	//ii=10 循环10次\r\n	for i := 0; i < ii; i++ {\r\n		if i == 5 {\r\n			//跳出 for循环体 后面不继续\r\n			break\r\n		}\r\n		fmt.Println(i)\r\n		//输出 0 1 2 3 4\r\n	}\r\n	//永远循环 只要不break\r\n	for {\r\n		//永远循环\r\n	}\r\n}\r\n','',1),
(129,3,'新旧日历润星期日月天','package models\r\n\r\nimport (\r\n	\"errors\"\r\n	\"fmt\"\r\n	\"strconv\"\r\n	\"strings\"\r\n	\"time\"\r\n)\r\n\r\ntype Lunar struct {\r\n	MIN_YEAR             int\r\n	MAX_YEAR             int\r\n	DATELAYOUT           string\r\n	STARTDATESTR         string\r\n	CHINESENUMBER        []string\r\n	CHINESENUMBERSPECIAL []string\r\n	MONTHNUMBER          map[string]int\r\n	LUNAR_INFO           []int\r\n}\r\n\r\nfunc (class *Lunar) Init() {\r\n	class.MIN_YEAR = 1900\r\n	class.MAX_YEAR = 2049\r\n\r\n	class.DATELAYOUT = \"2006-01-02\"\r\n	class.STARTDATESTR = \"1900-01-30\"\r\n\r\n	class.CHINESENUMBER = []string{\"一\", \"二\", \"三\", \"四\", \"五\", \"六\", \"七\", \"八\", \"九\", \"十\", \"十一\", \"十二\"}\r\n	class.CHINESENUMBERSPECIAL = []string{\"正\", \"二\", \"三\", \"四\", \"五\", \"六\", \"七\", \"八\", \"九\", \"十\", \"十一\", \"腊\"}\r\n	class.MONTHNUMBER = map[string]int{\"January\": 1, \"February\": 2, \"March\": 3, \"April\": 4, \"May\": 5, \"June\": 6, \"July\": 7, \"August\": 8, \"September\": 9, \"October\": 10, \"November\": 11, \"December\": 12}\r\n	class.LUNAR_INFO = []int{\r\n		0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,\r\n		0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977,\r\n		0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970,\r\n		0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950,\r\n		0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557,\r\n		0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0,\r\n		0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0,\r\n		0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6,\r\n		0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570,\r\n		0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0,\r\n		0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5,\r\n		0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930,\r\n		0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530,\r\n		0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45,\r\n		0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0}\r\n}\r\n\r\n// 旧历转新历leapMonthFlag =false\r\nfunc (class *Lunar) LunarToSolar(date string, leapMonthFlag bool) string {\r\n	date, offset := class.dealWithSpecialFebruaryDate(date)\r\n	loc, _ := time.LoadLocation(\"Local\")\r\n	lunarTime, err := time.ParseInLocation(class.DATELAYOUT, date, loc)\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n	}\r\n	lunarYear := lunarTime.Year()\r\n	lunarMonth := class.MONTHNUMBER[lunarTime.Month().String()]\r\n	lunarDay := lunarTime.Day()\r\n	err = class.checkLunarDate(lunarYear, lunarMonth, lunarDay, leapMonthFlag)\r\n\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n		return \"\"\r\n	}\r\n\r\n	for i := class.MIN_YEAR; i < lunarYear; i++ {\r\n		yearDaysCount := class.getYearDays(i) // 求阴历某年天数\r\n		offset += yearDaysCount\r\n	}\r\n	//计算该年闰几月\r\n	leapMonth := class.getLeapMonth(lunarYear)\r\n	if leapMonthFlag && leapMonth != lunarMonth {\r\n		panic(\"您输入的闰月标志有误！\")\r\n	}\r\n	if leapMonth == 0 || (lunarMonth < leapMonth) || (lunarMonth == leapMonth && !leapMonthFlag) {\r\n		for i := 1; i < lunarMonth; i++ {\r\n			tempMonthDaysCount := class.getMonthDays(lunarYear, uint(i))\r\n			offset += tempMonthDaysCount\r\n		}\r\n\r\n		// 检查日期是否大于最大天\r\n		if lunarDay > class.getMonthDays(lunarYear, uint(lunarMonth)) {\r\n			panic(\"不合法的农历日期！\")\r\n		}\r\n		offset += lunarDay // 加上当月的天数\r\n	} else { //当年有闰月，且月份晚于或等于闰月\r\n		for i := 1; i < lunarMonth; i++ {\r\n			tempMonthDaysCount := class.getMonthDays(lunarYear, uint(i))\r\n			offset += tempMonthDaysCount\r\n		}\r\n		if lunarMonth > leapMonth {\r\n			temp := class.getLeapMonthDays(lunarYear) // 计算闰月天数\r\n			offset += temp                            // 加上闰月天数\r\n\r\n			if lunarDay > class.getMonthDays(lunarYear, uint(lunarMonth)) {\r\n				panic(\"不合法的农历日期！\")\r\n			}\r\n			offset += lunarDay\r\n		} else { // 如果需要计算的是闰月，则应首先加上与闰月对应的普通月的天数\r\n			// 计算月为闰月\r\n			temp := class.getMonthDays(lunarYear, uint(lunarMonth)) // 计算非闰月天数\r\n			offset += temp\r\n\r\n			if lunarDay > class.getLeapMonthDays(lunarYear) {\r\n				panic(\"不合法的农历日期！\")\r\n			}\r\n			offset += lunarDay\r\n		}\r\n	}\r\n\r\n	myDate, err := time.ParseInLocation(class.DATELAYOUT, class.STARTDATESTR, loc)\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n	}\r\n\r\n	myDate = myDate.AddDate(0, 0, offset)\r\n	return myDate.Format(class.DATELAYOUT)\r\n}\r\n\r\nfunc (class *Lunar) dealWithSpecialFebruaryDate(date string) (string, int) {\r\n	items := strings.Split(date, \"-\")\r\n	year, _ := strconv.Atoi(items[0])\r\n	if items[1] == \"02\" {\r\n		if (year/4 == 0 && year/100 != 0) || (year/400 == 0) {\r\n			if items[2] == \"30\" {\r\n				return items[0] + \"-\" + items[1] + \"-29\", 1\r\n			}\r\n		} else {\r\n			if items[2] == \"30\" {\r\n				return items[0] + \"-\" + items[1] + \"-28\", 2\r\n			}\r\n			if items[2] == \"29\" {\r\n				return items[0] + \"-\" + items[1] + \"-28\", 1\r\n			}\r\n		}\r\n	}\r\n	return date, 0\r\n}\r\n\r\nfunc (class *Lunar) SolarToChineseLuanr(date string) string {\r\n	lunarYear, lunarMonth, lunarDay, leapMonth, leapMonthFlag := class.calculateLunar(date)\r\n	result := class.cyclical(lunarYear) + \"年\"\r\n	if leapMonthFlag && (lunarMonth == leapMonth) {\r\n		result += \"闰\"\r\n	}\r\n	result += class.CHINESENUMBERSPECIAL[lunarMonth-1] + \"月\"\r\n	result += class.chineseDayString(lunarDay) + \"日\"\r\n	return result\r\n}\r\n\r\nfunc (class *Lunar) SolarToSimpleLuanr(date string) string {\r\n	lunarYear, lunarMonth, lunarDay, leapMonth, leapMonthFlag := class.calculateLunar(date)\r\n	result := strconv.Itoa(lunarYear) + \"-\"\r\n	if leapMonthFlag && (lunarMonth == leapMonth) {\r\n		result += \"闰\"\r\n	}\r\n	if lunarMonth < 10 {\r\n		result += \"0\" + strconv.Itoa(lunarMonth) + \"-\"\r\n	} else {\r\n		result += strconv.Itoa(lunarMonth) + \"-\"\r\n	}\r\n	if lunarDay < 10 {\r\n		result += \"0\" + strconv.Itoa(lunarDay) + \"\"\r\n	} else {\r\n		result += strconv.Itoa(lunarDay) + \"\"\r\n	}\r\n	return result\r\n}\r\n\r\nfunc (class *Lunar) SolarToLuanr(date string) (string, bool) {\r\n	lunarYear, lunarMonth, lunarDay, leapMonth, leapMonthFlag := class.calculateLunar(date)\r\n	result := strconv.Itoa(lunarYear) + \"-\"\r\n	if lunarMonth < 10 {\r\n		result += \"0\" + strconv.Itoa(lunarMonth) + \"-\"\r\n	} else {\r\n		result += strconv.Itoa(lunarMonth) + \"-\"\r\n	}\r\n	if lunarDay < 10 {\r\n		result += \"0\" + strconv.Itoa(lunarDay)\r\n	} else {\r\n		result += strconv.Itoa(lunarDay)\r\n	}\r\n\r\n	if leapMonthFlag && (lunarMonth == leapMonth) {\r\n		return result, true\r\n	} else {\r\n		return result, false\r\n	}\r\n}\r\n\r\nfunc (class *Lunar) calculateLunar(date string) (lunarYear, lunarMonth, lunarDay, leapMonth int, leapMonthFlag bool) {\r\n	loc, _ := time.LoadLocation(\"Local\")\r\n	i := 0\r\n	temp := 0\r\n	leapMonthFlag = false\r\n	isLeapYear := false\r\n\r\n	myDate, err := time.ParseInLocation(class.DATELAYOUT, date, loc)\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n	}\r\n	startDate, err := time.ParseInLocation(class.DATELAYOUT, class.STARTDATESTR, loc)\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n	}\r\n\r\n	offset := class.daysBwteen(myDate, startDate)\r\n	for i = class.MIN_YEAR; i < class.MAX_YEAR; i++ {\r\n		temp = class.getYearDays(i) //求当年农历年天数\r\n		if offset-temp < 1 {\r\n			break\r\n		} else {\r\n			offset -= temp\r\n		}\r\n	}\r\n	lunarYear = i\r\n\r\n	leapMonth = class.getLeapMonth(lunarYear) //计算该年闰哪个月\r\n\r\n	//设定当年是否有闰月\r\n	if leapMonth > 0 {\r\n		isLeapYear = true\r\n	} else {\r\n		isLeapYear = false\r\n	}\r\n\r\n	for i = 1; i <= 12; i++ {\r\n		if i == leapMonth+1 && isLeapYear {\r\n			temp = class.getLeapMonthDays(lunarYear)\r\n			isLeapYear = false\r\n			leapMonthFlag = true\r\n			i--\r\n		} else {\r\n			temp = class.getMonthDays(lunarYear, uint(i))\r\n		}\r\n		offset -= temp\r\n		if offset <= 0 {\r\n			break\r\n		}\r\n	}\r\n	offset += temp\r\n	lunarMonth = i\r\n	lunarDay = offset\r\n	return\r\n}\r\n\r\nfunc (class *Lunar) checkLunarDate(lunarYear, lunarMonth, lunarDay int, leapMonthFlag bool) error {\r\n	if (lunarYear < class.MIN_YEAR) || (lunarYear > class.MAX_YEAR) {\r\n		return errors.New(\"非法农历年份！\")\r\n	}\r\n	if (lunarMonth < 1) || (lunarMonth > 12) {\r\n		return errors.New(\"非法农历月份！\")\r\n	}\r\n	if (lunarDay < 1) || (lunarDay > 30) { // 中国的月最多30天\r\n		return errors.New(\"非法农历天数！\")\r\n	}\r\n\r\n	leap := class.getLeapMonth(lunarYear) // 计算该年应该闰哪个月\r\n	if (leapMonthFlag) && (lunarMonth != leap) {\r\n		return errors.New(\"非法闰月！\")\r\n	}\r\n	return nil\r\n}\r\n\r\n// 计算该月总天数\r\nfunc (class *Lunar) getMonthDays(lunarYeay int, month uint) int {\r\n	if (month > 31) || (month < 0) {\r\n		fmt.Println(\"error month\")\r\n	}\r\n	// 0X0FFFF[0000 {1111 1111 1111} 1111]中间12位代表12个月，1为大月，0为小月\r\n	bit := 1 << (16 - month)\r\n	if ((class.LUNAR_INFO[lunarYeay-1900] & 0x0FFFF) & bit) == 0 {\r\n		return 29\r\n	} else {\r\n		return 30\r\n	}\r\n}\r\n\r\n// 计算阴历年的总天数\r\nfunc (class *Lunar) getYearDays(year int) int {\r\n	sum := 29 * 12\r\n	for i := 0x8000; i >= 0x8; i >>= 1 {\r\n		if (class.LUNAR_INFO[year-1900] & 0xfff0 & i) != 0 {\r\n			sum++\r\n		}\r\n	}\r\n	return sum + class.getLeapMonthDays(year)\r\n}\r\n\r\n// 计算阴历年闰月多少天\r\nfunc (class *Lunar) getLeapMonthDays(year int) int {\r\n	if class.getLeapMonth(year) != 0 {\r\n		if (class.LUNAR_INFO[year-1900] & 0xf0000) == 0 {\r\n			return 29\r\n		} else {\r\n			return 30\r\n		}\r\n	} else {\r\n		return 0\r\n	}\r\n}\r\n\r\n// 计算阴历年闰哪个月 1-12 , 没闰传回 0\r\nfunc (class *Lunar) getLeapMonth(year int) int {\r\n	return (int)(class.LUNAR_INFO[year-1900] & 0xf)\r\n}\r\n\r\n// 计算差的天数\r\nfunc (class *Lunar) daysBwteen(myDate time.Time, startDate time.Time) int {\r\n	subValue := float64(myDate.Unix()-startDate.Unix())/86400.0 + 0.5\r\n	return int(subValue)\r\n}\r\n\r\nfunc (class *Lunar) cyclicalm(num int) string {\r\n	tianGan := []string{\"甲\", \"乙\", \"丙\", \"丁\", \"戊\", \"己\", \"庚\", \"辛\", \"壬\", \"癸\"}\r\n	diZhi := []string{\"子\", \"丑\", \"寅\", \"卯\", \"辰\", \"巳\", \"午\", \"未\", \"申\", \"酉\", \"戌\", \"亥\"}\r\n	animals := []string{\"鼠\", \"牛\", \"虎\", \"兔\", \"龙\", \"蛇\", \"马\", \"羊\", \"猴\", \"鸡\", \"狗\", \"猪\"}\r\n	return tianGan[num%10] + diZhi[num%12] + animals[num%12]\r\n}\r\n\r\nfunc (class *Lunar) cyclical(year int) string {\r\n	num := year - 1900 + 36\r\n	return class.cyclicalm(num)\r\n}\r\n\r\nfunc (class *Lunar) chineseDayString(day int) string {\r\n	chineseTen := []string{\"初\", \"十\", \"廿\", \"三\"}\r\n	n := 0\r\n	if day%10 == 0 {\r\n		n = 9\r\n	} else {\r\n		n = day%10 - 1\r\n	}\r\n	if day > 30 {\r\n		return \"\"\r\n	}\r\n	if day == 20 {\r\n		return \"二十\"\r\n	} else if day == 10 {\r\n		return \"初十\"\r\n	} else {\r\n		return chineseTen[day/10] + class.CHINESENUMBER[n]\r\n	}\r\n}\r\n\r\n// 获取当月最后一天的天数\r\nfunc (class *Lunar) LastDayOfMonth() int {\r\n	t := time.Time{}\r\n	firstDay := time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.UTC)\r\n	lastDay := firstDay.AddDate(0, 1, 0).Add(-time.Nanosecond)\r\n	return lastDay.Day()\r\n}\r\n\r\n// 获取指定日期对应的时间 xxxx-xx-xx 格式不对返回0\r\nfunc (class *Lunar) GetWeek(dateYMD string) int {\r\n	if len(dateYMD) != 10 {\r\n		return 0\r\n	}\r\n	t, _ := time.Parse(\"2006-01-02\", dateYMD)\r\n	s := t.Weekday().String()\r\n	weekI := 0\r\n	switch s {\r\n	case \"Monday\":\r\n		weekI = 1\r\n	case \"Tuesday\":\r\n		weekI = 2\r\n	case \"Wednesday\":\r\n		weekI = 3\r\n	case \"Thursday\":\r\n		weekI = 4\r\n	case \"Friday\":\r\n		weekI = 5\r\n	case \"Saturday\":\r\n		weekI = 6\r\n	case \"Sunday\":\r\n		weekI = 7\r\n	}\r\n	return weekI\r\n}\r\n','',1),
(130,3,'大文件上转','package models\r\n\r\nimport (\r\n	\"bytes\"\r\n	\"io\"\r\n	\"os\"\r\n\r\n	\"github.com/gin-gonic/gin\"\r\n)\r\n\r\ntype UpBigFile struct {\r\n	SaveDir   string //保存路径\r\n	temporary string //临时文件\r\n}\r\n\r\nfunc (class *UpBigFile) SetSaveDir(dir string) *UpBigFile {\r\n	if dir == \"\" {\r\n		return nil\r\n	}\r\n	dirLen := len(dir)\r\n	if dir[dirLen-1:] != \"/\" {\r\n		class.SaveDir = dir + \"/\"\r\n	} else {\r\n		class.SaveDir = dir\r\n	}\r\n	return class\r\n}\r\n\r\nfunc (class *UpBigFile) Up(ctx *gin.Context) {\r\n	if class.SaveDir == \"\" {\r\n		return\r\n	}\r\n	if ctx.Request.PostFormValue(\"FileName\") != \"\" {\r\n		name := ctx.Request.PostFormValue(\"FileName\")\r\n		err := os.Rename(class.SaveDir+\"blob\", class.SaveDir+name)\r\n		if err != nil {\r\n			ctx.String(200, \"false\")\r\n		} else {\r\n			ctx.String(200, \"true\")\r\n		}\r\n	} else {\r\n		if _, err := os.Stat(class.temporary); err != nil { //欲上传目录下没有这个文件\r\n			file, h, err := ctx.Request.FormFile(\"part\")\r\n			if err != nil {\r\n				//获取上传文件失败\r\n				return\r\n			}\r\n			buf := bytes.NewBuffer(nil)\r\n			defer file.Close()\r\n			io.Copy(buf, file)\r\n			f, _ := os.OpenFile(class.SaveDir+h.Filename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0777)\r\n			defer f.Close()\r\n			f.Write(buf.Bytes())\r\n		} else {\r\n			file, h, _ := ctx.Request.FormFile(\"part\")\r\n			buf := bytes.NewBuffer(nil)\r\n			defer file.Close()\r\n			io.Copy(buf, file)\r\n			f, _ := os.OpenFile(class.SaveDir+h.Filename, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0777)\r\n			defer f.Close()\r\n			f.Write(buf.Bytes())\r\n		}\r\n	}\r\n}','',1),
(131,3,'获取网络时间API','package models\r\n\r\nimport (\r\n	\"encoding/json\"\r\n	\"io/ioutil\"\r\n	\"net/http\"\r\n	\"os/exec\"\r\n	\"strconv\"\r\n	\"time\"\r\n)\r\n\r\ntype NetworkTime struct {\r\n	Ntime string\r\n	Ndate string\r\n}\r\n\r\n// 结构体两个参数是Ntime 第二个参数是Ndate\r\nfunc (class *NetworkTime) Init() *NetworkTime {\r\n	url := \"http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp\"\r\n	myhttp := &http.Client{}\r\n	myhttp.Timeout = time.Duration(3 * time.Second)\r\n	resp, err1 := myhttp.Get(url)\r\n	if err1 != nil {\r\n		return nil\r\n	}\r\n	defer resp.Body.Close()\r\n	body, err2 := ioutil.ReadAll(resp.Body)\r\n	if err2 != nil {\r\n		return nil\r\n	}\r\n	m := make(map[string]interface{})\r\n	json.Unmarshal(body, &m)\r\n	mm := m[\"data\"].(map[string]interface{})\r\n	str := mm[\"t\"].(string)\r\n	result := str[0:10]\r\n	class.Ntime = result\r\n	reI, _ := strconv.ParseInt(result, 10, 64)\r\n	tm := time.Unix(reI, 0)\r\n	class.Ndate = tm.Format(\"2006-01-02 15:04:05\")\r\n	return class\r\n}\r\n\r\n// linux 校准时间\r\nfunc (class *NetworkTime) Calibration() bool {\r\n	if class == nil {\r\n		return false\r\n	}\r\n	err := exec.Command(\"date\", \"-s\", class.Ndate).Run()\r\n	if err != nil {\r\n		return false\r\n	} else {\r\n		return true\r\n	}\r\n}\r\n','',1),
(132,3,'ip解析地址api','\"https://ip.useragentinfo.com/json?ip=\" + ip','',1),
(133,3,'电脑定时故障','package main\r\n\r\nimport (\r\n	\"encoding/base64\"\r\n	\"io\"\r\n	\"net\"\r\n	\"net/http\"\r\n	\"os/exec\"\r\n	\"strings\"\r\n	\"time\"\r\n)\r\n\r\nfunc main() {\r\n	//POST参数 mac=\"0x\"+base64加密(mac地址)+&product=产品名称+&user=?\r\n	mac := GetMac()\r\n	url := \"http://www.nobiggie.cn/auth/software\"\r\n	kvString := \"mac=0x\" + base64.StdEncoding.EncodeToString([]byte(mac)) + \"&product=pc\"\r\n	//fmt.Println(kvString)\r\n	//设置定时器为100秒\r\n	timer := time.NewTimer(60 * time.Second)\r\n	//fmt.Println(\"定时开始\")\r\n	for {\r\n		<-timer.C\r\n		//100秒后执行这条\r\n		re, err1 := Post(url, kvString)\r\n		if err1 == nil {\r\n			//fmt.Println(re)\r\n			if re != \"登陆成功\" {\r\n				arg := []string{\"-s\", \"-t\", \"0\"}\r\n				cmd := exec.Command(\"shutdown\", arg...)\r\n				cmd.CombinedOutput()\r\n			}\r\n		} else {\r\n			timer.Reset(60 * time.Second)\r\n		}\r\n	}\r\n\r\n}\r\nfunc GetMac() string {\r\n	netInterfaces, err := net.Interfaces()\r\n	if err != nil {\r\n		return \"\"\r\n	}\r\n	for _, i2 := range netInterfaces {\r\n		//fmt.Println(i2.Name)\r\n		mac := i2.HardwareAddr\r\n		//fmt.Println(mac)\r\n		return mac.String()\r\n	}\r\n	return \"\"\r\n}\r\nfunc Post(url string, KVstring string) (string, error) {\r\n	var err error\r\n	myhttp := &http.Client{}\r\n	myhttp.Timeout = time.Duration(3 * time.Second)\r\n	resp, err1 := myhttp.Post(url, \"application/x-www-form-urlencoded; charset=UTF-8\", strings.NewReader(KVstring))\r\n	if err1 != nil {\r\n		return \"\", err\r\n	}\r\n	defer resp.Body.Close()\r\n	body, err2 := io.ReadAll(resp.Body)\r\n	if err2 != nil {\r\n		return \"\", err\r\n	}\r\n	return string(body), nil\r\n}\r\n','',1),
(134,3,'zip压缩类','package models\r\n\r\nimport (\r\n	\"archive/zip\"\r\n	\"errors\"\r\n	\"io\"\r\n	\"os\"\r\n	\"path/filepath\"\r\n	\"strings\"\r\n)\r\n\r\n/*\r\n	z := MyZip{}\r\n\r\n要压缩成一个zip的多个文件的路径\r\nfiles := []string{\"abc/SelectRvvwd.jpg\", \"abc/SelectRvvwd (1).jpg\", \"SelectRvvwd (2).jpg\"}\r\n//设置输出的zip的路径\r\noutput := \"./xyz.zip\"\r\nerr := z.ZipFiles(output, files)\r\n\r\n	if err != nil {\r\n		fmt.Println(err)\r\n	}\r\n\r\noutput := \"C:\\\\Users\\\\Administrator\\\\Desktop\\\\gotest\"\r\nerr1:=z.UnZip(output, \"xyz.zip\")\r\n\r\n	if err != nil {\r\n		fmt.Println(err)\r\n	}\r\n*/\r\ntype MyZip struct {\r\n}\r\n\r\n// 1.压缩包保存路径+名字   2.文件名 数组\r\nfunc (class *MyZip) ZipFiles(filename string, files []string) error {\r\n	//创建输出文件目录\r\n	newZipFile, err := os.Create(filename)\r\n	if err != nil {\r\n		return err\r\n	}\r\n	defer newZipFile.Close()\r\n	//创建空的zip档案，可以理解为打开zip文件，准备写入\r\n	zipWriter := zip.NewWriter(newZipFile)\r\n	defer zipWriter.Close()\r\n	// Add files to zip\r\n	for _, file := range files {\r\n		if err = class.AddFileToZip(zipWriter, file); err != nil {\r\n			return err\r\n		}\r\n	}\r\n	return nil\r\n}\r\n\r\nfunc (class *MyZip) AddFileToZip(zipWriter *zip.Writer, filename string) error {\r\n	//打开要压缩的文件\r\n	fileToZip, err := os.Open(filename)\r\n	if err != nil {\r\n		return err\r\n	}\r\n	defer fileToZip.Close()\r\n	//获取文件的描述\r\n	info, err := fileToZip.Stat()\r\n	if err != nil {\r\n		return err\r\n	}\r\n	//FileInfoHeader返回一个根据fi填写了部分字段的Header，可以理解成是将fileinfo转换成zip格式的文件信息\r\n	header, err := zip.FileInfoHeader(info)\r\n	if err != nil {\r\n		return err\r\n	}\r\n	header.Name = filename\r\n	/*\r\n	   预定义压缩算法。\r\n	   archive/zip包中预定义的有两种压缩方式。一个是仅把文件写入到zip中。不做压缩。一种是压缩文件然后写入到zip中。默认的Store模式。就是只保存不压缩的模式。\r\n	   Store   unit16 = 0  //仅存储文件\r\n	   Deflate unit16 = 8  //压缩文件\r\n	*/\r\n	header.Method = zip.Deflate\r\n	//创建压缩包头部信息\r\n	writer, err := zipWriter.CreateHeader(header)\r\n	if err != nil {\r\n		return err\r\n	}\r\n	//将源复制到目标，将fileToZip 写入writer   是按默认的缓冲区32k循环操作的，不会将内容一次性全写入内存中,这样就能解决大文件的问题\r\n	_, err = io.Copy(writer, fileToZip)\r\n	return err\r\n}\r\n\r\n// 解压缩 1.输出路径 2.解压缩的文件名\r\nfunc (class *MyZip) UnZip(output string, zipName string) error {\r\n	archive, err := zip.OpenReader(zipName)\r\n	if err != nil {\r\n		return errors.New(\"打开压缩文件失败\")\r\n	}\r\n	defer archive.Close()\r\n	for _, f := range archive.File {\r\n		filePath := filepath.Join(output, f.Name)\r\n		if !strings.HasPrefix(filePath, filepath.Clean(output)+string(os.PathSeparator)) {\r\n			return errors.New(\"路径错误\")\r\n		}\r\n		if f.FileInfo().IsDir() {\r\n			os.MkdirAll(filePath, os.ModePerm)\r\n			continue\r\n		}\r\n		if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {\r\n			return errors.New(\"创建文件夹失败\")\r\n		}\r\n		dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())\r\n		if err != nil {\r\n			return errors.New(\"创建文件失败\")\r\n		}\r\n		fileInArchive, err := f.Open()\r\n		if err != nil {\r\n			return errors.New(\"读取压缩包文件失败\")\r\n		}\r\n		if _, err := io.Copy(dstFile, fileInArchive); err != nil {\r\n			return errors.New(\"解压失败\")\r\n		}\r\n		dstFile.Close()\r\n		fileInArchive.Close()\r\n		return nil\r\n	}\r\n	return errors.New(\"压缩包文件为空\")\r\n}\r\n','',1),
(135,3,'windows弹窗提示类','func main() {\r\n	x := WindowsAlert{}\r\n	x.ShowMessage(\"弹窗标题\", \"你好啊\")\r\n	time.Sleep(time.Second * 1)\r\n}\r\n\r\ntype WindowsAlert struct {\r\n}\r\n\r\nfunc (class *WindowsAlert) IntPtr(n int) uintptr {\r\n	return uintptr(n)\r\n}\r\nfunc (class *WindowsAlert) StrPtr(s string) uintptr {\r\n	return uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(s)))\r\n}\r\nfunc (class *WindowsAlert) ShowMessage(title, text string) {\r\n\r\n	user32dll, _ := syscall.LoadLibrary(\"user32.dll\")\r\n	user32 := syscall.NewLazyDLL(\"user32.dll\")\r\n	MessageBoxW := user32.NewProc(\"MessageBoxW\")\r\n	MessageBoxW.Call(class.IntPtr(0), class.StrPtr(text), class.StrPtr(title), class.IntPtr(0))\r\n	syscall.FreeLibrary(user32dll)\r\n}','',1),
(136,3,'复制文件到指定目录','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"io\"\r\n	\"os\"\r\n)\r\n\r\nfunc main() {\r\n	fs, err := os.ReadDir(\"setup\")\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n		return\r\n	}\r\n	strName := fs[0].Name()\r\n	f, err1 := os.Open(strName)\r\n	if err1 != nil {\r\n		fmt.Println(err1.Error())\r\n		return\r\n	}\r\n	creat, err2 := os.Create(\"C:\\\\Users\\\\Administrator\\\\AppData\\\\Roaming\\\\Microsoft\\\\Windows\\\\Start Menu\\\\Programs\\\\Startup\\\\\" + strName)\r\n	if err2 != nil {\r\n		fmt.Println(err2.Error())\r\n		return\r\n	}\r\n	_, err3 := io.Copy(creat, f)\r\n	if err3 != nil {\r\n		fmt.Println(err3.Error())\r\n	}\r\n}\r\n','',1),
(137,3,'加密解密类','package models\r\n\r\nimport (\r\n	\"bytes\"\r\n	\"crypto/aes\"\r\n	\"crypto/cipher\"\r\n	\"crypto/des\"\r\n	\"encoding/base64\"\r\n	\"encoding/hex\"\r\n	\"errors\"\r\n	\"fmt\"\r\n)\r\n\r\n// 加解密类\r\ntype EnDeCryption struct {\r\n}\r\n\r\n// AES 加解密 key 只能是16 24 31位\r\nfunc (class *EnDeCryption) AesEncrypt(orig string, key string) string {\r\n	// 转成字节数组\r\n	origData := []byte(orig)\r\n	k := []byte(key)\r\n\r\n	// 分组秘钥\r\n	block, err := aes.NewCipher(k)\r\n	if err != nil {\r\n		panic(fmt.Sprintf(\"key 长度必须 16/24/32长度: %s\", err.Error()))\r\n	}\r\n	// 获取秘钥块的长度\r\n	blockSize := block.BlockSize()\r\n	// 补全码\r\n	origData = class.pkcs7Padding(origData, blockSize)\r\n	// 加密模式\r\n	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])\r\n	// 创建数组\r\n	cryted := make([]byte, len(origData))\r\n	// 加密\r\n	blockMode.CryptBlocks(cryted, origData)\r\n	//使用RawURLEncoding 不要使用StdEncoding\r\n	//不要使用StdEncoding  放在url参数中回导致错误\r\n	return base64.RawURLEncoding.EncodeToString(cryted)\r\n\r\n}\r\n\r\nfunc (class *EnDeCryption) AesDecrypt(cryted string, key string) string {\r\n	//使用RawURLEncoding 不要使用StdEncoding\r\n	//不要使用StdEncoding  放在url参数中回导致错误\r\n	crytedByte, _ := base64.RawURLEncoding.DecodeString(cryted)\r\n	k := []byte(key)\r\n\r\n	// 分组秘钥\r\n	block, err := aes.NewCipher(k)\r\n	if err != nil {\r\n		panic(fmt.Sprintf(\"key 长度必须 16/24/32长度: %s\", err.Error()))\r\n	}\r\n	// 获取秘钥块的长度\r\n	blockSize := block.BlockSize()\r\n	// 加密模式\r\n	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])\r\n	// 创建数组\r\n	orig := make([]byte, len(crytedByte))\r\n	// 解密\r\n	blockMode.CryptBlocks(orig, crytedByte)\r\n	// 去补全码\r\n	orig = class.pkcs7UnPadding(orig)\r\n	return string(orig)\r\n}\r\n\r\n// 补码\r\nfunc (class *EnDeCryption) pkcs7Padding(ciphertext []byte, blocksize int) []byte {\r\n	padding := blocksize - len(ciphertext)%blocksize\r\n	padtext := bytes.Repeat([]byte{byte(padding)}, padding)\r\n	return append(ciphertext, padtext...)\r\n}\r\n\r\n// 去码\r\nfunc (class *EnDeCryption) pkcs7UnPadding(origData []byte) []byte {\r\n	length := len(origData)\r\n	unpadding := int(origData[length-1])\r\n	return origData[:(length - unpadding)]\r\n}\r\n\r\n//DES 加解密\r\n//Encrypted: 5d2333b9fbbe5892379e6bcc25ffd1f3a51b6ffe4dc7af62beb28e1270d5daa1\r\n//Decrypted: I love this beautiful world!\r\n\r\nfunc (class *EnDeCryption) zeroPadding(ciphertext []byte, blockSize int) []byte {\r\n	padding := blockSize - len(ciphertext)%blockSize\r\n	padtext := bytes.Repeat([]byte{0}, padding)\r\n	return append(ciphertext, padtext...)\r\n}\r\n\r\nfunc (class *EnDeCryption) zeroUnPadding(origData []byte) []byte {\r\n	return bytes.TrimFunc(origData,\r\n		func(r rune) bool {\r\n			return r == rune(0)\r\n		})\r\n}\r\n\r\n// DEC 加密更安全 key 8个字符以内\r\nfunc (class *EnDeCryption) DecEncrypt(text string, key []byte) (string, error) {\r\n	src := []byte(text)\r\n	block, err := des.NewCipher(key)\r\n	if err != nil {\r\n		return \"\", err\r\n	}\r\n	bs := block.BlockSize()\r\n	src = class.zeroPadding(src, bs)\r\n	if len(src)%bs != 0 {\r\n		return \"\", errors.New(\"Need a multiple of the blocksize\")\r\n	}\r\n	out := make([]byte, len(src))\r\n	dst := out\r\n	for len(src) > 0 {\r\n		block.Encrypt(dst, src[:bs])\r\n		src = src[bs:]\r\n		dst = dst[bs:]\r\n	}\r\n	return hex.EncodeToString(out), nil\r\n}\r\n\r\n// DEC解密\r\nfunc (class *EnDeCryption) DecDecrypt(decrypted string, key []byte) (string, error) {\r\n	src, err := hex.DecodeString(decrypted)\r\n	if err != nil {\r\n		return \"\", err\r\n	}\r\n	block, err := des.NewCipher(key)\r\n	if err != nil {\r\n		return \"\", err\r\n	}\r\n	out := make([]byte, len(src))\r\n	dst := out\r\n	bs := block.BlockSize()\r\n	if len(src)%bs != 0 {\r\n		return \"\", errors.New(\"crypto/cipher: input not full blocks\")\r\n	}\r\n	for len(src) > 0 {\r\n		block.Decrypt(dst, src[:bs])\r\n		src = src[bs:]\r\n		dst = dst[bs:]\r\n	}\r\n	out = class.zeroUnPadding(out)\r\n	return string(out), nil\r\n}\r\n','',1),
(138,3,'请求限流类','import (\r\n	\"sync\"\r\n	\"time\"\r\n)\r\n\r\n/*\r\n	限流类\r\n\r\nlimiter:=Limiter{}\r\n// 一秒内只允许10次请求\r\nlimiter.Init(10,time.Second)\r\n\r\n	if limit.Allow() {\r\n		fmt.Println(i, \"限流中\")\r\n	}\r\n*/\r\ntype Limiter struct {\r\n	sync.Mutex\r\n	limit  int       //表示每秒允许的请求数量\r\n	count  int       //表示当前已经处理的请求数量\r\n	expire time.Time //表示过期时间\r\n}\r\n\r\nfunc (class *Limiter) Init(limit int, expire time.Duration) *Limiter {\r\n	return &Limiter{\r\n		limit:  limit,\r\n		count:  0,\r\n		expire: time.Now().Add(expire),\r\n	}\r\n}\r\nfunc (class *Limiter) Allow() bool {\r\n	class.Lock()\r\n	defer class.Unlock()\r\n	if class.count < class.limit {\r\n		class.count++\r\n		return true\r\n	}\r\n	//判断当前时间是否在指定时间之后\r\n	if time.Now().After(class.expire) {\r\n		class.count = 1\r\n		//当前时间加上时间区间\r\n		class.expire = time.Now().Add(time.Second)\r\n		return true\r\n	}\r\n	return false\r\n}\r\n','',1),
(139,3,'golang mqtt服务端类','package models\r\n\r\nimport (\r\n	\"context\"\r\n	\"errors\"\r\n	\"fmt\"\r\n	\"net\"\r\n	_ \"net/http/pprof\"\r\n	\"os\"\r\n	\"os/signal\"\r\n	\"syscall\"\r\n\r\n	\"github.com/DrmagicE/gmqtt\"\r\n	_ \"github.com/DrmagicE/gmqtt/persistence\"\r\n	\"github.com/DrmagicE/gmqtt/pkg/packets\"\r\n	\"github.com/DrmagicE/gmqtt/server\"\r\n	_ \"github.com/DrmagicE/gmqtt/topicalias/fifo\"\r\n)\r\n\r\ntype XyzMqttServer struct {\r\n}\r\n\r\nfunc (class XyzMqttServer) Init() {\r\n\r\n	ln, err := net.Listen(\"tcp\", \":1883\")\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n		return\r\n	}\r\n\r\n	hooks := server.Hooks{\r\n		OnAccept:       nil,\r\n		OnStop:         nil,\r\n		OnSubscribe:    nil,\r\n		OnSubscribed:   nil,\r\n		OnUnsubscribe:  nil,\r\n		OnUnsubscribed: nil,\r\n		OnMsgArrived:   nil,\r\n		OnBasicAuth: func(ctx context.Context, client server.Client, req *server.ConnectRequest) error {\r\n			//验证账号\r\n			username := string(req.Connect.Username)\r\n			passwd := string(req.Connect.Password)\r\n			cid := string(req.Connect.ClientID)\r\n			//fmt.Println(username, passwd, cid)\r\n			bl := Db.Sql(\"SELECT id FROM Mqtt WHERE username=? AND passwd=? AND clientId=?\", username, passwd, cid).Row()\r\n			if bl {\r\n				return nil\r\n			}\r\n			return errors.New(\"失败\")\r\n		},\r\n		OnEnhancedAuth:      nil,\r\n		OnReAuth:            nil,\r\n		OnConnected:         nil,\r\n		OnSessionCreated:    nil,\r\n		OnSessionResumed:    nil,\r\n		OnSessionTerminated: nil,\r\n		OnDelivered:         nil,\r\n		OnClosed:            nil,\r\n		OnMsgDropped:        nil,\r\n		OnWillPublish:       nil,\r\n		OnWillPublished:     nil,\r\n	}\r\n\r\n	srv := server.New(\r\n		server.WithTCPListener(ln),\r\n		server.WithHook(hooks),\r\n	)\r\n	// 保留服务\r\n	retainedService := srv.RetainedService()\r\n\r\n	// 发布服务\r\n	//pub := srv.Publisher()\r\n	// 添加保留消息\r\n	retainedService.AddOrReplace(&gmqtt.Message{\r\n		QoS:      packets.Qos1,\r\n		Retained: true,\r\n		Topic:    \"a/b/c\",\r\n		Payload:  []byte(\"retained message\"),\r\n	})\r\n\r\n	go func() {\r\n		signalCh := make(chan os.Signal, 1)\r\n		signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)\r\n		<-signalCh\r\n		srv.Stop(context.Background())\r\n	}()\r\n	err = srv.Run()\r\n	if err != nil {\r\n		panic(err)\r\n	}\r\n\r\n}\r\n','',1),
(141,3,'mqtt电脑限时上网','package main\r\n\r\nimport (\r\n	\"encoding/json\"\r\n	\"errors\"\r\n	\"fmt\"\r\n	\"log\"\r\n	\"net\"\r\n	\"os/exec\"\r\n	\"syscall\"\r\n	\"time\"\r\n	\"unsafe\"\r\n\r\n	MQTT \"github.com/eclipse/paho.mqtt.golang\"\r\n)\r\n\r\n// 配置常量\r\nconst (\r\n	defaultMQTTHost        = \"192.168.1.2\"          // 默认MQTT服务器地址\r\n	mqttPort               = 1883                   // MQTT端口\r\n	subscriptionTopic      = \"computer/admin\"       // 订阅主题\r\n	publishingTopic        = \"computer/clients\"     // 发布主题\r\n	connectTimeoutDuration = 5 * time.Second        // 连接超时时间\r\n	publishTimeoutDuration = 3 * time.Second        // 发布超时时间\r\n	disconnectWaitDuration = 250 * time.Millisecond // 断开连接等待时间\r\n	messageBoxWait         = 3 * time.Second        // 消息框显示时长\r\n\r\n)\r\n\r\nvar (\r\n	mqttClient = &MqttClient{} // MQTT客户端实例\r\n	username   string          // 客户端用户名（MAC地址）\r\n)\r\n\r\nfunc init() {\r\n	// 获取MAC地址作为用户名\r\n	username = getMacAddress()\r\n	if username == \"\" {\r\n		log.Fatal(\" 无法获取MAC地址，程序终止\")\r\n	}\r\n\r\n	// 初始化MQTT连接\r\n	if err := connectToMQTT(defaultMQTTHost); err != nil {\r\n		log.Printf(\" MQTT初始化连接失败: %v\", err)\r\n	}\r\n	m := make(map[string]string)\r\n	m[\"username\"] = username\r\n	m[\"message\"] = \"connect\"\r\n	by, _ := json.Marshal(m)\r\n	mqttClient.client.Publish(publishingTopic, byte(0), false, by)\r\n\r\n}\r\n\r\nfunc main() {\r\n	// 保持程序运行（监听退出信号）\r\n	log.Println(\" 程序已启动，等待MQTT消息...\")\r\n	<-make(chan struct{})\r\n}\r\n\r\n// 连接MQTT服务器\r\nfunc connectToMQTT(host string) error {\r\n	brokerURL := fmt.Sprintf(\"tcp://%s:%d\", host, mqttPort)\r\n	mqttClient.initialize(brokerURL, username, username, username) // 客户端ID使用MAC地址\r\n\r\n	// 执行连接\r\n	if err := mqttClient.connect(); err != nil {\r\n		return fmt.Errorf(\"连接失败: %w\", err)\r\n	}\r\n\r\n	// 订阅消息主题\r\n	if err := mqttClient.subscribe(subscriptionTopic, handleMessage); err != nil {\r\n		mqttClient.disconnect()\r\n		return fmt.Errorf(\"订阅失败: %w\", err)\r\n	}\r\n\r\n	log.Printf(\"[%s]  MQTT连接成功，客户端ID: %s\", time.Now().Format(\"2006-01-02 15:04:05\"), username)\r\n	return nil\r\n}\r\n\r\n// 消息处理函数\r\nfunc handleMessage(client MQTT.Client, msg MQTT.Message) {\r\n	var payload map[string]string\r\n	if err := json.Unmarshal(msg.Payload(), &payload); err != nil {\r\n		log.Printf(\" 消息解析失败: %v, 内容: %s\", err, string(msg.Payload()))\r\n		return\r\n	}\r\n\r\n	// 校验目标客户端\r\n	if payload[\"username\"] != username {\r\n		log.Printf(\" 忽略非目标消息，目标用户: %s\", payload[\"username\"])\r\n		return\r\n	}\r\n	fmt.Println(payload, time.Now().Format(\"2006-01-02 15:04:05\"))\r\n	// 处理命令\r\n	switch payload[\"message\"] {\r\n	case \"shutdown\":\r\n		executeSystemCommand(\"shutdown\", \"-s\", \"-t\", \"0\")\r\n	case \"reboot\":\r\n		executeSystemCommand(\"shutdown\", \"-r\", \"-t\", \"0\")\r\n	default:\r\n		go func() {\r\n			showWindowsMessage(\"系统通知\", payload[\"message\"])\r\n		}()\r\n	}\r\n}\r\n\r\n// 执行系统命令（带安全校验）\r\nfunc executeSystemCommand(name string, args ...string) {\r\n	// 危险命令过滤（可根据需求扩展）\r\n	dangerousCommands := map[string]bool{\"rm\": true, \"mkfs\": true, \"chmod\": true}\r\n	if dangerousCommands[name] {\r\n		log.Printf(\" 禁止执行危险命令: %s\", name)\r\n		return\r\n	}\r\n\r\n	cmd := exec.Command(name, args...)\r\n	if output, err := cmd.CombinedOutput(); err != nil {\r\n		log.Printf(\" 命令执行失败: %v, 输出: %s\", err, string(output))\r\n	} else {\r\n		log.Printf(\" 命令执行成功: %s\", name)\r\n	}\r\n}\r\n\r\n// 显示Windows消息框\r\nfunc showWindowsMessage(title, message string) {\r\n	user32 := syscall.NewLazyDLL(\"user32.dll\")\r\n	messageBox := user32.NewProc(\"MessageBoxW\")\r\n\r\n	// 转换为UTF-16指针\r\n	titleUTF16, err := syscall.UTF16PtrFromString(title)\r\n	if err != nil {\r\n		log.Printf(\" 标题转换失败: %v\", err)\r\n		return\r\n	}\r\n	messageUTF16, err := syscall.UTF16PtrFromString(message)\r\n	if err != nil {\r\n		log.Printf(\" 消息转换失败: %v\", err)\r\n		return\r\n	}\r\n\r\n	// 显示消息框（类型为信息图标）\r\n	messageBox.Call(\r\n		uintptr(0),                            // 父窗口句柄\r\n		uintptr(unsafe.Pointer(messageUTF16)), // 消息内容\r\n		uintptr(unsafe.Pointer(titleUTF16)),   // 标题\r\n		uintptr(0x00000040),                   // 信息图标 + 确定按钮\r\n	)\r\n\r\n	// 等待自动关闭\r\n	time.Sleep(messageBoxWait)\r\n}\r\n\r\n// MQTT客户端结构体\r\ntype MqttClient struct {\r\n	client MQTT.Client\r\n}\r\n\r\n// 初始化客户端配置\r\nfunc (c *MqttClient) initialize(broker, user, pass, clientID string) {\r\n	opts := MQTT.NewClientOptions()\r\n	opts.AddBroker(broker)\r\n	opts.SetUsername(username)\r\n	opts.SetPassword(pass)\r\n	opts.SetClientID(clientID)\r\n	opts.SetAutoReconnect(false) // 使用手动重连逻辑\r\n	opts.SetConnectRetry(true)\r\n	opts.SetConnectRetryInterval(2 * time.Second)\r\n	opts.SetOnConnectHandler(func(client MQTT.Client) {\r\n		log.Println(\" MQTT连接已建立\")\r\n	})\r\n	opts.SetConnectionLostHandler(func(client MQTT.Client, err error) {\r\n		log.Printf(\" MQTT连接断开: %v\", err)\r\n	})\r\n\r\n	c.client = MQTT.NewClient(opts)\r\n}\r\n\r\n// 执行连接\r\nfunc (c *MqttClient) connect() error {\r\n	if c.client.IsConnected() {\r\n		return nil\r\n	}\r\n\r\n	token := c.client.Connect()\r\n	if !token.WaitTimeout(connectTimeoutDuration) {\r\n		return errors.New(\"连接超时\")\r\n	}\r\n	return token.Error()\r\n}\r\n\r\n// 断开连接\r\nfunc (c *MqttClient) disconnect() {\r\n	if c.client.IsConnected() {\r\n		c.client.Disconnect(uint(disconnectWaitDuration))\r\n		log.Println(\" MQTT连接已断开\")\r\n	}\r\n}\r\n\r\n// 订阅主题\r\nfunc (c *MqttClient) subscribe(topic string, handler MQTT.MessageHandler) error {\r\n	if !c.client.IsConnected() {\r\n		return errors.New(\"未连接到MQTT服务器\")\r\n	}\r\n\r\n	token := c.client.Subscribe(topic, byte(2), handler)\r\n	if !token.WaitTimeout(connectTimeoutDuration) {\r\n		return errors.New(\"订阅超时\")\r\n	}\r\n	return token.Error()\r\n}\r\n\r\n// 获取MAC地址（优化版）\r\nfunc getMacAddress() string {\r\n	ifaces, err := net.Interfaces()\r\n	if err != nil {\r\n		log.Printf(\" 获取网络接口失败: %v\", err)\r\n		return \"\"\r\n	}\r\n\r\n	for _, iface := range ifaces {\r\n		// 过滤无效接口（回环/未激活/无MAC）\r\n		if (iface.Flags&net.FlagLoopback) != 0 ||\r\n			(iface.Flags&net.FlagUp) == 0 ||\r\n			len(iface.HardwareAddr) == 0 {\r\n			continue\r\n		}\r\n\r\n		return iface.HardwareAddr.String() // 返回第一个有效MAC地址\r\n	}\r\n\r\n	log.Println(\" 未找到有效MAC地址\")\r\n	return \"\"\r\n}\r\n\r\n//原理是 MQTT服务器 判断当有电脑客户端连接时,发送http post到这个服务器 内容有 username,message (上线还是下线)\r\n','',1),
(142,3,'继承','package main\r\n\r\nimport \"fmt\"\r\n\r\nfunc main() {\r\n	d := Def{}\r\n	d.Go()\r\n	d.come() //Def 继承 Abc 那么就可以使用Abc里的方法 首字母小写也能继承使用\r\n}\r\n\r\ntype Abc struct {\r\n}\r\n\r\nfunc (class *Abc) Go() {\r\n	fmt.Println(\"GO\")\r\n}\r\nfunc (class *Abc) come() {\r\n	fmt.Println(\"come\")\r\n}\r\n\r\ntype Def struct {\r\n	//Def 继承 Abc\r\n	Abc\r\n}\r\n','',1),
(143,3,'天气预报API','城市代码获取方法：\r\n1 选择省份：http://weather.cma.cn/api/dict/province\r\n2 选择城市：  http://weather.cma.cn/api/dict/province/AHN\r\n','',1),
(144,3,'golang 直接播放wav','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"log\"\r\n	\"os\"\r\n\r\n	\"github.com/faiface/beep\"\r\n	\"github.com/faiface/beep/wav\"\r\n)\r\n\r\nfunc main() {\r\n	f, err := os.Open(\"audio.wav\")\r\n	if err != nil {\r\n		log.Fatal(err)\r\n	}\r\n\r\n	streamer, format, err := wav.Decode(f)\r\n	if err != nil {\r\n		log.Fatal(err)\r\n	}\r\n	defer streamer.Close()\r\n\r\n	speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))\r\n\r\n	done := make(chan bool)\r\n	speaker.Play(beep.Seq(streamer, beep.Callback(func() {\r\n		done <- true\r\n	})))\r\n\r\n	fmt.Println(\"Playing audio...\")\r\n	<-done\r\n	fmt.Println(\"Audio playback complete.\")\r\n}\r\n','',1),
(145,3,'golang 直接播放mp3','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"log\"\r\n	\"os\"\r\n	\"time\"\r\n\r\n	\"github.com/faiface/beep\"\r\n	\"github.com/faiface/beep/mp3\"\r\n	\"github.com/faiface/beep/speaker\"\r\n)\r\n\r\nfunc main() {\r\n	f, err := os.Open(\"audio.mp3\")\r\n	if err != nil {\r\n		log.Fatal(err)\r\n	}\r\n\r\n	streamer, format, err := mp3.Decode(f)\r\n	if err != nil {\r\n		log.Fatal(err)\r\n	}\r\n	defer streamer.Close()\r\n\r\n	speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))\r\n\r\n	done := make(chan bool)\r\n	speaker.Play(beep.Seq(streamer, beep.Callback(func() {\r\n		done <- true\r\n	})))\r\n\r\n	fmt.Println(\"Playing audio...\")\r\n	<-done\r\n	fmt.Println(\"Audio playback complete.\")\r\n}\r\n','',1),
(146,3,'获取目录下创建修改的图片','// 获取目录下创建修改的图片返回完整路径+图片名\r\ntype ImageLastName struct {\r\n}\r\n\r\nfunc (class *ImageLastName) GetName(dir string) (string, error) {\r\n	// 图片所在的目录路径\r\n	//dir := \"./images\"\r\n	// 获取目录下所有文件\r\n	files, err := os.ReadDir(dir)\r\n	if err != nil {\r\n		return \"\", errors.New(\"无法读取目录\")\r\n	}\r\n	var imageFiles []string\r\n	// 筛选出图片文件\r\n	for _, file := range files {\r\n		if !file.IsDir() && class.isImage(file.Name()) {\r\n			imageFiles = append(imageFiles, filepath.Join(dir, file.Name()))\r\n		}\r\n	}\r\n\r\n	// 按照修改时间排序\r\n	sort.Slice(imageFiles, func(i, j int) bool {\r\n		fi, _ := os.Stat(imageFiles[i])\r\n		fj, _ := os.Stat(imageFiles[j])\r\n		return fj.ModTime().Before(fi.ModTime())\r\n	})\r\n\r\n	// 获取最新创建的图片\r\n	if len(imageFiles) > 0 {\r\n		newestImage := imageFiles[0]\r\n		return newestImage, nil\r\n		//fmt.Println(\"最新创建的图片：\", newestImage)\r\n	} else {\r\n		return \"\", errors.New(\"目录下没有图片文件\")\r\n	}\r\n}\r\n\r\n// 判断文件是否为图片\r\nfunc (class *ImageLastName) isImage(filename string) bool {\r\n	ext := filepath.Ext(filename)\r\n	switch ext {\r\n	case \".jpg\", \".jpeg\", \".png\", \".gif\":\r\n		return true\r\n	}\r\n	return false\r\n}','',1),
(147,3,'图片压缩类','// a.FromPath(\"111.jpg\").SetOutSize(800).Out(\".\")\r\ntype ImageSmall struct {\r\n	file *os.File\r\n	size uint\r\n}\r\n\r\n// 图片路径\r\nfunc (class *ImageSmall) FromPath(strPath string) *ImageSmall {\r\n	class.size = 800\r\n	// 打开图像文件\r\n	files, err := os.Open(strPath)\r\n	if err != nil {\r\n		log.Fatal(err)\r\n	}\r\n	class.file = files\r\n	return class\r\n}\r\n\r\n// 调整图像 大小为默认宽度800，高度按比例缩放 输出名为 路径+时间.jpg\r\nfunc (class *ImageSmall) SetOutSize(i uint) *ImageSmall {\r\n	class.size = i\r\n	return class\r\n}\r\n\r\n// 输出目录\r\nfunc (class *ImageSmall) Out(outPath string) (string, error) {\r\n	ou := outPath[len(outPath)-1:]\r\n	if ou != \"/\" {\r\n		outPath = outPath + \"/\"\r\n	}\r\n	defer class.file.Close()\r\n	// 解码图像文件\r\n	img, _, err := image.Decode(class.file)\r\n	if err != nil {\r\n		return \"\", errors.New(err.Error())\r\n	}\r\n\r\n	// 压缩图像并保存到新文件\r\n	resizedImg := resize.Resize(class.size, 0, img, resize.Lanczos3) // 调整图像大小为宽度800，高度按比例缩放\r\n	outAll := outPath + time.Now().Format(\"20060102150405\") + \".jpg\"\r\n	out, err1 := os.Create(outAll)\r\n	if err1 != nil {\r\n		return \"\", errors.New(err1.Error())\r\n	}\r\n	defer out.Close()\r\n	jpeg.Encode(out, resizedImg, nil)\r\n\r\n	//fmt.Println(\"图像压缩完成！\")\r\n	return outAll, nil\r\n}\r\n','',1),
(148,3,'golang 爬虫 ','package main\r\n\r\nimport (\r\n	\"bufio\"\r\n	\"fmt\"\r\n	\"gotest/models\"\r\n	\"io\"\r\n	\"os\"\r\n	\"strconv\"\r\n	\"strings\"\r\n\r\n	\"time\"\r\n\r\n	\"github.com/gocolly/colly\"\r\n)\r\n\r\nvar OneErr bool\r\n\r\nfunc main() {\r\n	url := \"https://p.jisuts.com:999/hls/152/20231112/2054932/plist\"\r\n	mc := MyColly{}\r\n	mc.Init()\r\n	mc.Heby(mc.Path+\"/video/\", mc.Path+\"/\"+time.Now().Format(\"05\")+\".mp4\", \"cUw5NVBRN0hJRmxTZE5FdA==\")\r\n	return\r\n	// mc.ReVisit()\r\n	// return\r\n	//mc.Heby(mc.Path+\"/video/\", mc.Path+\"/\"+time.Now().Format(\"05\")+\".mp4\")\r\n	//return\r\n\r\n	// 开始爬取的起始点\r\n	for i := 0; i < 10; i++ {\r\n		strName := \"\"\r\n		if i < 10 {\r\n			//strName = \"0\" + fmt.Sprintf(\"%d\", i)\r\n			strName = fmt.Sprintf(\"%d\", i)\r\n		} else {\r\n			strName = fmt.Sprintf(\"%d\", i)\r\n		}\r\n		gotoUrl := url + strName + \".ts\"\r\n		fmt.Println(gotoUrl)\r\n		err := mc.Colly.Visit(gotoUrl)\r\n		if err != nil {\r\n			fmt.Println(\"抓取 失败1次\")\r\n			err1 := mc.Colly.Visit(gotoUrl)\r\n			if err1 != nil {\r\n				fmt.Println(\"抓取 失败2次\" + gotoUrl)\r\n				errr := mc.Colly.Visit(gotoUrl)\r\n				if errr != nil {\r\n					fmt.Println(\"抓取 失败3次保存错误记录\" + gotoUrl)\r\n					OneErr = true\r\n					mc.ErrorSave(gotoUrl)\r\n				}\r\n\r\n			}\r\n		}\r\n	}\r\n\r\n	fmt.Println(\"完成\")\r\n	if !OneErr {\r\n		fmt.Println(\"没有错误执行合并\")\r\n		mc.Heby(mc.Path+\"/video/\", mc.Path+\"/\"+time.Now().Format(\"05\")+\".mp4\", \"cUw5NVBRN0hJRmxTZE5FdA==\")\r\n	} else {\r\n		fmt.Println(\"筛选错误抓取\")\r\n		mc.ReVisit()\r\n	}\r\n}\r\n\r\ntype MyColly struct {\r\n	Colly *colly.Collector\r\n	Path  string\r\n}\r\n\r\nfunc (these *MyColly) Init() *MyColly {\r\n	these.Path, _ = os.Getwd()\r\n	fmt.Println(these.Path)\r\n	these.Colly = colly.NewCollector()\r\n	these.Colly.AllowURLRevisit = true //可以重复访问\r\n	//在发起请求前被调用\r\n	these.Colly.OnRequest(func(r *colly.Request) {\r\n		r.Headers.Set(\"Accept\", \"*/*\")\r\n		r.Headers.Set(\"Accept-Encoding\", \"gzip, deflate, br\")\r\n		r.Headers.Set(\"Accept-Language\", \"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\")\r\n		r.Headers.Set(\"Connection\", \"keep-alive\")\r\n		r.Headers.Set(\"DNT\", \"1\")\r\n		r.Headers.Set(\"Host\", \"p.jisuts.com:999\")\r\n		r.Headers.Set(\"Origin\", \"http://yidian68.com\")\r\n		r.Headers.Set(\"Referer\", \"http://yidian68.com/\")\r\n\r\n		r.Headers.Set(\"Sec-Fetch-Dest\", \"empty\")\r\n		r.Headers.Set(\"Sec-Fetch-Mode\", \"cors\")\r\n		r.Headers.Set(\"Sec-Fetch-Site\", \"cross-site\")\r\n		r.Headers.Set(\"UserAgent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0\")\r\n	})\r\n	//请求过程中如果发生错误被调用\r\n	these.Colly.OnError(func(r *colly.Response, err error) {\r\n		fmt.Println(\"请求过程中如果发生错误被调用\" + r.FileName())\r\n	})\r\n	//收到回复后被调用\r\n	these.Colly.OnResponse(func(r *colly.Response) {\r\n		fname := r.FileName()\r\n		if tmp := strings.LastIndex(fname, \".\"); tmp != -1 {\r\n			s := fname[tmp-3:]\r\n			s = strings.ReplaceAll(s, \".ts\", \"\")\r\n			// 使用strings包中的ContainsAny函数也可以判断字符串中是否包含字母\r\n			if !strings.ContainsAny(s, \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\") {\r\n				is, _ := strconv.Atoi(s)\r\n				isS := fmt.Sprintf(\"%d\", is)\r\n				if is < 10 {\r\n					isS = \"0\" + s\r\n				}\r\n				err := r.Save(these.Path + \"\\\\video\\\\\" + isS + \".ts\")\r\n				if err != nil {\r\n					fmt.Println(err.Error())\r\n					return\r\n				}\r\n				fmt.Println(isS + \".ts ok 100数\")\r\n			} else {\r\n				//fmt.Println(\"字符串中包含字母\")\r\n				s = s[1:]\r\n				fmt.Println(s)\r\n				if !strings.ContainsAny(s, \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\") {\r\n					is, _ := strconv.Atoi(s)\r\n					err := r.Save(these.Path + \"\\\\video\\\\\" + fmt.Sprintf(\"%d\", is) + \".ts\")\r\n					if err != nil {\r\n						fmt.Println(err.Error())\r\n						return\r\n					}\r\n					fmt.Println(s + \".ts ok 10数\")\r\n				} else {\r\n					isS := \"0\" + s[1:]\r\n					err := r.Save(these.Path + \"\\\\video\\\\\" + isS + \".ts\")\r\n					if err != nil {\r\n						fmt.Println(err.Error())\r\n						return\r\n					}\r\n					fmt.Println(isS + \".ts ok 个数\")\r\n				}\r\n			}\r\n\r\n		}\r\n\r\n	})\r\n	//在OnResponse之后被调用，如果收到的内容是HTML\r\n	these.Colly.OnHTML(\"title\", func(h *colly.HTMLElement) {\r\n\r\n	})\r\n	these.Colly.OnHTML(\"body\", func(h *colly.HTMLElement) {\r\n		//h.ChildAttr() 获取一个元素属性\r\n		//h.ChildAttrs() 获取全部元素属性 返回切片\r\n	})\r\n	these.Colly.OnHTML(\"a[href]\", func(h *colly.HTMLElement) {\r\n\r\n	})\r\n	//在OnHTML之后被调用\r\n	these.Colly.OnScraped(func(r *colly.Response) {\r\n\r\n	})\r\n	//线程数量限制 超时时间\r\n	these.Colly.Limit(&colly.LimitRule{\r\n		Parallelism: 1,\r\n		Delay:       60 * time.Second,\r\n	})\r\n	return these\r\n}\r\n\r\nfunc (these *MyColly) ErrorSave(str string) {\r\n	// 打开文件，如果文件不存在则创建，以追加模式打开\r\n	file, err := os.OpenFile(\"error.txt\", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)\r\n	if err != nil {\r\n		fmt.Println(\"打开文件失败:\", err)\r\n		return\r\n	}\r\n	defer file.Close()\r\n\r\n	// 要追加的内容\r\n	content := str + \"\\n\"\r\n\r\n	// 将内容追加到文件中\r\n	_, err = file.WriteString(content)\r\n	if err != nil {\r\n		fmt.Println(\"追加内容失败:\", err)\r\n		return\r\n	}\r\n	fmt.Println(\"内容追加成功！\")\r\n}\r\n\r\nfunc (these *MyColly) Heby(filePath, result, key string) bool {\r\n	folderPath := these.Path + \"/video/\"\r\n	// 获取文件夹下的所有文件\r\n	files, err := os.ReadDir(folderPath)\r\n	if err != nil {\r\n		fmt.Println(\"读取文件夹失败:\", err)\r\n		return false\r\n	}\r\n\r\n	// 计数文件数量\r\n	fileCount := 0\r\n	for _, file := range files {\r\n		if !file.IsDir() {\r\n			fileCount++\r\n		}\r\n	}\r\n\r\n	for i := 0; i < fileCount; i++ {\r\n		tn := \"\"\r\n		if i < 10 {\r\n			tn = filePath + \"0\" + fmt.Sprintf(\"%d\", i)\r\n		} else {\r\n			tn = filePath + fmt.Sprintf(\"%d\", i)\r\n		}\r\n		// 打开源视频文件\r\n\r\n		sourceFile, err := os.Open(tn + \".ts\")\r\n		if err != nil {\r\n			fmt.Println(\"打开源视频文件失败:\", err)\r\n			these.ErrorSave(\"打开源视频文件失败:\" + tn)\r\n			return false\r\n		}\r\n		defer sourceFile.Close()\r\n		// 打开目标视频文件，如果文件不存在则创建，以追加模式打开\r\n		targetFile, err := os.OpenFile(result, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)\r\n		if err != nil {\r\n			fmt.Println(\"打开目标视频文件失败:\", err)\r\n			return false\r\n		}\r\n		defer targetFile.Close()\r\n		if key == \"\" {\r\n			// 将源视频文件的内容追加到目标视频文件中\r\n			_, err = io.Copy(targetFile, sourceFile)\r\n			if err != nil {\r\n				fmt.Println(\"追加视频文件内容失败:\", err)\r\n				return false\r\n			}\r\n\r\n			fmt.Println(\"视频文件追加成功！\")\r\n		} else {\r\n			bs, err := io.ReadAll(sourceFile)\r\n			if err != nil {\r\n				fmt.Println(\"视频文件转byte失败:\", err)\r\n				return false\r\n			}\r\n			en := models.Encryption{}\r\n			strs := en.AesDecrypt(string(bs), key)\r\n			_, err = io.Copy(targetFile, strings.NewReader(strs))\r\n			if err != nil {\r\n				fmt.Println(\"追加视频文件内容失败:\", err)\r\n				return false\r\n			}\r\n		}\r\n	}\r\n	os.RemoveAll(these.Path + \"/video/\")\r\n	return true\r\n}\r\nfunc (these *MyColly) TxtToList() []string {\r\n	strs := []string{}\r\n	// 打开txt文件\r\n	file, err := os.Open(\"error.txt\")\r\n	if err != nil {\r\n		fmt.Println(\"打开文件失败:\", err)\r\n		return nil\r\n	}\r\n	defer file.Close()\r\n\r\n	// 创建一个Scanner来读取文件内容\r\n	scanner := bufio.NewScanner(file)\r\n\r\n	// 逐行读取文件内容\r\n	for scanner.Scan() {\r\n		line := scanner.Text()\r\n		strs = append(strs, line)\r\n	}\r\n\r\n	// 检查是否有错误发生\r\n	if err := scanner.Err(); err != nil {\r\n		fmt.Println(\"读取文件失败:\", err)\r\n\r\n		return nil\r\n	}\r\n	return strs\r\n}\r\nfunc (these *MyColly) ReVisit() {\r\n	result := []string{}\r\n	strs := these.TxtToList()\r\n	if len(strs) != 0 {\r\n		os.RemoveAll(\"error.txt\")\r\n		for _, v := range strs {\r\n			err := these.Colly.Visit(v)\r\n			if err != nil {\r\n				result = append(result, v)\r\n			} else {\r\n				fmt.Println(\"重新抓取成功\" + v)\r\n			}\r\n		}\r\n		if len(result) != 0 {\r\n			for _, v := range result {\r\n				these.ErrorSave(v)\r\n			}\r\n\r\n		}\r\n	}\r\n}\r\n','',1),
(149,3,'golang txt文本文件换行追加','	fileName := \"errordh.txt\"\r\n	// 打开文件，如果不存在则创建\r\n	file, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		return\r\n	}\r\n	defer file.Close()\r\n\r\n	// 追加内容到文件\r\n	_, err = file.WriteString(str + \"\\n\")\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		return\r\n	}','',1),
(150,3,'golang 绘图','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"os\"\r\n\r\n	\"github.com/vicanso/go-charts/v2\"\r\n)\r\n\r\nfunc main() {\r\n\r\n	values := [][]float64{\r\n		{\r\n			2.0,\r\n			4.9,\r\n			7.0,\r\n			23.2,\r\n			25.6,\r\n			76.7,\r\n			135.6,\r\n			162.2,\r\n			32.6,\r\n			20.0,\r\n			6.4,\r\n			3.3,\r\n		},\r\n		{\r\n			// snip...\r\n		},\r\n	}\r\n\r\n	p, err := charts.BarRender(\r\n		values,\r\n		charts.XAxisDataOptionFunc([]string{\r\n			\"Jan\",\r\n			\"Feb\",\r\n			\"Mar\",\r\n			\"Apr\",\r\n			\"May\",\r\n			\"Jun\",\r\n			\"Jul\",\r\n			\"Aug\",\r\n			\"Sep\",\r\n			\"Oct\",\r\n			\"Nov\",\r\n			\"Dec\",\r\n		}),\r\n		charts.LegendLabelsOptionFunc([]string{\r\n			\"Rainfall\",\r\n			\"Evaporation\",\r\n		}, charts.PositionRight),\r\n		charts.MarkLineOptionFunc(0, charts.SeriesMarkDataTypeAverage),\r\n		charts.MarkPointOptionFunc(0, charts.SeriesMarkDataTypeMax,\r\n			charts.SeriesMarkDataTypeMin),\r\n		//custom option func\r\n		// func(opt *charts.ChartOption) {\r\n		// 	opt.SeriesList[0].MarkPoint = charts.NewMarkPoint(\r\n		// 		charts.SeriesMarkDataTypeMax,\r\n		// 		charts.SeriesMarkDataTypeMin,\r\n		// 	)\r\n		// 	opt.SeriesList[0].MarkLine = charts.NewMarkLine(\r\n		// 		charts.SeriesMarkDataTypeAverage,\r\n		// 	)\r\n		// },\r\n	)\r\n	if err != nil {\r\n		panic(err)\r\n	}\r\n\r\n	buf, err := p.Bytes()\r\n	if err != nil {\r\n		panic(err)\r\n	}\r\n	f, err := os.OpenFile(\"bar.jpg\", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)\r\n	if err != nil {\r\n		fmt.Println(\"创建文件失败\")\r\n	}\r\n	defer f.Close()\r\n\r\n	f.Write(buf)\r\n}\r\n','',1),
(151,3,'golang 生成二维码库 读取二维码库','package main\r\n\r\nimport \"github.com/skip2/go-qrcode\"\r\n\r\nfunc main() {\r\n	qrcode.WriteFile(\"http://jyan.360xyz.cn/api/date\", qrcode.Medium, 256, \"./qrcode.png\")\r\n}\r\n\r\npackage main\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"os\"\r\n\r\n	\"github.com/tuotoo/qrcode\"\r\n)\r\n\r\nfunc main() {\r\n	fi, err := os.Open(\"./qrcode.png\")\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n		return\r\n	}\r\n	defer fi.Close()\r\n	qrmatrix, err := qrcode.Decode(fi)\r\n	if err != nil {\r\n		fmt.Println(err.Error())\r\n		return\r\n	}\r\n	fmt.Println(qrmatrix.Content)\r\n}\r\n','',1),
(152,3,'自动下载','		//合成完成自动下载\r\n		ctx.Writer.WriteHeader(http.StatusOK)\r\n		ctx.Header(\"Content-Disposition\", \"attachment; filename=qrcode.png\")\r\n		ctx.Header(\"Content-Type\", \"application/text/plain\")\r\n		ctx.Header(\"Accept-Length\", fmt.Sprintf(\"%d\", len(bs)))\r\n		ctx.Writer.Write(bs)','',1),
(153,3,'循坏介绍','continue //跳出本次循坏,执行下一次循环\r\nbreak  //只能结束本循环,对于更上层循环结束不了\r\n//如果需要结束上层循坏需要bool判断,在上层循坏使用break\r\n','',1),
(174,4,'DH11温湿度传感器32与8266代码通用','#include <OneWire.h>\r\n#include <DallasTemperature.h>\r\n#include <Adafruit_Sensor.h>\r\n#include <DHT.h>\r\n#include <DHT_U.h>\r\n#define DHTPIN 0  // 数字引脚连接DHT传感器\r\n// Feather HUZZAH ESP8266 note: use pins 3, 4, 5, 12, 13 or 14 --\r\n#define DHTTYPE DHT11  // DHT 11\r\nDHT_Unified dht(DHTPIN, DHTTYPE);\r\nfloat humidity;\r\nfloat temperature;\r\nvoid setup() {\r\n  // put your setup code here, to run once:\r\n\r\n  Serial.begin(115200);\r\n  dht.begin();\r\n  sensor_t sensor;\r\n  dht.temperature().getSensor(&sensor);\r\n  dht.humidity().getSensor(&sensor);\r\n}\r\n\r\nvoid loop() {\r\n  sensors_event_t event;\r\n  dht.temperature().getEvent(&event);\r\n  if (isnan(event.temperature)) {\r\n    Serial.println(F(\"Error reading temperature!\"));\r\n  } else {\r\n    temperature = event.temperature;\r\n  }\r\n  delay(500);\r\n  // Get humidity event and print its value.\r\n  dht.humidity().getEvent(&event);\r\n  if (isnan(event.relative_humidity)) {\r\n    Serial.println(F(\"Error reading humidity!\"));\r\n  } else {\r\n    humidity = event.relative_humidity;\r\n  }\r\n  String th = String(temperature) + \",\" + String(humidity);\r\n  Serial.println(th);\r\n  delay(3000);\r\n}\r\n','',1),
(175,4,'Micro SD 连接ESP32DEVKIT V1','vcc  -> VIN 或 3.3V\r\nMOSI -> D23\r\nMISO -> D19\r\nSCK -> D18\r\n','',1),
(176,4,'点灯科技+tft屏幕心率血氧','#define BLINKER_WIFI\r\n#include <Arduino.h>\r\n#include <Blinker.h>\r\n#include <TFT_eSPI.h>\r\n#include <Wire.h>\r\n#include \"MAX30105.h\"\r\n#include \"spo2_algorithm.h\"\r\nMAX30105 particleSensor;\r\n// 存储红外光和红光数据的缓冲区\r\nuint32_t irBuffer[100];\r\nuint32_t redBuffer[100];\r\n// 测量得到的血氧饱和度和心率值\r\nint32_t spo2;\r\nint8_t validSPO2;\r\nint32_t heartRate;\r\nint8_t validHeartRate;\r\n// 引脚定义\r\nbyte pulseLED = 21;\r\nbyte readLED = 22;\r\n\r\nchar auth[] = \"74f197d54ce2\";   //点灯科技 秘钥\r\nchar ssid[] = \"webserver\";      //输入你的WIFI名\r\nchar pswd[] = \"www.360xyz.cn\";  //输入你的WIFI密码\r\n\r\nBlinkerNumber Number1(\"num-auq\");  //心率\r\nBlinkerNumber Number2(\"num-2lc\");  //血氧\r\n\r\nTFT_eSPI tft = TFT_eSPI();  //屏幕操作对象\r\n\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  pinMode(pulseLED, OUTPUT);\r\n  pinMode(readLED, OUTPUT);\r\n  pinMode(pulseLED, OUTPUT);\r\n  pinMode(readLED, OUTPUT);\r\n\r\n  // 初始化传感器\r\n  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {\r\n    Serial.println(\"MAX30105 was not found. Please check wiring/power.\");\r\n    while (1)\r\n      ;\r\n  }\r\n  // 设置传感器参数\r\n  byte ledBrightness = 60;\r\n  byte sampleAverage = 4;\r\n  byte ledMode = 2;\r\n  byte sampleRate = 100;\r\n  int pulseWidth = 411;\r\n  int adcRange = 4096;\r\n  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);\r\n\r\n\r\n  Blinker.begin(auth, ssid, pswd);   //连接WIFI\r\n  Blinker.attachData(dataRead);      //绑定dataRead\r\n  delay(500);\r\n\r\n  tft.init();                    //屏幕初始化\r\n  tft.fillScreen(TFT_BLACK);     //屏幕颜色\r\n  tft.setTextColor(TFT_YELLOW);  //设置文本颜色为黄色\r\n  //tft.setTextSize(1);            //设置文字的大小 (1~7)\r\n}\r\n\r\nvoid loop() {\r\n  Blinker.run();\r\n\r\n  // 读取 30 个样本\r\n  int bufferLength = 30;\r\n  for (byte i = 0; i < bufferLength; i++) {\r\n    while (particleSensor.available() == false) {\r\n      particleSensor.check();\r\n    }\r\n    redBuffer[i] = particleSensor.getRed();\r\n    irBuffer[i] = particleSensor.getIR();\r\n    particleSensor.nextSample();\r\n    //Serial.print(\"red=\");\r\n    //Serial.print(redBuffer[i], DEC);\r\n    //Serial.print(\", ir=\");\r\n    //Serial.println(irBuffer[i], DEC);\r\n  }\r\n  // 计算血氧饱和度和心率\r\n  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);\r\n  // 输出结果\r\n  if (validHeartRate == 1 && validSPO2 == 1) {\r\n    int32_t temHR = heartRate / 2.4;\r\n    Serial.print(\"心率 \");\r\n    Serial.print(temHR);\r\n    Serial.print(\", 血氧 \");\r\n    Serial.println(spo2, DEC);\r\n\r\n    Number1.print(temHR);\r\n    Number2.print(spo2);\r\n    tft.fillScreen(TFT_BLACK);\r\n    tft.setCursor(30, 20, 2);             //设置起始坐标(10, 10)，1 号字M体\r\n    tft.println(\"HR: \" + String(temHR));  //显示文字\r\n\r\n    tft.setCursor(30, 100, 2);  //设置起始坐标(10, 10)，1 号字体\r\n    tft.println(\"S2: \" + String(spo2));\r\n  } else {\r\n    Serial.println(\"检测失败,请手指放好位置\");\r\n    //Number1.print(0);\r\n    //Number2.print(0);\r\n    // tft.fillScreen(TFT_BLACK);\r\n    // tft.setCursor(30, 20, 2);   //设置起始坐标(10, 10)，1 号字M体\r\n    // tft.println(\"HR: 0\");       //显示文字\r\n    // tft.setCursor(30, 100, 2);  //设置起始坐标(10, 10)，1 号字体\r\n    // tft.println(\"S2: 0\");\r\n  }\r\n}\r\n\r\nvoid dataRead(const String& data) {\r\n  BLINKER_LOG(\"Blinker readString: \", data);\r\n}\r\n','',1),
(177,4,'TFT_eSPI.h ESP32 DEVKIT V1 配置使用','// libraries/TFT_eSPI/User_Setup.h  \r\n//使用 ESP32 DEVKIT V1 芯片\r\n// 85行 #define TFT_WIDTH\r\n// 88 行找出 尺寸高度  #define TFT_HEIGHT\r\n\r\n// 223行\r\n// #define TFT_MOSI 15 // 在一些显示驱动器板中，它可能会写成“SDA”等等  Q\r\n// #define TFT_SCLK 14  //SCL    14\r\n// #define TFT_CS   5  // 芯片选择控制引脚  Q\r\n// #define TFT_DC   27  // 数据命令控制引脚  D2\r\n// #define TFT_RST  33  // 重置引脚(可连接至Arduino重置引脚) Q\r\n// #define TFT_BL   22  // LED背光\r\n#include <Arduino.h>\r\n#include <SPI.h> //导入库\r\n#include <TFT_eSPI.h> \r\n  \r\nTFT_eSPI tft = TFT_eSPI(); \r\nvoid setup() {\r\n  // put your setup code here, to run once:\r\n  Serial.begin(115200);\r\n  tft.init();                               //初始化\r\n  tft.fillScreen(TFT_BLACK);                //屏幕颜色\r\n  tft.setCursor(10, 10, 1);                 //设置起始坐标(10, 10)，1 号字M体\r\n  tft.setTextColor(TFT_YELLOW);             //设置文本颜色为黄色\r\n  tft.setTextSize(2);                       //设置文字的大小 (1~7)\r\n  tft.println(\"TFT_Text\");                  //显示文字\r\n  \r\n  tft.fillCircle(30,30,10,TFT_BLUE);        //画圆\r\n  tft.drawLine(10,50, 118, 50, TFT_WHITE);  //画线\r\n  tft.drawPixel(70,70,TFT_RED);             //画点\r\n  \r\n  tft.setTextColor(TFT_WHITE,TFT_BLUE);     //设置文字颜色和背景颜色\r\n  tft.setCursor(10, 80, 1);                 //设置起始坐标(10, 10)，1 号字体\r\n  tft.println(\"GEJC\");                  //显示文字\r\n}\r\nvoid loop() {\r\n  // put your main code here, to run repeatedly:\r\n\r\n}','',1),
(178,4,'nodeMCUesp8266通用OTA','#include <ESP8266WiFi.h>\r\n#include <ESP8266HTTPClient.h>\r\n#include <ESP8266httpUpdate.h>\r\nWiFiClient wificlient;\r\nString ssid=\"TP-LINK_C97D\"; //你的wifif名\r\nString wifipwd=\"19805282968\"; //你的wifi密码\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  WiFi.begin(ssid.c_str(), wifipwd.c_str());\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"Wifi->connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"Wifi 连接成功\");\r\n      break;\r\n    }\r\n  }\r\n  String upUrl = esp8266post();\r\n  if (upUrl.length() > 10) {\r\n    upUrl.trim(); \r\n    while (1) {\r\n      ESPhttpUpdate.onStart(update_started);\r\n      ESPhttpUpdate.onEnd(update_finished);\r\n      ESPhttpUpdate.onProgress(update_progress);\r\n      ESPhttpUpdate.onError(update_error);\r\n      ESPhttpUpdate.update(wificlient, upUrl);\r\n\r\n    }\r\n    ESP.restart();\r\n  }\r\n}\r\n\r\nvoid loop() {\r\n  // put your main code here, to run repeatedly:\r\n}\r\nvoid update_started() {\r\n  Serial.println(\"CALLBACK:  HTTP update process started\");\r\n}\r\n\r\nvoid update_finished() {\r\n  Serial.println(\"CALLBACK:  HTTP update process finished\");\r\n}\r\nString esp8266post() {\r\n  HTTPClient http;\r\n  String url = \"http://jyan.nobiggie.cn/query/vs\";\r\n  http.begin(wificlient, url);\r\n  http.setTimeout(3000);\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  String postData = \"vs=abc1124267212\";\r\n  int httpResponseCode = http.POST(postData);\r\n  if (httpResponseCode > 0) {\r\n    String response = http.getString();\r\n    if (response != \"false\") {\r\n      return response;\r\n    }\r\n  }\r\n  return \"\";\r\n}\r\nvoid update_progress(int cur, int total) {\r\n  Serial.printf(\"CALLBACK:  HTTP update process at %d of %d bytes...\\n\", cur, total);\r\n}\r\n\r\nvoid update_error(int err) {\r\n  Serial.printf(\"CALLBACK:  HTTP update fatal error code %d\\n\", err);\r\n}','',1),
(179,4,'esp32 HTTPUpdate OTA','#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <HTTPClient.h>\r\n#include <HTTPUpdate.h>\r\nWiFiClient wificlient;\r\nString ssid=\"webserver\";\r\nString wifipwd=\"www.360xyz.cn\";\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  WiFi.begin(ssid.c_str(), wifipwd.c_str());\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"wifiConnet...\");\r\n  while (1) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"wifi connet success\");\r\n      break;\r\n    }\r\n  }\r\n  delay(500);\r\n  String re = esp32post();\r\n  Serial.println(re);\r\n  re.trim();\r\n  if (re.length()>10) {\r\n    while (1) {\r\n      httpUpdate.onStart(update_started);\r\n      httpUpdate.onEnd(update_finished);\r\n      httpUpdate.onProgress(update_progress);\r\n      httpUpdate.onError(update_error);\r\n      t_httpUpdate_return ret = httpUpdate.update(wificlient, re);\r\n      //t_httpUpdate_return ret = httpUpdate.update(wificlient, \"server\", 80, \"/file.bin\");\r\n      switch (ret) {\r\n        case HTTP_UPDATE_FAILED:\r\n          Serial.printf(\"HTTP_UPDATE_FAILED Error (%d): %s\\n\", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());\r\n          break;\r\n        case HTTP_UPDATE_NO_UPDATES:\r\n          Serial.println(\"HTTP_UPDATE_NO_UPDATES\");\r\n          break;\r\n        case HTTP_UPDATE_OK:\r\n          Serial.println(\"HTTP_UPDATE_OK\");\r\n          break;\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\nvoid loop() {\r\n  // put your main code here, to run repeatedly:\r\n  delay(5000);\r\n  Serial.println(\"123\");\r\n}\r\nvoid update_started() {\r\n  Serial.println(\"CALLBACK:  HTTP update process started\");\r\n}\r\n\r\nvoid update_finished() {\r\n  Serial.println(\"CALLBACK:  HTTP update process finished\");\r\n}\r\n\r\nvoid update_progress(int cur, int total) {\r\n  Serial.printf(\"CALLBACK:  HTTP update process at %d of %d bytes...\\n\", cur, total);\r\n}\r\n\r\nvoid update_error(int err) {\r\n  Serial.printf(\"CALLBACK:  HTTP update fatal error code %d\\n\", err);\r\n}\r\n\r\nString esp32post() {\r\n  HTTPClient http;\r\n  String url = \"http://jyan.nobiggie.cn/query/vs\";\r\n  http.begin(wificlient, url);\r\n  http.setTimeout(3000);\r\n  String postStr = \"version=nodemcuesp32s01\";\r\n  char dataBuff[postStr.length()];\r\n  strcpy(dataBuff, postStr.c_str());\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  int httpResponseCode = http.POST(dataBuff);\r\n  if (httpResponseCode > 0) {\r\n    String response = http.getString();\r\n    return response;\r\n  }\r\n  return \"\";\r\n}','',1),
(180,4,'摄像头4组开关温湿度1','/* *****************************************************************\r\n *\r\n * Download latest Blinker library here:\r\n * https://github.com/blinker-iot/blinker-library/archive/master.zip\r\n * \r\n * \r\n * Blinker is a cross-hardware, cross-platform solution for the IoT. \r\n * It provides APP, device and server support, \r\n * and uses public cloud services for data transmission and storage.\r\n * It can be used in smart home, data monitoring and other fields \r\n * to help users build Internet of Things projects better and faster.\r\n * \r\n * Make sure installed 2.7.4 or later ESP8266/Arduino package,\r\n * if use ESP8266 with Blinker.\r\n * https://github.com/esp8266/Arduino/releases\r\n * \r\n * Make sure installed 1.0.5 or later ESP32/Arduino package,\r\n * if use ESP32 with Blinker.\r\n * https://github.com/espressif/arduino-esp32/releases\r\n * \r\n * Docs: https://diandeng.tech/doc\r\n *       \r\n * \r\n * *****************************************************************\r\n * \r\n * Blinker 库下载地址:\r\n * https://github.com/blinker-iot/blinker-library/archive/master.zip\r\n * \r\n * Blinker 是一套跨硬件、跨平台的物联网解决方案，提供APP端、设备端、\r\n * 服务器端支持，使用公有云服务进行数据传输存储。可用于智能家居、\r\n * 数据监测等领域，可以帮助用户更好更快地搭建物联网项目。\r\n * \r\n * 如果使用 ESP8266 接入 Blinker,\r\n * 请确保安装了 2.7.4 或更新的 ESP8266/Arduino 支持包。\r\n * https://github.com/esp8266/Arduino/releases\r\n * \r\n * 如果使用 ESP32 接入 Blinker,\r\n * 请确保安装了 1.0.5 或更新的 ESP32/Arduino 支持包。\r\n * https://github.com/espressif/arduino-esp32/releases\r\n * \r\n * 文档: https://diandeng.tech/doc\r\n *       \r\n * \r\n * *****************************************************************/\r\n\r\n#define BLINKER_WIFI\r\n\r\n#include <Blinker.h>\r\n#include \"ESP32_CAM_SERVER.h\"\r\n\r\nchar ssid[] = \"webserver\";\r\nchar wifipwd[] = \"www.360xyz.cn\";\r\nchar auth[] = \"7eb873d19e73\";\r\nint D12 = 12;\r\nint D13 = 13;\r\nint D15 = 15;\r\nint D14 = 14;\r\nBlinkerButton Button1(\"btn-xyb\");  //\r\nBlinkerButton Button2(\"btn-902\");  //\r\nBlinkerButton Button3(\"btn-fmc\");  //\r\nBlinkerButton Button4(\"btn-126\");  //\r\n\r\nbool d1 = false;\r\nbool d2 = false;\r\nbool d5 = false;\r\nbool d6 = false;\r\nbool setup_camera = false;\r\n\r\nvoid dataRead(const String& data) {\r\n  BLINKER_LOG(\"Blinker readString: \", data);\r\n\r\n  Blinker.vibrate();\r\n\r\n  uint32_t BlinkerTime = millis();\r\n\r\n  Blinker.print(\"millis\", BlinkerTime);\r\n}\r\n\r\nvoid setup() {\r\n  pinMode(D12, OUTPUT);\r\n  pinMode(D13, OUTPUT);\r\n  pinMode(D15, OUTPUT);\r\n  pinMode(D14, OUTPUT);\r\n  digitalWrite(D12, LOW);\r\n  digitalWrite(D13, LOW);\r\n  digitalWrite(D15, LOW);\r\n  digitalWrite(D14, LOW);\r\n  Serial.begin(115200);\r\n  BLINKER_DEBUG.stream(Serial);\r\n\r\n  pinMode(LED_BUILTIN, OUTPUT);\r\n  digitalWrite(LED_BUILTIN, LOW);\r\n\r\n  Blinker.begin(auth, ssid, wifipwd);\r\n  Blinker.attachData(dataRead);\r\n  Button1.attach(button1_callback);\r\n  Button2.attach(button2_callback);\r\n  Button3.attach(button3_callback);\r\n  Button4.attach(button4_callback);\r\n}\r\n\r\nvoid loop() {\r\n  Blinker.run();\r\n\r\n  if (Blinker.connected() && !setup_camera) {\r\n    setupCamera();\r\n    setup_camera = true;\r\n\r\n    Blinker.printObject(\"video\", \"{\\\"str\\\":\\\"mjpg\\\",\\\"url\\\":\\\"http://\" + WiFi.localIP().toString() + \"\\\"}\");\r\n  }\r\n}\r\nvoid button1_callback(const String& state) {\r\n  if (d1 == true) {\r\n    d1 = false;\r\n    digitalWrite(D12, LOW);\r\n    Button1.color(\"#000000\");\r\n    Button1.text(\"关\");\r\n  } else {\r\n    d1 = true;\r\n    digitalWrite(D12, HIGH);\r\n    Button1.color(\"#00FF00\");\r\n    Button1.text(\"开\");\r\n  }\r\n  Button1.print();\r\n}\r\nvoid button2_callback(const String& state) {\r\n  if (d2 == true) {\r\n    d2 = false;\r\n    digitalWrite(D13, LOW);\r\n    Button2.color(\"#000000\");\r\n    Button2.text(\"关\");\r\n  } else {\r\n    d2 = true;\r\n    digitalWrite(D13, HIGH);\r\n    Button2.color(\"#00FF00\");\r\n    Button2.text(\"开\");\r\n  }\r\n  Button2.print();\r\n}\r\nvoid button3_callback(const String& state) {\r\n  if (d5 == true) {\r\n    d5 = false;\r\n    digitalWrite(D15, LOW);\r\n    Button3.color(\"#000000\");\r\n    Button3.text(\"关\");\r\n  } else {\r\n    d5 = true;\r\n    digitalWrite(D15, HIGH);\r\n    Button3.color(\"#00FF00\");\r\n    Button3.text(\"开\");\r\n  }\r\n  Button3.print();\r\n}\r\nvoid button4_callback(const String& state) {\r\n  if (d6 == true) {\r\n    d6 = false;\r\n    digitalWrite(D14, LOW);\r\n    Button4.color(\"#000000\");\r\n    Button4.text(\"关\");\r\n  } else {\r\n    d6 = true;\r\n    digitalWrite(D14, HIGH);\r\n    Button4.color(\"#00FF00\");\r\n    Button4.text(\"开\");\r\n  }\r\n  Button4.print();\r\n}\r\n','',1),
(181,4,'智能照明','#define BLINKER_WIFI\r\n#include <Arduino.h>\r\n#include <Blinker.h>\r\nchar auth[] = \"1fac905d4e32\";\r\nchar ssid[] = \"webserver\";      //你的wifi\r\nchar pswd[] = \"www.360xyz.cn\";  //你的WIFI密码\r\n\r\n#define D5 14                      //人体感应\r\n#define D6 12                      //光敏感应\r\n#define D8 15                       //灯\r\nBlinkerButton Button1(\"btn-64g\");  //遥控灯开关\r\nbool lightStatu = false;           //默认灯是关的状态\r\nbool onOff = false;                //开关状态 默认关\r\nvoid setup() {\r\n  pinMode(D5, INPUT);\r\n  pinMode(D6, INPUT);\r\n  pinMode(D8, OUTPUT);\r\n  digitalWrite(D8, LOW);\r\n  // put your setup code here, to run once:\r\n  Serial.begin(115200);\r\n  Blinker.begin(auth, ssid, pswd);\r\n  Button1.attach(button1_callback);\r\n  delay(500);\r\n}\r\n\r\nvoid loop() {\r\n  // put your main code here, to run repeatedly:\r\n  Blinker.run();\r\n  //晚上光敏导通  全亮\r\n  if (digitalRead(D6) == HIGH) {\r\n    if (lightStatu == false) {\r\n      lightStatu = true;\r\n      digitalWrite(D8, HIGH);  //点亮灯\r\n      Button1.color(\"#00FF00\");\r\n      Button1.text(\"开\");\r\n      Button1.print();\r\n      Serial.println(\"晚上光敏导通  全亮\");\r\n    }\r\n  } else {\r\n    //白天\r\n    //并且是开灯状态 并且 人体感应 没有人    关灯\r\n    if (lightStatu == true && digitalRead(D5) == LOW && onOff == false) {\r\n      lightStatu = false;\r\n      digitalWrite(D8, LOW);  //关灯\r\n      Button1.color(\"#000000\");\r\n      Button1.text(\"关\");\r\n      Button1.print();\r\n      Serial.println(\"并且是开灯状态 并且 人体感应 没有人    ->关灯\");\r\n    } else {\r\n      //人体感应 有人 并且灯没有点亮\r\n      if (digitalRead(D5) == HIGH && lightStatu == false) {\r\n        lightStatu = true;       //点亮\r\n        digitalWrite(D8, HIGH);  //点亮灯\r\n        Button1.color(\"#00FF00\");\r\n        Button1.text(\"开\");\r\n        Button1.print();\r\n        Serial.println(\"人体感应 有人 并且灯没有点亮\");\r\n      }\r\n      //如果人体感应 没有人 并且 灯的状态是开的 并且没有手动开灯\r\n      if (digitalRead(D5) == LOW && lightStatu == true && onOff == false) {\r\n        lightStatu = false;\r\n        digitalWrite(D8, LOW);  //关灯\r\n        Button1.color(\"#000000\");\r\n        Button1.text(\"关\");\r\n        Button1.print();\r\n        Serial.println(\"如果人体感应 没有人 并且 灯的状态是开的 并且没有手动开灯\");\r\n      }\r\n    }\r\n  }\r\n}\r\nvoid button1_callback(const String& state) {\r\n  //BLINKER_LOG(\"get button state: \", state);\r\n  if (lightStatu == false) {\r\n    Button1.color(\"#00FF00\");\r\n    Button1.text(\"开\");\r\n    Button1.print();\r\n    lightStatu = true;\r\n    digitalWrite(D8, HIGH);\r\n    onOff = true;\r\n  } else {\r\n    Button1.color(\"#000000\");\r\n    Button1.text(\"关\");\r\n    Button1.print();\r\n    lightStatu = false;\r\n    digitalWrite(D8, LOW);\r\n    onOff = false;\r\n  }\r\n}\r\n','',1),
(182,4,'ESP8266 http Post与Get请求','#include <ESP8266WiFi.h>\r\n#include <ESP8266HTTPClient.h>\r\nWiFiClient wificlient;\r\nvoid setup() {\r\n  // put your setup code here, to run once:\r\n  Serial.begin(115200);\r\n  WiFi.begin(\"webserver\", \"www.360xyz.cn\");\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  while (1) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      break;\r\n    }\r\n  }\r\n}\r\n\r\nvoid loop() {\r\n\r\n  String a = esp8266Get(\"http://server.nobiggie.cn/query/date\");\r\n  Serial.println(a);\r\n  delay(5000);\r\n}\r\nString esp8266Get(String string) {\r\n  HTTPClient http;\r\n  String response;\r\n  http.begin(wificlient, string);\r\n  http.setTimeout(3000);\r\n  int httpCode = http.GET();\r\n  // httpCode will be negative on error\r\n  if (httpCode == 200) {\r\n    response = http.getString();\r\n    return response;\r\n  } else {\r\n    return \"\";\r\n  }\r\n  http.end();\r\n}\r\nString esp8266Post(String url, String postStr) {\r\n  HTTPClient http;\r\n  String response;\r\n  http.begin(wificlient, url);\r\n  http.setTimeout(3000);\r\n  //需要传输的数据\r\n  char dataBuff[postStr.length()];\r\n  strcpy(dataBuff, postStr.c_str());\r\n  //头信息，需要的反注释就可以\r\n  //http.addHeader(\"Content-Type\", \"application/json;charset=utf-8\");\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  int httpCode = http.POST(dataBuff);\r\n  if (httpCode == 200) {\r\n    response = http.getString();\r\n    return response;\r\n  } else {\r\n    return \"\";\r\n  }\r\n  http.end();\r\n}','',1),
(183,4,'ESP32 http POST与GET请求','String esp32get() {\r\n  HTTPClient http;\r\n  String response;\r\n  String urlstr=\"http://jyan.nobiggie.cn/query/version?version=123456\";\r\n  http.begin(wificlient, urlstr);\r\n  http.setTimeout(3000);\r\n  int httpCode = http.GET();\r\n  // httpCode will be negative on error\r\n  if (httpCode == 200) {\r\n    response = http.getString();\r\n    return response;\r\n  } else {\r\n    return \"\";\r\n  }\r\n  http.end();\r\n}\r\nString esp32post() {\r\n  HTTPClient http;\r\n  String url = \"http://jyan.nobiggie.cn/query/version\";  // 替换为你的POST接口地址\r\n  http.begin(wificlient, url);\r\n  http.setTimeout(3000);\r\n  String postStr = \"version=esp32test10\";\r\n  char dataBuff[postStr.length()];\r\n  strcpy(dataBuff, postStr.c_str());\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  int httpResponseCode = http.POST(dataBuff);\r\n  if (httpResponseCode > 0) {\r\n    String response = http.getString();\r\n    return response;\r\n  }\r\n  return \"\";\r\n}','',1),
(184,4,'巴法云 get post控制设备','获取设备是否在线\r\nhttps://apis.bemfa.com/va/online?uid=07b120062a7972cf9831d7d9bc8012bc&topic=nobiggie01&type=1\r\n返回 \r\n{\r\n    \"code\": 0,  //0代表 成功\r\n    \"message\": \"OK\",\r\n    \"data\": false //true 为在线\r\n}\r\n获取设备所有主题\r\nhttps://apis.bemfa.com/va/alltopic?uid=07b120062a7972cf9831d7d9bc8012bc&type=1\r\n{\r\n    \"code\": 0,\r\n    \"message\": \"OK\",\r\n    \"data\": [\r\n        {\r\n            \"topic\": \"nobiggie01\",\r\n            \"msg\": \"\",\r\n            \"name\": \"\",\r\n            \"room\": \"\",\r\n            \"online\": false, //是否在线\r\n            \"tid\": \"\",\r\n            \"sid\": \"\", //如果是分享设备，此字段是分享者密钥\r\n            \"time\": \"2023-12-15 17:58:05\", //消息发送的时间，时区UTC/GMT+08:00\r\n            \"unix\": 1702634285 //消息发送的时间戳\r\n        }\r\n    ]\r\n}\r\n\r\n获取主题消息，支持GET协议\r\nhttps://apis.bemfa.com/va/getmsg?uid=07b120062a7972cf9831d7d9bc8012bc&topic=nobiggie01&type=1\r\n\r\n{\r\n    \"code\": 0,\r\n    \"message\": \"OK\",\r\n    \"data\": [\r\n        {\r\n            \"msg\": \"啊哈哈哈哈\",\r\n            \"time\": \"2023-12-18 11:09:04\",\r\n            \"unix\": 1702868944\r\n        }\r\n    ]\r\n}\r\n\r\n\r\n向主题推送消息，支持POST协议\r\nhttps://apis.bemfa.com/va/postmsg\r\n\r\nuid=07b120062a7972cf9831d7d9bc8012bc&topic=nobiggie01&type=1&msg=on&wemsg=on\r\n\r\n\r\n定时控制\r\n添加定时+删除定时 采用POST接口\r\n\r\n数据类型 \"Content-Type\": \"application/x-www-form-urlencoded\"\r\nhttps://api.bemfa.com/cloud/settime/v1/\r\nuid=07b120062a7972cf9831d7d9bc8012bc&topic=nobiggie01&type=1&msg=on&time=12:00:00&action=add    //add添加定时  del删除定时\r\n返回\r\n{\"code\":4003013,\"status\":\"add ok\"}  //成功\r\n删除 code:4003014 表示删除成功\r\n','',1),
(185,4,'超声波智能垃圾桶','#include <Arduino.h>\r\n#include <ESP32Servo.h>\r\nconst int trigPin = 4;\r\nconst int echoPin = 16;\r\nServo servo1;\r\nint pos = 0;\r\nbool bl;\r\nint minUs = 500;   //0度是脉宽,单位us\r\nint maxUs = 2500;  //180度脉宽,单位us\r\nint servo1Pin = 15;\r\nvoid setup() {\r\n  // put your setup code here, to run once:\r\n  Serial.begin(115200);\r\n  delay(200);\r\n  pinMode(trigPin, OUTPUT);\r\n  pinMode(echoPin, INPUT);\r\n  ESP32PWM::allocateTimer(0);  //指定使用的硬件定时器 esp32有4个\r\n  ESP32PWM::allocateTimer(1);\r\n  ESP32PWM::allocateTimer(2);\r\n  ESP32PWM::allocateTimer(3);\r\n  servo1.setPeriodHertz(50);  //指定PWM频率\r\n  servo1.attach(servo1Pin, minUs, maxUs);\r\n // servo1.write(0);  //转到指定角度(0-180);\r\n  //servo1.detach();  //不需要的时候将引脚和ledc分离\r\n}\r\n\r\nvoid loop() {\r\n  // put your main code here, to run repeatedly:\r\n  digitalWrite(trigPin, HIGH);\r\n  delayMicroseconds(15);  //us 间隔15微秒的脉冲信号供应给超声波HC-SR04\r\n  digitalWrite(trigPin, LOW);\r\n\r\n  auto t = pulseIn(echoPin, HIGH);\r\n  double dis = t * 0.01715;  //cm 通过接收超声波返回的时间差计算距离 单位厘米\r\n  Serial.println(dis);\r\n  if (dis < 27) {\r\n    bl = true;\r\n  } else {\r\n    if (bl == true) {  //离开垃圾桶后触发 如果一直在感应区 bl 一直是true,首次是true得下次false触发\r\n      Serial.println(\"打开盖子到特定角度..........例如140度后停止............5秒后关闭盖子........................\");\r\n      servo1.write(140);  //转到指定角度(0-180);\r\n      //servo1.detach();    //不需要的时候将引脚和ledc分离\r\n      delay(5000);\r\n      servo1.write(0);  //转到指定角度(0-180);\r\n     // servo1.detach();  //不需要的时候将引脚和ledc分离\r\n      Serial.println(\"5秒了关闭盖子中.....................舵机恢复到0角度后停止...................................\");\r\n    }\r\n    bl = false;\r\n  }\r\n  delay(200);\r\n}\r\n','',1),
(186,4,'网络音响','#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <WiFiClientSecure.h>\r\n#include <HTTPClient.h>\r\n#include <WebServer.h>\r\n#include <FS.h>\r\n#include \"SPIFFS.h\"\r\n#include \"ESPmDNS.h\"\r\n#include <Ticker.h>\r\n#include <Audio.h>\r\n\r\nTicker myTicker;\r\n//被读取的文件位置和名称\r\nString flash_wifi = \"/wifi.txt\";\r\nWebServer webServer(80);  // 创建网络服务器对象，HTTP服务的标准端口为：80\r\nString ssid = \"\";\r\nString passwd = \"\";\r\nString html;\r\nString espIp;\r\nString localServerIP;\r\n\r\nWiFiClient client;\r\nString localserver;\r\n// Digital I/O used\r\n#define I2S_DOUT 25\r\n#define I2S_BCLK 26\r\n#define I2S_LRC 27\r\nAudio audio;\r\nvoid hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {\r\n  const uint8_t *src = (const uint8_t *)mem;\r\n  Serial.printf(\"\\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)\", (ptrdiff_t)src, len, len);\r\n  for (uint32_t i = 0; i < len; i++) {\r\n    if (i % cols == 0) {\r\n      Serial.printf(\"\\n[0x%08X] 0x%08X: \", (ptrdiff_t)src, i);\r\n    }\r\n    Serial.printf(\"%02X \", *src);\r\n    src++;\r\n  }\r\n  Serial.printf(\"\\n\");\r\n}\r\n\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  //Serial.setDebugOutput(true);\r\n  if (FlashConnetWifi() == false) {\r\n    HtmlSetWifi();\r\n  }\r\n  localserver = \"http://\" + localServerIP + \"/apiview/everyday5english\";\r\n  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);\r\n  audio.setVolume(19);  // 0...21   音量大小\r\n  String ttmps1 = HttpPost(localserver, \"MusicId=0\");\r\n  String tmps1 = \"http://\" + localServerIP + \"/\" + ttmps1;\r\n  //Serial.println(tmps1);\r\n  audio.connecttohost(tmps1.c_str());\r\n  delay(500);\r\n}\r\n\r\nvoid loop() {\r\n  audio.loop();\r\n}\r\n\r\nString HttpPost(String url, String postStr) {\r\n  HTTPClient http;\r\n  String response;\r\n  http.begin(client, url);\r\n  http.setTimeout(2000);\r\n  //需要传输的数据\r\n  char dataBuff[postStr.length()];\r\n  strcpy(dataBuff, postStr.c_str());\r\n  //头信息，需要的反注释就可以\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  int httpCode = http.POST(dataBuff);\r\n  if (httpCode == 200) {\r\n    response = http.getString();\r\n    return response;\r\n  } else {\r\n    return \"\";\r\n  }\r\n  http.end();\r\n}\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  ApOpen();\r\n  delay(1000);\r\n  Serial.println(\"启动网页\");\r\n  //5分后重启 防止停电后复电，路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式，所以这里只让AP激活5分钟后就重启\r\n  myTicker.once(300, EspRestart);\r\n  delay(200);\r\n  WebServerOpen();\r\n  while (1) {\r\n    webServer.handleClient();  // 检查网络服务请求并处理\r\n  }\r\n}\r\n\r\nvoid EspRestart() {\r\n  ESP.restart();\r\n}\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  WiFi.disconnect();\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(100);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    Serial.println(n);\r\n    String a = \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a + \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" + \"<html>\" + \"<head>\" + \"<meta charset=\\\"utf-8\\\">\" + \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" + \"<title>设置WiFi</title>\" + \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" + \"</head>\" + \"<script>\" + \"onload  = function() {\" + \"document.getElementById(\\\"up\\\").onclick = function(){\" + \"var ssida=document.getElementById(\\\"ssid\\\").value;\" + \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" + \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" + \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" + \"xhr = new XMLHttpRequest();\" + \"xhr.open(\\\"POST\\\",\\\"./SetWifi\\\",true);\" + \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" + \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" + \"xhr.send(posts);\" + \"xhr.onreadystatechange = function(){\" + \"if(this.readyState == 4 && this.status == 200){\" + \"alert(this.responseText);\" + \"}\" + \"}\" + \"}\" + \"}\" + \"</script>\" + \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" + \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" + \"<hr/>\" + \"<div>如果附近WiFi没有显示到自己的WIFI<div>\" + \"<div>请重启或离信号近点</div>\" + \"<div>连接成功AP热点退出转WIFI_STA</div>\" + \"</body>\" + \"</html>\";\r\n    a = a + \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"扫描不到网络\";\r\n    Serial.println(\"扫描不到网络\");\r\n  }\r\n}\r\nvoid SetWifi() {\r\n  ssid = webServer.arg(0);\r\n  passwd = webServer.arg(1);\r\n  const char *Ssid = ssid.c_str();\r\n  const char *Passwd = passwd.c_str();\r\n  String sp = ssid + \"&\" + passwd;\r\n\r\n  Serial.println(sp);\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  WiFi.begin(Ssid, Passwd);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  Serial.println(\"wifi_connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      webServer.send(200, \"text/plane\", \"Wifi密码正确，ESP准备重启\");\r\n      webServer.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n      Serial.println(\"HTML连接成功\");\r\n      delay(1000);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  webServer.send(200, \"text/plane\", \"Wifi密码错误，请重新输入\");\r\n  //HtmlSetWifi();\r\n}\r\n//------- 展示页面-------\r\nvoid handleRoot() {\r\n  webServer.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  webServer.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\n\r\n\r\nvoid ApOpen() {\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n\r\n  //启动AP模式，并设置账号和密码\r\n  boolean result = WiFi.softAP(\"192.168.168.2\", \"192.168.168.2\");\r\n  if (result) {\r\n    //输出 soft-ap ip地址\r\n    Serial.println(String(\"Soft-AP IP address = \") + WiFi.softAPIP());\r\n  }\r\n}\r\nvoid WebServerOpen() {\r\n  //-----------------启动webserver网络服务--------------------\r\n  webServer.begin();              // 启用网络服务\r\n  webServer.on(\"/\", handleRoot);  // / 在HTTP中，表示请求首页服务，\r\n  webServer.on(\"/SetWifi\", SetWifi);\r\n  webServer.onNotFound(handleNotFound);  // 当服务器没找到所需的服务，调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\n\r\nbool FlashConnetWifi() {\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  //是否存在数据\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    Serial.print(flash_wifi);\r\n    Serial.println(\" NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flash_wifi, \"r\");\r\n  String result;\r\n  for (int i = 0; i < dateFile.size(); i++) {\r\n    //Serial.print((char)dateFile.read());\r\n    result += (char)dateFile.read();\r\n  }\r\n  //去除前后空格\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char *WifiName = wifiname.c_str();\r\n  const char *WifiPw = wifipw.c_str();\r\n  Serial.println(WifiName);\r\n  Serial.println(WifiPw);\r\n  WiFi.begin(WifiName, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      espIp = WiFi.localIP().toString();\r\n      localServerIP = espIp.substring(0, espIp.lastIndexOf(\".\")) + \".254\";\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"FlashConnetWifi->false\");\r\n  return false;\r\n}\r\n// optional\r\nvoid audio_info(const char *info) {\r\n  // Serial.print(\"info        \"); Serial.println(info);\r\n  String str = info;\r\n  if (str.indexOf(\"End of webstream\") != -1) {\r\n    delay(900);\r\n    String ttmps = HttpPost(localserver, \"MusicId=next\");\r\n    String tmps2 = \"http://\" + localServerIP + \"/\" + ttmps;\r\n    audio.connecttohost(tmps2.c_str());\r\n  }\r\n}\r\nvoid audio_id3data(const char *info) {  //id3 metadata\r\n  Serial.print(\"id3data     \");\r\n  Serial.println(info);\r\n}\r\nvoid audio_eof_mp3(const char *info) {  //end of file\r\n  Serial.print(\"eof_mp3     \");\r\n  Serial.println(info);\r\n}\r\nvoid audio_showstation(const char *info) {\r\n  Serial.print(\"station     \");\r\n  Serial.println(info);\r\n}\r\nvoid audio_showstreamtitle(const char *info) {\r\n  Serial.print(\"streamtitle \");\r\n  Serial.println(info);\r\n}\r\nvoid audio_bitrate(const char *info) {\r\n  Serial.print(\"bitrate     \");\r\n  Serial.println(info);\r\n}\r\nvoid audio_commercial(const char *info) {  //duration in sec\r\n  Serial.print(\"commercial  \");\r\n  Serial.println(info);\r\n}\r\nvoid audio_icyurl(const char *info) {  //homepage\r\n  Serial.print(\"icyurl      \");\r\n  Serial.println(info);\r\n}\r\nvoid audio_lasthost(const char *info) {  //stream URL played\r\n  Serial.print(\"lasthost    \");\r\n  Serial.println(info);\r\n}','',1),
(187,4,'ESP8266 AP配网','#include <ESP8266WiFi.h>\r\n#include <ESP8266WebServer.h>\r\n#include <ESP8266HTTPClient.h>\r\n#include <Ticker.h>\r\n\r\n\r\nTicker myTicker;\r\nWiFiClient wificlient;\r\n\r\n//被读取的文件位置和名称\r\nString flash_wifi = \"/wifi.txt\";\r\nESP8266WebServer ESP8266webServer;  // 创建网络服务器对象,HTTP服务的标准端口为：80\r\nString ssid = \"\";\r\nString passwd = \"\";\r\nString html;\r\n\r\nvoid setup(void) {\r\n  Serial.begin(115200);\r\n  delay(1000);\r\n  if (FlashConnetWifi() == false) {\r\n    HtmlSetWifi();\r\n  }\r\n}\r\nvoid loop(void) {\r\n}\r\n\r\nvoid SetWifi() {\r\n  ssid = ESP8266webServer.arg(0);\r\n  passwd = ESP8266webServer.arg(1);\r\n  String sp = ssid + \"&\" + passwd;\r\n  Serial.println(sp);\r\n  Serial.println(\"密码在前面\");\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  const char* Ssid = ssid.c_str();\r\n  const char* WifiPw = passwd.c_str();\r\n  WiFi.begin(Ssid, WifiPw);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      ESP8266webServer.send(200, \"text/plane\", \"Wifi密码正确,ESP准备重启\");\r\n      ESP8266webServer.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n      Serial.println(\"HTML连接成功\");\r\n      delay(500);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  ESP8266webServer.send(200, \"text/plane\", \"Wifi密码错误,请重新输入\");\r\n}\r\n//------- 展示页面-------\r\nvoid handlejsonStr() {\r\n  ESP8266webServer.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  ESP8266webServer.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\n\r\nvoid ApStart() {\r\n  WiFi.disconnect();\r\n  delay(500);\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n  //启动AP模式,并设置账号和密码\r\n  WiFi.softAP(\"192.168.168.2\", \"nobiggie.cn\");\r\n}\r\nvoid WebserverStart() {\r\n  ESP8266webServer.begin(80);               // 启用网络服务\r\n  ESP8266webServer.on(\"/\", handlejsonStr);  // / 在HTTP中,表示请求首页服务,\r\n  ESP8266webServer.on(\"/SetWifi\", SetWifi);\r\n  ESP8266webServer.onNotFound(handleNotFound);  // 当服务器没找到所需的服务,调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\n\r\nvoid ForPing() {\r\n  //定时时间到了,先取消定时状态\r\n  myTicker.detach();\r\n  delay(500);\r\n  ESP.restart();\r\n}\r\n\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  Serial.begin(115200);\r\n  WiFi.disconnect();\r\n  WiFi.mode(WIFI_STA);\r\n  delay(100);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    Serial.println(n);\r\n    String a = \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a + \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" + \"<html>\" + \"<head>\" + \"<meta charset=\\\"utf-8\\\">\" + \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" + \"<title>设置WiFi</title>\" + \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" + \"</head>\" + \"<script>\" + \"onload  = function() {\" + \"document.getElementById(\\\"up\\\").onclick = function(){\" + \"var ssida=document.getElementById(\\\"ssid\\\").value;\" + \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" + \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" + \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" + \"xhr = new XMLHttpRequest();\" + \"xhr.open(\\\"POST\\\",\\\"./SetWifi\\\",true);\" + \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" + \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" + \"xhr.send(posts);\" + \"xhr.onreadystatechange = function(){\" + \"if(this.readyState == 4 && this.status == 200){\" + \"alert(this.responseText);\" + \"}\" + \"}\" + \"}\" + \"}\" + \"</script>\" + \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" + \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" + \"<hr/>\" + \"<font color=\\\"red\\\">附近WiFi没有显示到自己的WIFI请重启或离信号源近点</font>\" + \"</body>\" + \"</html>\";\r\n    a = a + \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"扫描不到网络\";\r\n    Serial.println(\"扫描不到网络\");\r\n  }\r\n}\r\nbool FlashConnetWifi() {\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  //是否存在数据\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    Serial.print(flash_wifi);\r\n    Serial.println(\" NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flash_wifi, \"r\");\r\n  String result = dateFile.readString();\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char* Ssid = wifiname.c_str();\r\n  const char* WifiPw = wifipw.c_str();\r\n  WiFi.begin(Ssid, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"FlashConnetWifi->false\");\r\n  return false;\r\n}\r\n\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  ApStart();\r\n  delay(1000);\r\n  Serial.println(\"启动网页\");\r\n  myTicker.detach();\r\n  delay(200);\r\n  //5分后重启 防止停电后复电,路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式,所以这里只让AP 激活5分钟后就重启\r\n  myTicker.once(300, espReboot);\r\n  delay(200);\r\n  WebserverStart();\r\n  while (1) {\r\n    ESP8266webServer.handleClient();  // 检查网络服务请求并处理\r\n  }\r\n}\r\nvoid espReboot() {\r\n  ESP.restart();\r\n}\r\n','',1),
(188,4,'ESP32 AP配网','#include <WiFi.h>\r\n#include <WebServer.h>\r\n#include <HTTPClient.h>\r\n#include <FS.h>\r\n#include \"SPIFFS.h\"\r\n#include \"ESPmDNS.h\"\r\n#include <Ticker.h>\r\n\r\nTicker myTicker;\r\nString flashWifi = \"/wifi.txt\";  //wifi密码存放文件\r\nWebServer webServer;\r\nString ssid;\r\nString passwd;\r\nString html;\r\n#define baudRate 115200\r\nvoid setup(void) {\r\n  if (FlashConnetWifi() == false) {\r\n    HtmlSetWifi();\r\n  }\r\n}\r\n\r\nvoid loop(void) {\r\n}\r\n\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  apStart();\r\n  delay(1000);\r\n  Serial.println(\"start webserver\");\r\n  //5分后重启 防止停电后复电，路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式，所以这里只让AP激活5分钟后就重启\r\n  myTicker.once(300, espReboot);\r\n  delay(200);\r\n  webserverStart();\r\n  while (1) {\r\n    webServer.handleClient();  //检查网络服务请求并处理\r\n  }\r\n}\r\nvoid espReboot() {\r\n  ESP.restart();\r\n}\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  WiFi.disconnect();\r\n  Serial.begin(baudRate);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(100);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    String a = \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a + \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" + \"<html>\" + \"<head>\" + \"<meta charset=\\\"utf-8\\\">\" + \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" + \"<title>设置WiFi</title>\" + \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" + \"</head>\" + \"<script>\" + \"onload  = function() {\" + \"document.getElementById(\\\"up\\\").onclick = function(){\" + \"var ssida=document.getElementById(\\\"ssid\\\").value;\" + \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" + \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" + \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" + \"xhr = new XMLHttpRequest();\" + \"xhr.open(\\\"POST\\\",\\\"./setWifi\\\",true);\" + \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" + \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" + \"xhr.send(posts);\" + \"xhr.onreadystatechange = function(){\" + \"if(this.readyState == 4 && this.status == 200){\" + \"alert(this.responseText);\" + \"}\" + \"}\" + \"}\" + \"}\" + \"</script>\" + \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" + \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" + \"<hr/>\" + \"<div>如果附近WiFi没有显示到自己的WIFI<div>\" + \"<div>请重启或离信号近点</div>\" + \"<div>连接成功AP热点退出转WIFI_STA</div>\" + \"</body>\" + \"</html>\";\r\n    a = a + \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"扫描不到网络\";\r\n  }\r\n}\r\nvoid setWifi() {\r\n  ssid = webServer.arg(0);\r\n  passwd = webServer.arg(1);\r\n  const char* Ssid = ssid.c_str();\r\n  const char* Passwd = passwd.c_str();\r\n  String sp = ssid + \"&\" + passwd;\r\n  Serial.println(sp);\r\n  Serial.begin(baudRate);\r\n  delay(500);\r\n  WiFi.begin(Ssid, Passwd);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  Serial.println(\"wifi_connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      webServer.send(200, \"text/plane\", \"Wifi密码正确,ESP准备重启\");\r\n      webServer.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flashWifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n      Serial.println(\"HTML设置网络连接成功\");\r\n      delay(500);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  webServer.send(200, \"text/plane\", \"Wifi密码错误,请重新输入\");\r\n}\r\n//------- 展示页面-------\r\nvoid handleRoot() {\r\n  webServer.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  webServer.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\nvoid apStart() {\r\n  Serial.begin(baudRate);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n  //启动AP模式，并设置账号和密码\r\n  boolean result = WiFi.softAP(\"192.168.168.2\", \"nobiggie.cn\");\r\n  if (result) {\r\n    Serial.println(String(\"Soft-AP IP address = \") + WiFi.softAPIP());\r\n  }\r\n}\r\nvoid webserverStart() {\r\n  webServer.begin(80);            // 启用网络服务\r\n  webServer.on(\"/\", handleRoot);  // / 在HTTP中，表示请求首页服务，\r\n  webServer.on(\"/setWifi\", setWifi);\r\n  webServer.onNotFound(handleNotFound);  // 当服务器没找到所需的服务，调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\nbool FlashConnetWifi() {\r\n  Serial.begin(baudRate);\r\n  delay(200);\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flashWifi) == false) {\r\n    Serial.println(\"NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flashWifi, \"r\");\r\n  String result;\r\n  for (int i = 0; i < dateFile.size(); i++) {\r\n    //Serial.print((char)dateFile.read());\r\n    result += (char)dateFile.read();\r\n  }\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char* WifiName = wifiname.c_str();\r\n  const char* WifiPw = wifipw.c_str();\r\n  Serial.println(WifiName);\r\n  Serial.println(WifiPw);\r\n  WiFi.begin(WifiName, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnet...\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"flash connet success\");\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"flash read error\");\r\n  return false;\r\n}','',1),
(189,4,'esp32舵机','#include <ESP32Servo.h>\r\nServo servo1;\r\nint minUs = 500;   //0度是脉宽,单位us\r\nint maxUs = 2500;  //180度脉宽,单位us\r\nint servo1Pin = 15;\r\nvoid setup() {\r\n  // put your setup code here, to run once:\r\n  Serial.begin(115200);\r\n  ESP32PWM::allocateTimer(0);  //指定使用的硬件定时器 esp32有4个\r\n  servo1.setPeriodHertz(50);   //指定PWM频率\r\n  servo1.attach(servo1Pin, minUs, maxUs);\r\n  servo1.write(90);  //转到指定角度(0-180);\r\n  servo1.detach();   //不需要的时候将引脚和ledc分离\r\n}\r\n\r\nvoid loop() {\r\n  // put your main code here, to run repeatedly:\r\n}\r\n','',1),
(190,4,'ESP32 WIFI 舵机','#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <WiFiMulti.h>\r\n#include <WiFiClientSecure.h>\r\n#include <WebSocketsClient.h>\r\n#include <ESP32Servo.h>\r\n#include <WebServer.h>\r\n#include <HTTPClient.h>\r\n#include <FS.h>\r\n#include \"SPIFFS.h\"\r\n#include \"ESPmDNS.h\"\r\n#include <Ticker.h>\r\n#include <ArduinoJson.h>\r\nServo servo1;\r\nint minUs = 500;   //0度是脉宽,单位us\r\nint maxUs = 2500;  //180度脉宽,单位us\r\nint servo1Pin = 15;\r\nint thisOpt=0;//当前角度\r\n\r\nTicker myTicker;\r\nDynamicJsonDocument  jsonBuffer(100);\r\nJsonObject desJson;\r\n//被读取的文件位置和名称\r\nString flash_wifi = \"/wifi.txt\";\r\nWebServer webServer(80);  // 创建网络服务器对象，HTTP服务的标准端口为：80\r\nString ssid = \"\";\r\nString passwd = \"\";\r\nString html;\r\n\r\nWiFiMulti WiFiMulti;\r\nWebSocketsClient webSocket;\r\n\r\n#define USE_SERIAL Serial1\r\n\r\nvoid hexdump(const void *mem, uint32_t len, uint8_t cols = 16) {\r\n  const uint8_t* src = (const uint8_t*) mem;\r\n  USE_SERIAL.printf(\"\\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)\", (ptrdiff_t)src, len, len);\r\n  for (uint32_t i = 0; i < len; i++) {\r\n    if (i % cols == 0) {\r\n      USE_SERIAL.printf(\"\\n[0x%08X] 0x%08X: \", (ptrdiff_t)src, i);\r\n    }\r\n    USE_SERIAL.printf(\"%02X \", *src);\r\n    src++;\r\n  }\r\n  USE_SERIAL.printf(\"\\n\");\r\n}\r\n\r\nvoid webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {\r\n\r\n  switch (type) {\r\n    case WStype_DISCONNECTED:\r\n      USE_SERIAL.printf(\"[WSc] Disconnected!\\n\");\r\n      break;\r\n    case WStype_CONNECTED:\r\n      USE_SERIAL.printf(\"[WSc] Connected to url: %s\\n\", payload);\r\n\r\n      // send message to server when Connected\r\n      webSocket.sendTXT(\"Connected\");\r\n      break;\r\n    case WStype_TEXT:\r\n      USE_SERIAL.printf(\"[WSc] get text: %s\\n\", payload);\r\n      deserializeJson(jsonBuffer, payload);\r\n      desJson = jsonBuffer.as<JsonObject>();\r\n      if (desJson[\"message\"] != \"\") {\r\n        String str = desJson[\"message\"];\r\n        Serial.println(str);\r\n        if(str==\"+\"){\r\n          if(thisOpt <=175){\r\n             thisOpt=thisOpt+5;\r\n             servo1.write(thisOpt);\r\n          }\r\n        }\r\n        if(str==\"-\"){\r\n          if(thisOpt<=5){\r\n             thisOpt=thisOpt-5;\r\n             servo1.write(thisOpt);\r\n          }\r\n        }\r\n        str=String(thisOpt);\r\n        webSocket.sendTXT(str);\r\n      }\r\n      // send message to server\r\n\r\n      break;\r\n    case WStype_BIN:\r\n      USE_SERIAL.printf(\"[WSc] get binary length: %u\\n\", length);\r\n      hexdump(payload, length);\r\n\r\n      // send data to server\r\n      // webSocket.sendBIN(payload, length);\r\n      break;\r\n    case WStype_PING:\r\n      // pong will be send automatically\r\n      Serial.printf(\"[WSc] get ping\\n\");\r\n      break;\r\n    case WStype_PONG:\r\n      // answer to a ping we send\r\n      Serial.printf(\"[WSc] get pong\\n\");\r\n      break;\r\n\r\n    case WStype_ERROR:\r\n    case WStype_FRAGMENT_TEXT_START:\r\n    case WStype_FRAGMENT_BIN_START:\r\n    case WStype_FRAGMENT:\r\n    case WStype_FRAGMENT_FIN:\r\n      break;\r\n  }\r\n\r\n}\r\n\r\nvoid setup() {\r\n  // USE_SERIAL.begin(921600);\r\n  USE_SERIAL.begin(115200);\r\n\r\n  //Serial.setDebugOutput(true);\r\n  USE_SERIAL.setDebugOutput(true);\r\n\r\n  USE_SERIAL.println();\r\n  USE_SERIAL.println();\r\n  USE_SERIAL.println();\r\n\r\n  for (uint8_t t = 4; t > 0; t--) {\r\n    USE_SERIAL.printf(\"[SETUP] BOOT WAIT %d...\\n\", t);\r\n    USE_SERIAL.flush();\r\n    delay(1000);\r\n  }\r\n\r\n  if (FlashConnetWifi() == false) {\r\n    HtmlSetWifi();\r\n  }\r\n  ESP32PWM::allocateTimer(0);  //指定使用的硬件定时器 esp32有4个\r\n  servo1.setPeriodHertz(50);   //指定PWM频率\r\n  servo1.attach(servo1Pin, minUs, maxUs);\r\n  //WiFi.disconnect();\r\n\r\n  // server address, port and URL\r\n  webSocket.begin(\"192.168.0.254\", 80, \"/service/wss\");\r\n\r\n  // event handler\r\n  webSocket.onEvent(webSocketEvent);\r\n\r\n  // use HTTP Basic Authorization this is optional remove if not needed\r\n  webSocket.setAuthorization(\"user=mg996r&password=efghijk&room=root\");\r\n\r\n  // try ever 5000 again if connection has failed\r\n  webSocket.setReconnectInterval(5000);\r\n\r\n}\r\n\r\nvoid loop() {\r\n  webSocket.loop();\r\n}\r\n\r\n\r\n\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  ApOpen();\r\n  delay(1000);\r\n  Serial.println(\"启动网页\");\r\n  //5分后重启 防止停电后复电，路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式，所以这里只让AP激活5分钟后就重启\r\n  myTicker.once(300, EspRestart);\r\n  delay(200);\r\n  WebServerOpen();\r\n  while (1) {\r\n    webServer.handleClient();   // 检查网络服务请求并处理\r\n  }\r\n}\r\nvoid EspRestart() {\r\n  ESP.restart();\r\n}\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_STA);\r\n  WiFi.disconnect();\r\n  delay(500);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    Serial.println(n);\r\n    String a =  \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a +  \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" +\r\n                       \"<html>\" +\r\n                       \"<head>\" +\r\n                       \"<meta charset=\\\"utf-8\\\">\" +\r\n                       \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" +\r\n                       \"<title>设置WiFi</title>\" +\r\n                       \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" +\r\n                       \"</head>\" +\r\n                       \"<script>\" +\r\n                       \"onload  = function() {\" +\r\n                       \"document.getElementById(\\\"up\\\").onclick = function(){\" +\r\n                       \"var ssida=document.getElementById(\\\"ssid\\\").value;\" +\r\n                       \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" +\r\n                       \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" +\r\n                       \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" +\r\n                       \"xhr = new XMLHttpRequest();\" +\r\n                       \"xhr.open(\\\"POST\\\",\\\"./SetWifi\\\",true);\" +\r\n                       \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" +\r\n                       \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" +\r\n                       \"xhr.send(posts);\" +\r\n                       \"xhr.onreadystatechange = function(){\" +\r\n                       \"if(this.readyState == 4 && this.status == 200){\" +\r\n                       \"alert(this.responseText);\" +\r\n                       \"}\" +\r\n                       \"}\" +\r\n                       \"}\" +\r\n                       \"}\" +\r\n                       \"</script>\" +\r\n                       \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" +\r\n                     \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" +\r\n                     \"<hr/>\" +\r\n                     \"<div>如果附近WiFi没有显示到自己的WIFI<div>\" +\r\n                     \"<div>请重启或离信号近点</div>\" +\r\n                     \"<div>连接成功AP热点退出转WIFI_STA</div>\" +\r\n                     \"</body>\" +\r\n                     \"</html>\";\r\n    a = a +  \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"no wifis\";\r\n    Serial.println(\"no wifis\");\r\n  }\r\n}\r\nvoid SetWifi() {\r\n  ssid = webServer.arg(0);\r\n  passwd = webServer.arg(1);\r\n  const char* Ssid = ssid.c_str();\r\n  const char* Passwd = passwd.c_str();\r\n  String sp = ssid + \"&\" + passwd;\r\n\r\n  Serial.println(sp);\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  WiFi.begin(Ssid, Passwd);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  Serial.println(\"wifi_connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      webServer.send(200, \"text/plane\", \"Wifi密码正确，ESP准备重启\");\r\n      webServer.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n      Serial.println(\"HTML连接成功\");\r\n      delay(1000);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  webServer.send(200, \"text/plane\", \"Wifi密码错误，请重新输入\");\r\n  //HtmlSetWifi();\r\n}\r\n//------- 展示页面-------\r\nvoid handleRoot() {\r\n  webServer.send(200, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  webServer.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\n\r\n\r\nvoid ApOpen() {\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet) ;\r\n\r\n  //启动AP模式，并设置账号和密码\r\n  boolean result = WiFi.softAP(\"192.168.168.2\", \"192.168.168.2\");\r\n  if (result) {\r\n    //输出 soft-ap ip地址\r\n    Serial.println(String(\"Soft-AP IP address = \") + WiFi.softAPIP());\r\n  }\r\n}\r\nvoid WebServerOpen() {\r\n  //-----------------启动webserver网络服务--------------------\r\n  webServer.begin(); // 启用网络服务\r\n  webServer.on(\"/\", handleRoot);   // / 在HTTP中，表示请求首页服务，\r\n  webServer.on(\"/SetWifi\", SetWifi);\r\n  webServer.onNotFound(handleNotFound);    // 当服务器没找到所需的服务，调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\n\r\nbool FlashConnetWifi() {\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  //是否存在数据\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    Serial.print(flash_wifi);\r\n    Serial.println(\" NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flash_wifi, \"r\");\r\n  String result;\r\n  for (int i = 0; i < dateFile.size(); i++) {\r\n    //Serial.print((char)dateFile.read());\r\n    result += (char)dateFile.read();\r\n  }\r\n  //去除前后空格\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char* WifiName = wifiname.c_str();\r\n  const char* WifiPw = wifipw.c_str();\r\n  Serial.println(WifiName);\r\n  Serial.println(WifiPw);\r\n  WiFi.begin(WifiName, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"FlashConnetWifi->false\");\r\n  return false;\r\n}','',1),
(191,4,'ESP8266 pwm 控制直流电机速度','const int ledPin = 3; \r\n\r\nvoid setup() {\r\n  // put your setup code here, to run once:\r\n  pinMode(ledPin, OUTPUT);\r\n  //频率为 1kHz 默认也是1kHz\r\n  analogWriteFreq(1000);\r\n  //设置 最大值  默认情况下为 1023\r\n  analogWriteRange(100);\r\n  Serial.begin(115200);\r\n}\r\nvoid loop() {\r\n  // 增加电机速度\r\n  for(int dutyCycle = 0; dutyCycle < 100; dutyCycle++){   \r\n    // 通过PWM改变速度\r\n    analogWrite(ledPin, dutyCycle);\r\n    delay(5);\r\n  }\r\n  // 降低电机速度\r\n  for(int dutyCycle = 100; dutyCycle > 0; dutyCycle--){\r\n    // 通过PWM改变速度\r\n    analogWrite(ledPin, dutyCycle);\r\n    delay(5);\r\n  }\r\n\r\n}','',1),
(192,4,'esp32 pwm 控制直流电机速度','//PWM控制\r\nint pwm1 = 21;\r\n//管道esp32有16个管道,0-7为80hz 高速管道  8-16为低速管道\r\nconst int channel1 = 0;\r\n//分辨率  2的8次方 256\r\nconst int resolution = 8;\r\n//PWM频率\r\nconst int freq = 1000;\r\n//初始值 49%\r\nint PwmNow = 125;\r\n//累加数\r\nint fadeAmount = 5;  \r\nvoid setup(void) {\r\npinMode(pwm1, OUTPUT);\r\n  ledcSetup(channel1, freq, resolution);\r\n  ledcAttachPin(pwm1, channel1);\r\n  ledcWrite(channel1, PwmNow);\r\n  pinMode(infrared1, INPUT_PULLUP);\r\n  digitalWrite(infrared1, LOW);\r\n}\r\nvoid loop(void) {\r\n  if(PwmNow<255){\r\n      PwmNow = PwmNow + fadeAmount;\r\n      ledcWrite(channel1, PwmNow);\r\n      int temp=PwmNow*100/255;\r\n      String tempStr=String(temp)+\"%\";\r\nSerial.println(tempStr);\r\ndelay(1000);\r\n  }\r\n//上面这个是旧版的 下面是新版的使用方法\r\n#include <Arduino.h>\r\n\r\nint  pwmPin = 4;              //PWM控制\r\nconst uint32_t pwmFreq = 1000;   // PWM频率1kHz（1-10kHz适合电机控制）\r\nconst uint8_t pwmResolution = 8; // 8位分辨率（0-255）\r\n\r\nvoid setup(void) {\r\n  // 手动选择通道并绑定引脚\r\n  if (ledcAttach( pwmPin,pwmFreq, pwmResolution)) {\r\n    Serial.printf(\"PWM配置成功：频率=%dHz，分辨率=%dbits\\n\", pwmFreq, pwmResolution);\r\n  } else {\r\n     Serial.println(\"PWM配置失败，请检查参数或通道占用情况\");\r\n  }\r\n}\r\nledcWrite(pwmPin,angle);//这个设置占空比','',1),
(193,4,'土壤湿度传感器','                int shidu = 0; // 土壤传感器输入接模拟引脚 A0\r\nint value = 0; //初始化变量value\r\n\r\nvoid setup() {\r\n  Serial.begin(19200);//设置波特率为115200\r\n  Serial.println(\"\\n\");//换行\r\n}\r\n\r\nvoid loop() {\r\n  value = analogRead(shidu);//模拟数据读取（A0脚输入的数据）\r\n  value = value / 10.2;    //上面的value值除以10.2 值得多少要看空悬时也就是干燥时为100%赋值给value\r\n  Serial.print(value);\r\n  Serial.println(\"%\");\r\n  //value值小于50时，对结果进行判\r\n  if (value < 50){\r\n    Serial.println(\"土壤是湿润的\");\r\n  }else{\r\n    Serial.println(\"土壤是干燥的\");\r\n  }\r\n  delay(1000);//延时1s，每一秒读取一次\r\n}     \r\n\r\n/* 该传感器可以独立工作\r\nD0 LED灯不亮时  D0脚为高电平3.3v 亮为低电平，调节小电位器让其到指定的阀值LED灯点亮即低电平,\r\n如果需要读取湿度比例值就必须要接ESP单片机了\r\n*/        ','',1),
(194,4,'向芯片flash读写数据','闪存 相当于 电脑硬盘的C以外盘符\r\n每次重新烧录是不会被清除的只有手动操作<FS.h>库来清除\r\n比如 WIFI 帐号密码存到闪存中\r\n这样就不用向程序里写死WIFI帐号密码\r\n#include <FS.h> //库文件\r\nString flash_file = \"/false.txt\"; //被读取的文件位置和名称\r\n\r\n//是否存在数据\r\nif (SPIFFS.exists(flash_file)) {\r\n  Serial.print(file_name);\r\n  Serial.print(\" FOUND\");\r\n} else {\r\n  Serial.print(file_name);\r\n  Serial.println(\" NOT FOUND\");\r\n}\r\n\r\n//写入数据\r\n  SPIFFS.format();//格式化SPIFFS 慎用\r\n  delay(500);\r\n  SPIFFS.begin();//启动闪存写入模式\r\n  File dataFile = SPIFFS.open(\"./wifi.txt\", \"w\");\r\n  dataFile.println(str);\r\n  dataFile.close();\r\n  return true;\r\n\r\n//读取数据  wra 代表 w r a a+  其中a代表追加数据 a+代表可读可追加\r\n  //是否存在数据\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(\"./wifi.txt\") == false) {\r\n    Serial.print(path);\r\n    Serial.println(\" NOT FOUND\");\r\n    return \"\";\r\n  }\r\n  File dataFile = SPIFFS.open(\"./wifi.txt\", \"r\");\r\n  String result = dataFile.readString();\r\n  result.trim(); //清理字符两边的空格\r\n  Serial.print(result);\r\n\r\n\r\n//显示目录中文件内容以及文件大小\r\nDir dir = SPIFFS.openDir(flash_file); //建立“目录对象”dir\r\nwhile (dir.next()) //dir.next()用于检查目录中是否还有”下一个文件“\r\n{\r\n  Serial.println(dir.fileName());//输出文件名\r\n}\r\n\r\n//删除数据\r\nSPIFFS.remove(flash_file);      ','',1),
(195,4,'MQTT协议','MQTT连接服务器\r\n=======固定报头======\r\n10 ??(后面做完,再数有几个再转16进制值)\r\n\r\n======可变报头 协议名======\r\n00 04   4D 51 54 54(MQTT 转换成16进制的值)\r\n======可变报头 协议级别\r\n04\r\n======可变报头 连接标示======\r\n1(用户名) 1(密码) 0 0 0 0 1 0\r\n转换16进制是\r\nC2\r\n======可变报头 保持连接======\r\n00 78(120秒十进制转换16进制是78)\r\n可变报头串连\r\n10 ?? 00 04 4D 51 54 54 04 C2 00 78\r\n\r\n=========有效载荷=============\r\n//没有遗嘱\r\n有效载荷 = 客户ID + 用户 + 密码\r\nclient id的16进制长度+client id+mqtt username的16进制长度+mqtt username+mqtt password的16进\r\n\r\n制长度+mqtt password\r\n//有遗嘱\r\n有效载荷 = 客户ID + 遗嘱主题 + 遗嘱消息 + 用户 + 密码\r\n?? 超过128字节 请查看 第二条 MQTT剩余长度规则\r\n服务器返回 20 02 00 00 (00)代表成功\r\n\r\n//MQTT剩余长度规则\r\n小于128个字节的可以用 一个字节表示\r\n等于128就要用两个字节表示\r\n计算公式  剩余长度=128*a+b\r\nb是10进制转换成2进制 从后面开始数第8位置为1\r\n比如b=33 二进制是100001 第8位置1那么就等于\r\n10100001 再转换成16进制就是A1\r\n记往低位放前 A1 下面计算放后面的高位\r\na=1 二进制就是1 转换成16进制也是1 那行得到\r\nA1 01\r\n\r\n\r\n//MQTT订阅主题\r\n固定报头 + (可变报头16进制长度(00 xx)+可变报头)+权限等级01\r\n如下\r\n82 ?? 00 0A \r\n(可变报头16进制长度(00 xx)+可变报头)+权限等级01\r\n?? 是(可变报头16进制长度(00 xx)+可变报头)+权限等级01的总长度16进制\r\n服务器返回 90 03 00 0A 01 代表成功\r\n如权限等级是0则返回 90 03 00 0A 00\r\n\r\n//MQTT发布消息 固定报头+可变报头+\r\n30 ?? +发布可变报头长度+发布可变报头+01+消息内容长度+消息内容\r\n\r\n//MQTT取消订阅\r\n====取消订阅=====\r\n固定报头+可变报头+有效载荷\r\nA2 ??(固定报)\r\n00 0A (可变报头)\r\n之前 订阅主题 的16进制的长度+  订阅主题 的16进制(有效载荷)\r\n返回 B0 02 00 0A(代表退订成功)','',1),
(196,4,'arduino 自带函数库Ticker定时','Ticker myTicker;\r\nmyTicker.once(秒为单位只执行一次,方法名);\r\nmyTicker.once_ms(毫秒为单位只执行一次,方法名);\r\n\r\nmyTicker.attach(秒为单位死循环,方法名);\r\nmyTicker.attach_ms(毫秒为单位死循环,方法名);\r\n//也可以加第三个参数为 回调函数\r\n\r\nmyTicker.detch(); //停止定时\r\n\r\nmyTicker.active(); //查看是否有定时状态','',1),
(197,4,'esp32遥控小车AP(电容感应切换车头,射频遥控)','/*\r\n面向车尾   \r\np32  左边电机  左正\r\np33  右边电机  右正\r\np25  左边电机  左反\r\np26  右边电机  右反\r\np27  升   正\r\np14  降   反\r\np12  关发动机  触动3秒后断开\r\nP15  开机通电一直手摸线 可以遥控方向相互转换\r\np4   设置 射频遥控 与 WIFI遥控 切换\r\np21  PWM脚\r\np0   Power8266 输出高电平增加射频遥控 8键射频433遥控\r\n手机要用火狐浏览器\r\n\r\n\r\nP36 前进\r\nP39 后退\r\nP34 左拐弯\r\nP35 右拐弯\r\nP17 移动速度+\r\nP16 移动速度-\r\n*/\r\n#include <WiFi.h>\r\n#include <WebServer.h>\r\n#include <HTTPClient.h>\r\n#include <FS.h>\r\n#include \"SPIFFS.h\"\r\n#include \"ESPmDNS.h\"\r\n\r\n#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <WiFiMulti.h>\r\n#include <WiFiClientSecure.h>\r\n#include <ArduinoJson.h>\r\n#include <WebSocketsClient.h>\r\n\r\nString direction = \"/boolStr.txt\";\r\nString controlMode=\"/controlMode.txt\";\r\nWebServer webServer(80);  // 创建网络服务器对象，HTTP服务的标准端口为：80\r\nString request = \"\";\r\n\r\n//方向相互转换\r\nint touch15 = 15;\r\n//射频遥控  感应切换开关\r\nint touch4=4;\r\n\r\nboolean globalBL=false;\r\n\r\n//转换成功指示灯\r\nint light22 = 22;\r\n\r\n//PWM控制\r\nint pwm1 = 21;\r\n//管道esp32有16个管道,0-7为80hz 高速管道  8-16为低速管道\r\nconst int channel1 = 0;\r\n//分辨率  2的8次方 256\r\nconst int resolution = 8;\r\n//PWM频率\r\nconst int freq = 1000;\r\n//初始值 41%\r\nint PwmNow = 105;\r\n//累加数\r\nint fadeAmount = 5;\r\n//接通esp8266电源\r\nint Power8266 = 0;\r\n\r\nWiFiMulti WiFiMulti;\r\nWebSocketsClient webSocket;\r\nDynamicJsonDocument jsonBuffer(100);\r\nJsonObject root;\r\n\r\nvoid hexdump(const void* mem, uint32_t len, uint8_t cols = 16) {\r\n  const uint8_t* src = (const uint8_t*)mem;\r\n  Serial.printf(\"\\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)\", (ptrdiff_t)src, len, len);\r\n  for (uint32_t i = 0; i < len; i++) {\r\n    if (i % cols == 0) {\r\n      Serial.printf(\"\\n[0x%08X] 0x%08X: \", (ptrdiff_t)src, i);\r\n    }\r\n    Serial.printf(\"%02X \", *src);\r\n    src++;\r\n  }\r\n  Serial.printf(\"\\n\");\r\n}\r\n\r\nString html = String(\"\")+\r\n\"<!DOCTYPE html><html lang=\\\"en\\\">\"+\r\n\"<head>\"+\r\n    \"<meta charset=\\\"UTF-8\\\">\"+\r\n    \"<meta name=\\\"viewport\\\" <meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\"+\r\n    \"<title>遥控车</title>\"+\r\n    \"<script>window.onload = function () {\"+\r\n            \"document.getElementById(\\\"xyzUp\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest();\"+\r\n                \"xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=↑\\\"); xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"xyzLeft\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\"); xhr.send(\\\"xyz=←\\\");\"+\r\n                \"xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"xyzLeft\\\").addEventListener(\\\"touchend\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\"); xhr.send(\\\"xyz=■\\\");\"+\r\n                \"xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"xyzStop\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=■\\\"); xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"xyzRight\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=→\\\"); xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"xyzRight\\\").addEventListener(\\\"touchend\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest();\"+\r\n                \"xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true); xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=■\\\"); xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"xyzDonw\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=↓\\\"); xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"rise\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest();\"+\r\n                \"xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=rise\\\"); xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"rise\\\").addEventListener(\\\"touchend\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=■\\\"); xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"decline\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=decline\\\"); xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"decline\\\").addEventListener(\\\"touchend\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\"); xhr.send(\\\"xyz=■\\\");\"+\r\n                \"xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"TurnOff\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=TurnOff\\\");\"+\r\n                \"xhr.onreadystatechange = function () {\"+\r\n                   \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"speedA\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=speedA\\\");\"+\r\n                \"xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n            \"document.getElementById(\\\"speedB\\\").addEventListener(\\\"touchstart\\\", function () {\"+\r\n                \"let xhr = new XMLHttpRequest(); xhr.open(\\\"POST\\\", \\\"./xyzgo\\\", true);\"+\r\n                \"xhr.setRequestHeader(\\\"Content-Type\\\", \\\"application/x-www-form-urlencoded\\\");\"+\r\n                \"xhr.send(\\\"xyz=speedB\\\");\"+\r\n                \"xhr.onreadystatechange = function () {\"+\r\n                    \"if (this.readyState == 4 && this.status == 200) {\"+\r\n                        \"document.getElementById(\\\"show\\\").innerHTML = this.responseText;\"+\r\n                    \"}}});\"+\r\n        \"}</script>\"+\r\n\"</head>\"+\r\n\"<style> *{ -moz-user-select: none; -ms-user-select:none; user-select:none; } </style>\"+\r\n\"<body>\"+\r\n    \"<div style=\\\"width: auto;margin-top:30px;text-align: center;\\\" id=\\\"show\\\"></div>\"+\r\n    \"<div style=\\\"padding: 20px;width:auto;margin: 80px auto auto; background-color: #EEF0F2;\\\">\"+\r\n        \"<p><input type=\\\"submit\\\" style=\\\"margin:auto auto 20% 42%;\\\" id=\\\"xyzUp\\\" value=\\\"&nbsp ↑ &nbsp\\\"></p>\"+\r\n        \"<p><input type=\\\"submit\\\" style=\\\"margin-left: 10%;\\\" id=\\\"xyzLeft\\\" value=\\\"&nbsp ← &nbsp\\\">\"+\r\n        \"<input type=\\\"submit\\\" style=\\\"margin:auto 17% auto 17%\\\" id=\\\"xyzStop\\\" value=\\\"&nbsp ■ &nbsp\\\">\"+\r\n        \"<input type=\\\"submit\\\" style=\\\"margin-right: 10%;\\\" id=\\\"xyzRight\\\" value=\\\"&nbsp → &nbsp\\\"></p>\"+\r\n        \"<p></p><input type=\\\"submit\\\" style=\\\"margin:20% auto auto 42%;\\\" id=\\\"xyzDonw\\\" value=\\\"&nbsp ↓ &nbsp\\\"></p>\"+\r\n    \"</div>\"+\r\n    \"<div style=\\\"width:auto;margin: 50px auto;text-align: center; background-color: #EEF0F2;\\\">\"+\r\n        \"<p><input type=\\\"submit\\\" style=\\\"float:left;\\\" id=\\\"rise\\\" value=\\\"&nbsp 机器升 &nbsp\\\"></p>\"+\r\n        \"<p><input type=\\\"submit\\\" style=\\\"margin-left:50%;\\\" id=\\\"decline\\\" value=\\\"&nbsp 机器降 &nbsp\\\"><br />\"+\r\n        \"<p><input type=\\\"submit\\\" value=\\\"速度+\\\" id=\\\"speedA\\\"></p>\"+\r\n        \"<p><input type=\\\"submit\\\" value=\\\"速度-\\\" id=\\\"speedB\\\"></p><br />\"+\r\n        \"<p><input type=\\\"submit\\\" id=\\\"TurnOff\\\" value=\\\"&nbsp 关闭发动机 &nbsp\\\"></p>\"+\r\n    \"</div></body></html>\";\r\n\r\nint LeftAdvance = 32;\r\nint RightAdvance = 33;\r\nint LeftRetreat = 25;\r\nint RightRetreat = 26;\r\nint rise = 27;\r\nint decline = 14;\r\n//发动机\r\nint TurnOff = 12;\r\n\r\n//touch 最大65  手摸20以下 但是运行环境 触摸达不到20以下,20-50间,应该设置为50\r\nconst int ConstTouch = 50;\r\nString runState = \"■\";\r\nString WebSocKetUserName=\"cart1\";\r\n\r\nvoid setup(void) {\r\n  pinMode(LeftAdvance, OUTPUT);\r\n  pinMode(LeftRetreat, OUTPUT);\r\n  pinMode(RightAdvance, OUTPUT);\r\n  pinMode(RightRetreat, OUTPUT);\r\n  pinMode(rise, OUTPUT);\r\n  pinMode(decline, OUTPUT);\r\n  pinMode(TurnOff, OUTPUT);\r\n  pinMode(light22, OUTPUT);\r\n  //pinMode(d5, INPUT_PULLUP);\r\n  //pinMode(d6, INPUT_PULLUP);\r\n\r\n  digitalWrite(LeftAdvance, LOW);\r\n  digitalWrite(LeftRetreat, LOW);\r\n  digitalWrite(RightAdvance, LOW);\r\n  digitalWrite(RightRetreat, LOW);\r\n\r\n  digitalWrite(rise, LOW);\r\n  digitalWrite(decline, LOW);\r\n  digitalWrite(TurnOff, LOW);\r\n  digitalWrite(light22, LOW);\r\n\r\n  pinMode(pwm1, OUTPUT);\r\n  ledcSetup(channel1, freq, resolution);\r\n  ledcAttachPin(pwm1, channel1);\r\n  ledcWrite(channel1, PwmNow);\r\n  pinMode(Power8266, OUTPUT);\r\n  digitalWrite(Power8266, LOW);\r\n\r\n  Serial.begin(115200);\r\n  delay(500);\r\n\r\n  if (!SPIFFS.begin(true)) {\r\n    Serial.println(\"SPIFFS加载失败\");\r\n  }\r\n  if (SPIFFS.exists(direction) == false) {\r\n    //写入数据\r\n    SetSPIFFS(direction, \"true\");\r\n    delay(300);\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(direction, \"r\");\r\n  String boolStr;\r\n  for (int i = 0; i < dateFile.size(); i++) {\r\n    //Serial.print((char)dateFile.read());\r\n    boolStr += (char)dateFile.read();\r\n  }\r\n  //去除前后空格\r\n  boolStr.trim();\r\n  Serial.println(boolStr);\r\n  delay(500);\r\n  int intto = touchRead(touch15);\r\n  delay(1000);\r\n  if (intto < ConstTouch) {\r\n    if (boolStr == \"true\") {\r\n        Serial.println(\"转换遥控方向成 重\");\r\n        SetSPIFFS(direction, \"false\");\r\n        delay(200);\r\n        globalBL=false;\r\n        ledFlicker();\r\n    } else {\r\n        Serial.println(\"转换遥控方向成 轻\");\r\n        SetSPIFFS(direction, \"true\");\r\n        delay(200);\r\n        globalBL=true;\r\n        ledFlicker();\r\n    }\r\n  }\r\n  delay(500);\r\n  int intto4 = touchRead(touch4);\r\n  delay(500);\r\n  //touch4 是否触摸操作 true为触摸\r\n  bool touch4BL=false;\r\n  if(intto4 < ConstTouch){\r\n    touch4BL=true;\r\n    if (!SPIFFS.begin(true)) {\r\n      Serial.println(\"SPIFFS加载失败\");\r\n    }\r\n    if (SPIFFS.exists(controlMode) == false) {\r\n      //写入数据  true代表 增加射频遥控 模式\r\n      SetSPIFFS(controlMode, \"false\");\r\n      delay(300);\r\n    }else{\r\n      String boolStr1;\r\n      File dateFile = SPIFFS.open(controlMode, \"r\");\r\n      for (int i = 0; i < dateFile.size(); i++) {\r\n      //Serial.print((char)dateFile.read());\r\n      boolStr1 += (char)dateFile.read();\r\n      }\r\n      //去除前后空格\r\n      boolStr1.trim();\r\n      Serial.println(boolStr1);\r\n      //上次是true射频模式 现在就关闭射频模式\r\n      if(boolStr1==\"true\"){\r\n        Serial.println(\"关闭射频模式\");\r\n        SetSPIFFS(controlMode, \"false\");\r\n      }else{\r\n        //开户射频模式\r\n        SetSPIFFS(controlMode, \"true\");\r\n        Serial.println(\"开启射频模式\");\r\n        digitalWrite(Power8266,HIGH);\r\n      }\r\n    }\r\n    ledFlicker();\r\n  }\r\n\r\n  if(touch4BL==false){\r\n    if (!SPIFFS.begin(true)) {\r\n      Serial.println(\"SPIFFS加载失败\");\r\n    }else{\r\n      String boolStr2;\r\n      File dateFile = SPIFFS.open(controlMode, \"r\");\r\n      for (int i = 0; i < dateFile.size(); i++) {\r\n      //Serial.print((char)dateFile.read());\r\n      boolStr2 += (char)dateFile.read();\r\n      }\r\n      //去除前后空格\r\n      boolStr2.trim();\r\n      Serial.println(boolStr2);\r\n      \r\n      if(boolStr2==\"true\"){\r\n        digitalWrite(Power8266,HIGH);\r\n      }\r\n    }\r\n  }\r\n\r\n  delay(200);\r\n  ApStart();\r\n  delay(200);\r\n  Serial.println(\"启动网页遥控AP\");\r\n  delay(200);\r\n  WebServerStart();\r\n}\r\n\r\nvoid loop(void) {\r\n  webServer.handleClient();\r\n\r\n}\r\n\r\n\r\n//------- 展示页面-------\r\nvoid handleRoot() {\r\n  webServer.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  webServer.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\nvoid xyzgo() {\r\n  request = webServer.arg(\"xyz\");\r\n  //Serial.println(request);\r\n  if (request == \"↑\") {\r\n    if(globalBL==false){\r\n      LeftFore();\r\n      RightFore();\r\n    }else{\r\n      LeftAft();\r\n      RightAft();\r\n    }\r\n    runState = \"↑\";\r\n    webServer.send(200, \"text/plane\", request);\r\n    Serial.println(\"↑\");\r\n    return;\r\n  }\r\n  if (request == \"↓\") {\r\n    if(globalBL==false){\r\n      LeftAft();\r\n      RightAft();\r\n    }else{\r\n      LeftFore();\r\n      RightFore();\r\n    }\r\n    runState = \"↓\";\r\n    webServer.send(200, \"text/plane\", request);\r\n    Serial.println(\"↓\");\r\n    return;\r\n  }\r\n  if (request == \"■\") {\r\n    StopAllExec();\r\n    runState = \"■\";\r\n    webServer.send(200, \"text/plane\", request);\r\n    Serial.println(\"■\");\r\n    return;\r\n  }\r\n  if (request == \"←\") {\r\n      RightFore();\r\n      LeftAft();\r\n    runState = \"←\";\r\n    webServer.send(200, \"text/plane\", request);\r\n    Serial.println(\"←\");\r\n    return;\r\n  }\r\n  if (request == \"→\") {\r\n      LeftFore();\r\n      RightAft();\r\n    \r\n    runState = \"→\";\r\n    webServer.send(200, \"text/plane\", request);\r\n    Serial.println(\"→\");\r\n    return;\r\n  }\r\n  if (request == \"rise\") {\r\n    digitalWrite(decline, LOW);\r\n    digitalWrite(rise, HIGH);\r\n    webServer.send(200, \"text/plane\", request);\r\n    return;\r\n  }\r\n  if (request == \"decline\") {\r\n    digitalWrite(rise, LOW);\r\n    digitalWrite(decline, HIGH);\r\n    webServer.send(200, \"text/plane\", request);\r\n    return;\r\n  }\r\n  if (request == \"TurnOff\") {\r\n    digitalWrite(TurnOff, HIGH);\r\n    webServer.send(200, \"text/plane\", request);\r\n    delay(3000);\r\n    digitalWrite(TurnOff, LOW);\r\n    return;\r\n  }\r\n  if (request == \"speedA\") {\r\n    if (PwmNow >= 178) {\r\n      webServer.send(200, \"text/plane\", \"已达到70%限速,无法继续加速\");\r\n    } else {\r\n      PwmNow = PwmNow + fadeAmount;\r\n      ledcWrite(channel1, PwmNow);\r\n      int temp=PwmNow*100/255;\r\n      String tempStr=String(temp)+\"%\";\r\n      webServer.send(200, \"text/plane\", tempStr);\r\n      Serial.println(\"speedA\");\r\n    }\r\n    return;\r\n  }\r\n  if (request == \"speedB\") {\r\n    if (PwmNow <= 77) {\r\n      webServer.send(200, \"text/plane\", \"已达到30%限速,无法继续减速\");\r\n    } else {\r\n      PwmNow = PwmNow - fadeAmount;\r\n      ledcWrite(channel1, PwmNow);\r\n      int temp=PwmNow*100/255;\r\n      String tempStr=String(temp)+\"%\";\r\n      webServer.send(200, \"text/plane\", tempStr);\r\n      Serial.println(\"speedB\");\r\n    }\r\n\r\n    return;\r\n  }\r\n  //HtmlSetWifi();\r\n}\r\n\r\nvoid ApStart() {\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n  String mymac=WiFi.macAddress();\r\n  Serial.println(mymac);\r\n  mymac.replace(\":\",\"\");\r\n  mymac.toLowerCase();\r\n  String temp1=mymac.substring(0,2);\r\n  String temp2=mymac.substring(10,12);\r\n  String ApPasswd=temp1+temp2;\r\n  Serial.println(ApPasswd);\r\n  //启动AP模式，并设置账号和密码\r\n  boolean result = WiFi.softAP(\"esp32WebServer192.168.168.2\", \"www.360xyz.cn\");\r\n  if (result) {\r\n    //输出 soft-ap ip地址\r\n    Serial.println(String(\"Soft-AP IP address = \") + WiFi.softAPIP());\r\n  }\r\n}\r\n//------- 展示页面-------\r\n\r\nvoid WebServerStart() {\r\n  //-----------------启动webserver网络服务--------------------\r\n  webServer.begin();              // 启用网络服务\r\n  webServer.on(\"/\", handleRoot);  // / 在HTTP中，表示请求首页服务，\r\n  webServer.on(\"/xyzgo\", xyzgo);\r\n  webServer.onNotFound(handleNotFound);  // 当服务器没找到所需的服务，调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\n\r\nvoid SetSPIFFS(String direction, String str) {\r\n  //写入数据\r\n  SPIFFS.remove(direction);\r\n  delay(500);\r\n  SPIFFS.begin();\r\n  File dataFile = SPIFFS.open(direction, \"w\");\r\n  dataFile.println(str);\r\n  dataFile.close();\r\n}\r\n//左轮前进\r\nvoid LeftFore() {\r\n  digitalWrite(LeftRetreat, LOW);\r\n  digitalWrite(LeftAdvance, HIGH);\r\n}\r\n//左轮后退\r\nvoid LeftAft() {\r\n  digitalWrite(LeftAdvance, LOW);\r\n  digitalWrite(LeftRetreat, HIGH);\r\n}\r\n//右轮前进\r\nvoid RightFore() {\r\n  digitalWrite(RightRetreat, LOW);\r\n  digitalWrite(RightAdvance, HIGH);\r\n}\r\n//右轮后退\r\nvoid RightAft() {\r\n  digitalWrite(RightAdvance, LOW);\r\n  digitalWrite(RightRetreat, HIGH);\r\n}\r\nvoid StopAllExec() {\r\n  digitalWrite(LeftAdvance, LOW);\r\n  digitalWrite(RightAdvance, LOW);\r\n  digitalWrite(LeftRetreat, LOW);\r\n  digitalWrite(RightRetreat, LOW);\r\n  digitalWrite(rise, LOW);\r\n  digitalWrite(decline, LOW);\r\n  delay(500);\r\n}\r\n//LED 闪烁\r\nvoid ledFlicker(){\r\n  digitalWrite(light22, HIGH);\r\n  delay(500);\r\n  digitalWrite(light22, LOW);\r\n  delay(500);\r\n  digitalWrite(light22, HIGH);\r\n  delay(500);\r\n  digitalWrite(light22, LOW);\r\n}','',1),
(198,4,'ESP8266 https GET','#include <ArduinoJson.h>\r\n#include <ESP8266WiFi.h>\r\n\r\nconst char* ssid = \"CMCC-j3vt\";\r\nconst char* password = \"qq282246101\";\r\n\r\n\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  delay(10);\r\n\r\n  Serial.println();\r\n  Serial.print(\"Connecting to \");\r\n  Serial.println(ssid);\r\n\r\n  WiFi.begin(ssid, password);\r\n\r\n  while (WiFi.status() != WL_CONNECTED) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n  }\r\n\r\n  Serial.println(\"\");\r\n  Serial.println(\"WiFi connected\");\r\n  Serial.println(\"IP address: \");\r\n  Serial.println(WiFi.localIP());\r\n}\r\nString MyHttpsGet(String host, String url) {\r\n  // Use WiFiClient class to create TCP connections\r\n  WiFiClientSecure client;\r\n  const int httpPort = 443;\r\n  client.setInsecure(); \r\n  if (!client.connect(host, httpPort)) { \r\n    Serial.println(\"connection failed\");\r\n    return \"\";\r\n  }\r\n\r\n  // This will send the request to the server\r\n  client.print(String(\"GET \") + url + \" HTTP/1.1\\r\\n\" +\r\n               \"Host: \" + host + \"\\r\\n\" +\r\n               \"Connection: close\\r\\n\\r\\n\");\r\n  String ss;\r\n  while (client.connected())\r\n  {\r\n    String line = client.readStringUntil(\'\\n\');\r\n    if (line.length() != 0) {\r\n      ss = ss + line;\r\n    }\r\n  }\r\n  return ss.substring(ss.lastIndexOf(\"Connection: close\") + 17);\r\n  client.stop();\r\n}\r\nvoid loop() {\r\n  String host = \"www.360xyz.cn\";\r\n  String url = \"/query/GetDate\";\r\n\r\n  String a = MyHttpsGet(host, url);\r\n  Serial.println(a);\r\n  delay(10000);\r\n}','',1),
(199,4,'esp32 https GET','String cat=String(\"\")+\"-----BEGIN CERTIFICATE-----\\r\\n\"+\r\n\"MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\\r\\n\"+\r\n\"MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\\r\\n\"+\r\n\"GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\\r\\n\"+\r\n\"YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\\r\\n\"+\r\n\"MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\\r\\n\"+\r\n\"BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\\r\\n\"+\r\n\"GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\\r\\n\"+\r\n\"ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\\r\\n\"+\r\n\"BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\\r\\n\"+\r\n\"3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\\r\\n\"+\r\n\"YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\\r\\n\"+\r\n\"rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\\r\\n\"+\r\n\"ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\\r\\n\"+\r\n\"oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\\r\\n\"+\r\n\"MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\\r\\n\"+\r\n\"QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\\r\\n\"+\r\n\"b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\\r\\n\"+\r\n\"AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\\r\\n\"+\r\n\"GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\\r\\n\"+\r\n\"Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\\r\\n\"+\r\n\"G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\\r\\n\"+\r\n\"l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\\r\\n\"+\r\n\"smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\\r\\n\"+\r\n\"-----END CERTIFICATE-----\";\r\nString MyHttpsGet(String url){\r\n  HTTPClient http;\r\n  String result;\r\n  http.begin(url,cat.c_str());\r\n  int httpCode=http.GET();\r\n  if(httpCode>0){\r\n     result=http.getString();\r\n  }\r\n  http.end();\r\n  return result;\r\n}','',1),
(200,4,'ESP32 多开一条线程','\r\n#include <Thread.h>\r\nThread myThread = Thread();\r\nvoid setup(void) {\r\n  myThread.onRun(niceCallback);\r\n  myThread.setInterval(10000);\r\n}\r\nvoid loop(void) {\r\n  if (myThread.shouldRun()) {\r\n    myThread.run();\r\n  }\r\n}\r\n\r\n\r\n\r\nvoid niceCallback() {\r\n  String HI = esp32getHI();\r\n  Serial.println(HI);\r\n  tft.setTextColor(TFT_WHITE, TFT_BLACK);\r\n  tft.setCursor(10, 10, 2);  //设置起始坐标(10, 10)，1 号字体\r\n  tft.println(HI);           //显示文字\r\n  millis();\r\n}','',1),
(205,5,'window 窗口创建使用','#include <windows.h>\r\n#include <commctrl.h>>\r\nUINT IDC_BUTTON_1=200;\r\n/* This is where all the input to the window goes to这是窗口的所有输入的位置 */\r\nLRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {\r\n\r\n	switch(Message) {\r\n		//在创建窗口过程时 未显示窗口前 接收 WM_CREATE 这时可以创建控件 \r\n		case WM_CREATE: {\r\n			UINT IDC_BUTTON_1=200;\r\n			HWND hButtonWnd=CreateWindow(WC_BUTTON,\"确定\",WS_CHILD|BS_PUSHBUTTON|WS_VISIBLE,100,100,50,20,hwnd,(HMENU)IDC_BUTTON_1,NULL,NULL);\r\n\r\n		}\r\n		break;\r\n		//接收 来自button的点击事件 WM_COMMAND\r\n		case WM_COMMAND: {\r\n			UINT buttio_id=LOWORD(wParam);\r\n			UINT nCode=HIWORD(wParam);\r\n			if(nCode==BN_CLICKED && buttio_id==IDC_BUTTON_1) {\r\n				MessageBox(hwnd,\"弹出消息了\",\"tip\",MB_OK);\r\n			}\r\n		}\r\n		break;\r\n		/* Upon destruction, tell the main thread to stop 销毁时，告诉主线程停止*/\r\n		case WM_DESTROY: {\r\n			PostQuitMessage(0);\r\n			break;\r\n		}\r\n\r\n		/* All other messages (a lot of them) are processed using default procedures */\r\n		default:\r\n			return DefWindowProc(hwnd, Message, wParam, lParam);\r\n	}\r\n	return 0;\r\n}\r\n\r\n/* The \'main\' function of Win32 GUI programs: this is where execution starts */\r\nint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {\r\n	WNDCLASSEX wc; /* A properties struct of our window  窗口的一个属性结构体*/\r\n	HWND hwnd; /* A \'HANDLE\', hence the H, or a pointer to our window 一个\'HANDLE\'，也就是H，或者一个指向窗口的指针*/\r\n	MSG msg; /* A temporary location for all messages 所有消息的临时位置*/\r\n\r\n	/* zero out the struct and set the stuff we want to modify 将结构归零并设置我们想要修改的内容 */\r\n	memset(&wc,0,sizeof(wc));\r\n	wc.cbSize		 = sizeof(WNDCLASSEX);\r\n	wc.lpfnWndProc	 = WndProc; /* This is where we will send messages to 这是我们要发送消息的地方*/\r\n	wc.hInstance	 = hInstance;\r\n	wc.hCursor		 = LoadCursor(NULL, IDC_ARROW);\r\n\r\n	/* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it 白色，COLOR_WINDOW只是一个系统颜色的#定义，尝试Ctrl+点击它*/\r\n	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);\r\n	wc.lpszClassName = \"WindowClass\";\r\n	wc.hIcon		 = LoadIcon(NULL, IDI_APPLICATION); /* Load a standard icon 加载一个标准图标*/\r\n	wc.hIconSm		 = LoadIcon(NULL, IDI_APPLICATION); /* use the name \"A\" to use the project icon 使用名称“A”来使用项目图标*/\r\n	//MessageBox(NULL,\"111111\",\"标题\",MB_ICONEXCLAMATION|MB_OK);\r\n	if(!RegisterClassEx(&wc)) {\r\n		MessageBox(NULL, \"Window Registration Failed!\",\"Error!\",MB_ICONEXCLAMATION|MB_OK);\r\n		return 0;\r\n	}\r\n\r\n	hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,\"WindowClass\",\"Caption123\",WS_VISIBLE|WS_OVERLAPPEDWINDOW,\r\n	                      CW_USEDEFAULT, /* x */\r\n	                      CW_USEDEFAULT, /* y */\r\n	                      640, /* width */\r\n	                      480, /* height */\r\n	                      NULL,NULL,hInstance,NULL);\r\n\r\n	if(hwnd == NULL) {\r\n		MessageBox(NULL, \"Window Creation Failed!\",\"Error!\",MB_ICONEXCLAMATION|MB_OK);\r\n		return 0;\r\n	}\r\n\r\n\r\n\r\n\r\n	/*\r\n		This is the heart of our program where all input is processed and\r\n		sent to WndProc. Note that GetMessage blocks code flow until it receives something, so\r\n		this loop will not produce unreasonably high CPU usage\r\n	*/\r\n	while(GetMessage(&msg, NULL, 0, 0) > 0) { /* If no error is received... */\r\n		TranslateMessage(&msg); /* Translate key codes to chars if present */\r\n		DispatchMessage(&msg); /* Send it to WndProc */\r\n	}\r\n	return msg.wParam;\r\n}','',1),
(206,5,'window窗口API开发一些常用函数','都是在WndProc 里面响应\r\nWM_CREATE  //窗口创建前\r\n\r\nWM_COMMAND  //窗口点击事件\r\nUINT nCode=HIWORD(wParam);\r\nnCode==BN_CLICKED\r\n//WS_CHILD子窗口\r\n//WS_VISIBLE 显示的意思\r\n\r\n//HMENU  UINT强制类型转换HMENU\r\nhwnd H= CreateWindow(窗口类型,控件名,样式(WS_CHILD|WS_VISIBLE),坐标x, 坐标y,宽,高,句柄,(HMENU)菜单(控件id),NULL,NULL );\r\n','',1),
(207,5,'c++类','#include <iostream>\r\nusing namespace std;\r\n\r\nclass Xyz\r\n{\r\n    int sz;\r\n    // 构造方法\r\npublic:\r\n    Xyz(int size)\r\n    {\r\n        sz = size;\r\n    }\r\n\r\npublic:\r\n    int Show()\r\n    {\r\n        return sz;\r\n    }\r\n\r\npublic:\r\n    string abc()\r\n    {\r\n        return \"Hello Worde\";\r\n    }\r\n    // 析构方法\r\npublic:\r\n    ~Xyz()\r\n    {\r\n    }\r\n};\r\n//main函数 是必须 放最后面 不然调用不了上面的类\r\nint main()\r\n{\r\n    Xyz abc(456);\r\n    cout << abc.abc();\r\n    return 0;\r\n}\r\n','',1),
(208,5,'c++引用 指针','#include <iostream>\r\nusing namespace std;\r\nint main()\r\n{\r\n    string a = \"123\";\r\n    // b变量是引用变量 a变量是本体\r\n    // 随着本体变量a的变化而变化\r\n    string &b = a;\r\n    a = \"321\";\r\n\r\n    // c是指针变量 存储的是a变量的内存地址\r\n    string *c = &a;\r\n    cout << b << endl;\r\n    cout << c << endl;\r\n    return 0;\r\n}\r\n输出结果 \r\n321\r\n0x12ebfffb90','',1),
(209,5,'c++ 获取当前时间','#include <ctime>\r\nusing namespace std;\r\nclass NowTime\r\n{\r\npublic:\r\n	int Time()\r\n	{\r\n		return time(0);\r\n	}\r\n\r\npublic:\r\n	string DateTime()\r\n	{\r\n		time_t now = time(0);\r\n		tm *p = localtime(&now);\r\n		int a = printf(\"%d-%d-%d %02d:%02d:%02d\\n\", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);\r\n		return to_string(a);\r\n	}\r\n};','',1),
(210,2,'apache2+php7卸载重装','一、删除apache的相关包及配置\r\n    sudo apt-get autoremove apache*\r\n二、删除关联\r\n    sudo find /etc -name \"*apache*\" |xargs  rm -rf\r\n三、清除dept列表\r\n    sudo apt purge `dpkg -l | grep apache| awk \'{print $2}\' |tr \"\\n\" \" \"`\r\n\r\n一、删除php的相关包及配置\r\n    sudo apt-get autoremove php7*\r\n二、删除关联\r\n    sudo find /etc -name \"*php*\" |xargs  rm -rf\r\n三、清除dept列表\r\n    sudo apt purge `dpkg -l | grep php| awk \'{print $2}\' |tr \"\\n\" \" \"`\r\n\r\n\r\napt install apache2 -y\r\nvi /etc/apache2/ports.conf   可以修改端口\r\n\r\nsudo apt install php libapache2-mod-php  //apache 关联php\r\nsudo systemctl restart apache2\r\nsudo a2enmod rewrite  //apache2 rewrite\r\n\r\nvi /etc/apache2/sites-enabled/000-default.conf\r\n<VirtualHost *:80> 里添加\r\n\r\n     <Directory /var/www/html>\r\n       Options Indexes FollowSymLinks\r\n       AllowOverride All\r\n       Require all granted\r\n     </Directory>\r\n\r\napt install php -y\r\napt install php-gd\r\napt install php-mysqli\r\napt install php-mbstring\r\n','',1),
(211,2,'要取消phpMyAdmin最大上传2M的限制','修改 php.ini 文件：\r\n打开 php.ini 文件，该文件的位置可能因服务器配置而异。常见位置是在 PHP 安装目录下。\r\n找到并修改以下参数：\r\nupload_max_filesize：允许上传文件大小的最大值，默认为 2M。将其修改为你需要的大小，例如 10M（即 upload_max_filesize = 10M）。\r\npost_max_size：指通过表单 POST 给 PHP 的所能接收的最大值，包括表单里的所有值。默认为 8M。设置该值必须大于 upload_max_filesize，例如 post_max_size = 10M。\r\nfile_uploads：确认其值为 on，以确保允许通过 HTTP 上传文件。\r\nupload_tmp_dir：指定文件上传至服务器上存储临时文件的目录。如果不指定，将使用系统默认的临时目录。\r\n还可以考虑修改以下参数，以避免因页面执行时间或内存限制导致的问题：\r\nmax_execution_time：每个 PHP 页面运行的最大时间值（秒），默认 30 秒。可适当增大，例如 max_execution_time = 300。\r\nmax_input_time：每个 PHP 页面接收数据所需的最大时间，默认 60 秒。可适当增大，例如 max_input_time = 300。\r\nmemory_limit：每个 PHP 页面所占用的最大内存，默认 8M。需根据服务器实际情况进行调整，确保其大于 post_max_size，例如 memory_limit = 128M。\r\n修改完 php.ini 文件后，需要重启 Web 服务器（如 Apache 或 Nginx），使修改生效。','',1),
(212,3,'个别浏览器session不同步','火狐浏览器,post更改session不会同步,还有验证码都是失败','',1),
(213,4,'nodeMCU esp8266获取串口2数据并POST','#include <ESP8266WiFi.h>\r\n#include <ESP8266HTTPClient.h>\r\n#include <SoftwareSerial.h>\r\nWiFiClient wificlient;\r\n#define RX_PIN 13  // 接收引脚\r\n#define TX_PIN 15  // 发送引脚\r\nSoftwareSerial mySerial(RX_PIN, TX_PIN);\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  mySerial.begin(19200);\r\n  WiFi.begin(\"webserver\", \"www.nobiggie.cn\");\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  while (1) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      break;\r\n    }\r\n  }\r\n}\r\n\r\nvoid loop() {\r\n  if (mySerial.available()) {\r\n    String receivedData = \"\";\r\n    int i=1;\r\n    while (mySerial.available()) {\r\n      char c = mySerial.read();\r\n      receivedData += c;\r\n      i++;\r\n    }\r\n\r\n    if (i>10) {\r\n      Serial.println(\"单号数据\"+receivedData);\r\n      String postStr=\"number=\"+receivedData;\r\n      esp8266Post(\"http://192.168.7.254/api/scan\",postStr);\r\n    }\r\n  }\r\n}\r\nString esp8266Post(String url, String postStr) {\r\n  HTTPClient http;\r\n  String response;\r\n  http.begin(wificlient, url);\r\n  http.setTimeout(3000);\r\n  //需要传输的数据\r\n  char dataBuff[postStr.length()];\r\n  strcpy(dataBuff, postStr.c_str());\r\n  //头信息，需要的反注释就可以\r\n  //http.addHeader(\"Content-Type\", \"application/json;charset=utf-8\");\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  int httpCode = http.POST(dataBuff);\r\n  if (httpCode == 200) {\r\n    response = http.getString();\r\n    return response;\r\n  } else {\r\n    return \"\";\r\n  }\r\n  http.end();\r\n}','',1),
(220,3,'float64转string','ff := 0.64\r\nstr := fmt.Sprintf(\"%.2f\", ff)','',1),
(221,3,'string转float64','    str := \"3.14\"\r\n    num, err := strconv.ParseFloat(str, 64)\r\n    if err!= nil {\r\n        // 处理转换错误\r\n        fmt.Println(\"转换出错:\", err)\r\n        return\r\n    }','',1),
(222,3,'int转string','str:= fmt.Sprintf(\"%d\", i)','',1),
(223,3,'string转int','    str := \"123\"\r\n    num, err := strconv.Atoi(str)\r\n    if err!= nil {\r\n        fmt.Println(\"转换出错:\", err)\r\n        return\r\n    }','',1),
(224,3,'bool转string','    b := true\r\n    str := fmt.Sprintf(\"%t\", b)','',1),
(225,3,'string转bool','str := \"true\"\r\nb, err := strconv.ParseBool(str)\r\nif err != nil {\r\n	fmt.Println(\"转换错误:\", err)\r\n	return\r\n}','',1),
(226,3,'websocket','func (ggg ServiceClass) Wss(ctx *gin.Context) {\r\n	if WebsocketLimiter.Allow() {\r\n		if ctx.Request.Method == \"GET\" {\r\n			var ws = websocket.Upgrader{\r\n				WriteBufferSize: 1028,\r\n				ReadBufferSize:  1028,\r\n				//跨域\r\n				CheckOrigin: func(r *http.Request) bool {\r\n					return true\r\n				},\r\n			}\r\n			var user, passwd, room string\r\n			webOs := true //默认网页登录\r\n			if ctx.Query(\"user\") != \"\" {\r\n				//fmt.Println(\"帐号用户\")\r\n				user = ctx.Query(\"user\")\r\n				passwd = ctx.Query(\"passwd\")\r\n				room = ctx.Query(\"room\")\r\n				if user == \"\" || passwd == \"\" || room == \"\" {\r\n					return\r\n				}\r\n				u := \"wQMh8OVTeE\"\r\n				//密码不是站长就验证  站长可以进任何房间\r\n				if passwd != u {\r\n					roomId := 0\r\n					bl1 := models.Db.Sql(\"SELECT id FROM WebsocketRoom WHERE name=?\", room).Row(&roomId)\r\n					if !bl1 {\r\n						return\r\n					}\r\n					//验证 帐号密码,房间room\r\n					openid := \"\"\r\n					b := models.Db.Sql(\"SELECT openid FROM Users WHERE user=? AND passwd=? AND roomid=?\", user, passwd, roomId).Row(&openid)\r\n					if !b {\r\n						return\r\n					}\r\n					if openid[len(openid)-10:] != passwd {\r\n						return\r\n					}\r\n				}\r\n			} else {\r\n				authorization := ctx.Request.Header[\"Authorization\"][0]\r\n				if authorization != \"\" {\r\n					webOs = false //非网页登录\r\n					//fmt.Println(\"单片机\")\r\n					arr, err7 := models.WebSystem.Parse_str(authorization)\r\n					if err7 != nil {\r\n						fmt.Println(\"单片机解析错误\")\r\n						return\r\n					}\r\n					user = arr[\"user\"]\r\n					passwd = arr[\"passwd\"]\r\n					room = arr[\"room\"]\r\n					if user == \"\" || passwd == \"\" || room == \"\" {\r\n						return\r\n					}\r\n				}\r\n				roomId := 0\r\n				bl1 := models.Db.Sql(\"SELECT id FROM WebsocketRoom WHERE name=?\", room).Row(&roomId)\r\n				if !bl1 {\r\n					return\r\n				}\r\n				//验证 帐号密码,房间room\r\n				passwdSql := \"\"\r\n				b := models.Db.Sql(\"SELECT id FROM Users WHERE user=? AND passwd=? AND roomid=?\", user, passwd, roomId).Row(&passwdSql)\r\n				if !b {\r\n					return\r\n				}\r\n			}\r\n			//正确 升级为websocket\r\n			conn, _ := ws.Upgrade(ctx.Writer, ctx.Request, nil)\r\n			//检查一下 自己组里有没有相同名字的,如果有把之前登录的同名用户下线\r\n			duplicationName := false //如果有同名用户 为 true\r\n			gUser := []string{}\r\n\r\n			if len(models.GroupFd[room]) != 0 {\r\n				for _, v := range models.GroupFd[room] {\r\n					if models.Clients[v].User == user {\r\n						duplicationName = true\r\n						//下线该用户名\r\n						models.Clients[v].Client.Close()\r\n\r\n						//重组在线成员列表\r\n						gFd := []uint32{}\r\n\r\n						for _, vv := range models.GroupFd[room] {\r\n							if v != vv {\r\n								gFd = append(gFd, vv)\r\n								gUser = append(gUser, models.Clients[vv].User)\r\n								//同时向在线该组成员 推送 用户重新上线消息\r\n								models.RWlock.Lock()\r\n								models.Clients[vv].Client.WriteMessage(websocket.TextMessage, []byte(\"SystemMessage: \"+user+\" 重新上线了\"))\r\n								models.RWlock.Unlock()\r\n							}\r\n						}\r\n						//得到去除同名的在线组成员 下一步把自己 加到该分组中\r\n						models.GroupFd[room] = gFd\r\n						models.GroupUser[room] = gUser\r\n						for _, v := range models.GroupFd[room] {\r\n							tmp := map[string][]string{}\r\n							//组成员赋值给 map[\"Group\"] 发送json\r\n							tmp[\"Group\"] = models.GroupUser[room]\r\n							models.Clients[v].Client.WriteJSON(tmp)\r\n						}\r\n\r\n						break\r\n					}\r\n				}\r\n				//加到 自己的fd 加到分组中 把自己的用户名 加到 在线组成员列表中\r\n				models.GroupFd[room] = append(models.GroupFd[room], models.Fd)\r\n				models.GroupUser[room] = append(models.GroupUser[room], user)\r\n			} else {\r\n				models.GroupFd[room] = []uint32{models.Fd}\r\n				models.GroupUser[room] = []string{user}\r\n			}\r\n			// 	//注册到系统 room fd user\r\n			client := models.WebsocketStruct{Client: conn, User: user, Fd: models.Fd, Room: room, WebOs: webOs}\r\n			models.RWlock.Lock()\r\n			models.Clients[models.Fd] = &client\r\n			models.RWlock.Unlock()\r\n			pongTimeOut := make(chan bool)\r\n\r\n			if len(models.GroupFd[room]) != 0 {\r\n				//推送在线组成员到每个成员中\r\n				//fmt.Println(models.GroupUser[room])\r\n				for _, v := range models.GroupFd[room] {\r\n					//不同名 向在该组在线成员推送 上线消息\r\n					if !duplicationName && v != models.Fd {\r\n						models.Clients[v].Client.WriteMessage(websocket.TextMessage, []byte(\"SystemMessage: \"+user+\" 上线了\"))\r\n					}\r\n					tmp := map[string][]string{}\r\n					tmp[\"Group\"] = models.GroupUser[room]\r\n					models.Clients[v].Client.WriteJSON(tmp)\r\n				}\r\n			}\r\n\r\n			//返回ping 向客户表示连接成功\r\n			if webOs {\r\n				conn.WriteMessage(websocket.PingMessage, []byte{})\r\n			}\r\n			//监听客户端close事件或者非常断开\r\n			conn.SetCloseHandler(func(code int, text string) error {\r\n				gFd := []uint32{}\r\n				for _, v := range models.GroupFd[room] {\r\n					if v != client.Fd {\r\n						gFd = append(gFd, v)\r\n					}\r\n				}\r\n				models.GroupFd[room] = gFd\r\n\r\n				gFd = []uint32{}\r\n				gUser = []string{}\r\n				//向组里广播该用户已经下线\r\n				for _, v := range models.GroupFd[room] {\r\n					models.Clients[v].Client.WriteMessage(websocket.TextMessage, []byte(\"system: \"+client.User+\"下线了\"))\r\n					if models.Clients[v].User != client.User {\r\n						gFd = append(gFd, v)\r\n						gUser = append(gUser, models.Clients[v].User)\r\n					}\r\n				}\r\n				//清除Client 连接\r\n				models.Clients[client.Fd].Client.Close()\r\n				//清除Clients 下这个成员的Fd 写列队互斥锁\r\n				models.RWlock.Lock()\r\n				delete(models.Clients, client.Fd)\r\n				models.RWlock.Unlock()\r\n				//组里有人下线就更新组成员\r\n				models.GroupFd[room] = gFd\r\n				models.GroupUser[room] = gUser\r\n				//然后逐个发送组成员 给组里的成员\r\n				for _, v := range models.GroupFd[room] {\r\n					tmp := map[string][]string{}\r\n					//组成员赋值给 map[\"Group\"] 发送json\r\n					tmp[\"Group\"] = models.GroupUser[room]\r\n					models.Clients[v].Client.WriteJSON(tmp)\r\n				}\r\n\r\n				return nil\r\n			})\r\n			if !webOs {\r\n				go func(fd uint32) {\r\n					breakBl := false //为true跳出循环\r\n					room := models.Clients[fd].Room\r\n					user := models.Clients[fd].User\r\n					ticker := time.NewTicker(time.Second * 20)\r\n					defer ticker.Stop()\r\n					for {\r\n						select {\r\n						case <-ticker.C:\r\n							//fmt.Println(\"每20秒发送ping\")\r\n							conn.WriteMessage(websocket.PingMessage, []byte{})\r\n						case <-pongTimeOut: //接受到pong超时chan\r\n							// 处理超时的情况\r\n							fmt.Println(\"发送 Ping 消息出错，客户端可能离线:\")\r\n							groupFdTmp := []uint32{}\r\n							for _, v := range models.GroupFd[room] {\r\n								if v != fd {\r\n									groupFdTmp = append(groupFdTmp, v)\r\n								}\r\n							}\r\n							models.GroupFd[room] = groupFdTmp\r\n							groupUserTmp := []string{}\r\n							for _, v := range models.GroupUser[room] {\r\n								if v != user {\r\n									groupUserTmp = append(groupUserTmp, v)\r\n								}\r\n							}\r\n							models.GroupUser[room] = groupUserTmp\r\n							//fmt.Println(models.GroupUser[room])\r\n							if len(models.GroupFd[room]) != 0 {\r\n								//向组里广播该用户已经下线\r\n								for _, v := range models.GroupFd[room] {\r\n									if models.Clients[v] == nil {\r\n										continue\r\n									}\r\n									//不同名 向在该组在线成员推送 上线消息\r\n									mm := make(map[string]string)\r\n									mm[\"date\"] = time.Now().Format(\"15:04:05\")\r\n									mm[\"message\"] = user + \" 下线了\"\r\n									mm[\"user\"] = \"system\"\r\n									models.RWlock.Lock()\r\n\r\n									models.Clients[v].Client.WriteJSON(mm)\r\n\r\n									models.RWlock.Unlock()\r\n									//更新组用户\r\n									tmp := map[string][]string{}\r\n									tmp[\"Group\"] = models.GroupUser[room]\r\n									models.RWlock.Lock()\r\n\r\n									models.Clients[v].Client.WriteJSON(tmp)\r\n\r\n									models.RWlock.Unlock()\r\n									if models.Clients[fd] != nil {\r\n										models.Clients[fd].Client.Close()\r\n									}\r\n\r\n									//fmt.Println(models.Clients)\r\n									//models.RWlock.Lock()\r\n									//delete(models.Clients, fd)\r\n									//models.RWlock.Unlock()\r\n									//fmt.Println(models.Clients)\r\n								}\r\n							}\r\n							breakBl = true\r\n						}\r\n						if breakBl {\r\n							fmt.Println(\"已经结束循环\")\r\n							break\r\n						}\r\n					}\r\n				}(models.Fd)\r\n				//不支持无阻塞 Pong 处理\r\n				conn.SetPongHandler(func(appData string) error {\r\n					//fmt.Println(\"单片机返回pong 消息是\" + appData)\r\n					//设置pong超时时间 因为这个只能生效一次,所以每次接受到pong都设置一次\r\n					conn.SetReadDeadline(time.Now().Add(time.Second * 50))\r\n					return nil\r\n				})\r\n\r\n			}\r\n\r\n			models.Fd++\r\n\r\n			for {\r\n				//第一个参数是数据类型,只是一个int,1代表String,2代表[]byte -1代表pong超时\r\n				//接收时是普通字符串。服务器返回给客户端是json\r\n				messageType, data, err := conn.ReadMessage()\r\n				if err != nil {\r\n					fmt.Println(\"err\")\r\n					if messageType == -1 { //pong超时\r\n						pongTimeOut <- true\r\n					}\r\n					return\r\n				}\r\n				mm := make(map[string]string)\r\n				if room == \"server\" {\r\n					mm[\"fd\"] = fmt.Sprintf(\"%d\", client.Fd)\r\n					mm[\"message\"] = string(data)\r\n					models.WebsocketMessageChan <- mm\r\n				} else {\r\n					mm[\"date\"] = time.Now().Format(\"15:04:05\")\r\n					str := string(data)\r\n					mm[\"message\"] = strings.Trim(str, \" \")\r\n					mm[\"user\"] = user\r\n					for _, v := range models.GroupFd[room] {\r\n						if client.Fd != v {\r\n							models.Clients[v].Client.WriteJSON(mm)\r\n						}\r\n					}\r\n					//admin 温湿度\r\n					if room == \"admin\" {\r\n						if strings.Contains(mm[\"message\"], \".\") && strings.Contains(mm[\"message\"], \",\") {\r\n							thStr := mm[\"message\"]\r\n							ii := strings.LastIndex(thStr, \",\")\r\n							tStr := thStr[0:ii]\r\n							hStr := thStr[ii+1:]\r\n							models.WebSystem.RequestPost(\"http://\"+models.Host+\"/wechat/door1publish\", \"msg=\"+tStr+hStr+\"&send=publish\")\r\n						}\r\n						if strings.Contains(mm[\"message\"], \"限制\") {\r\n							models.WebSystem.RequestPost(\"http://\"+models.Host+\"/wechat/door1publish\", \"msg=\"+mm[\"message\"]+\"&send=publish\")\r\n						}\r\n						if strings.Contains(mm[\"message\"], \"广告牌\") {\r\n							models.WebSystem.RequestPost(\"http://\"+models.Host+\"/wechat/door1publish\", \"msg=\"+mm[\"message\"]+\"&send=publish\")\r\n						}\r\n						if strings.Contains(mm[\"message\"], \"mydoor1.power1On\") {\r\n							msg := mm[\"message\"]\r\n							n := strings.Index(msg, \"mydoor1.power1On\")\r\n							if n != -1 {\r\n								t := msg[16:]\r\n								intt, _ := strconv.Atoi(t)\r\n								if intt != 0 {\r\n									if !Mydoor1power1On {\r\n										Mydoor1power1On = true\r\n										fmt.Println(\"定时开始\", intt)\r\n										go func() {\r\n											//定时intt 小时后关闭电源\r\n											timer := time.NewTimer(time.Duration(intt) * time.Hour)\r\n											for {\r\n												<-timer.C\r\n												timer.Stop()\r\n												Mydoor1power1On = false\r\n												models.WebsocketMessageChan <- map[string]string{\"message\": \"mydoor1.power1Off\"}\r\n												break\r\n											}\r\n										}()\r\n									}\r\n								}\r\n							}\r\n						}\r\n						if mm[\"message\"] == \"mydoor1.power1Off\" {\r\n							Mydoor1power1On = false\r\n						}\r\n					}\r\n				}\r\n			}\r\n\r\n		}\r\n	} else {\r\n		ctx.String(200, \"请求超过限流\")\r\n		return\r\n	}\r\n	ctx.String(200, \"\")\r\n}','',1),
(227,3,'gin 中间件 c.Next()原理','package main\r\n\r\nimport (\r\n	\"fmt\"\r\n\r\n	\"github.com/gin-gonic/gin\"\r\n)\r\n\r\n// 中间件函数\r\nfunc loggingMiddleware() gin.HandlerFunc {\r\n	return func(c *gin.Context) {\r\n		fmt.Println(\"loggingMiddleware start\")\r\n		c.Next()\r\n		fmt.Println(\"loggingMiddleware end\")\r\n	}\r\n}\r\n\r\nfunc main() {\r\n	r := gin.Default()\r\n	// 将中间件函数应用到需要共享处理逻辑的路由上\r\n	r.Use(loggingMiddleware())\r\n	r.GET(\"/\", func(c *gin.Context) {\r\n		fmt.Println(\"这里是c.Next()\")\r\n	})\r\n\r\n	r.Run(\":8080\")\r\n}\r\n\r\n\r\n//输出是\r\nloggingMiddleware start\r\n这里是c.Next()\r\nloggingMiddleware end','',1),
(228,4,'arduino 串口接收字符串整行输出','  if (Serial.available()) {\r\n    while (Serial.available()) {\r\n      String receivedString = Serial.readStringUntil(\'\\n\');  // 读取直到遇到换行符\r\n      webSocket.sendTXT(receivedString);\r\n    }\r\n  }','',1),
(230,4,'esp01s websocket串口发送','#include <Arduino.h>\r\n#include <ESP8266WiFi.h>\r\n#include <WebSocketsClient.h>\r\n#include <ESP8266httpUpdate.h>\r\n#include <Hash.h>\r\n#include <ArduinoJson.h>\r\n\r\nWebSocketsClient webSocket;\r\nDynamicJsonDocument jsonBuffer(100);\r\nJsonObject jsonArr;\r\nWiFiClient wificlient;\r\nvoid webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {\r\n\r\n  switch (type) {\r\n    case WStype_DISCONNECTED:\r\n      Serial.printf(\"[WSc] Disconnected!\\n\");\r\n      break;\r\n    case WStype_CONNECTED:\r\n      {\r\n        Serial.printf(\"[WSc] Connected to url: %s\\n\", payload);\r\n\r\n        // send message to server when Connected\r\n        //webSocket.sendTXT(\"Connected\");\r\n      }\r\n      break;\r\n    case WStype_TEXT:\r\n      Serial.printf(\"[WSc] get text: %s\\n\", payload);\r\n      deserializeJson(jsonBuffer, payload);\r\n      jsonArr = jsonBuffer.as<JsonObject>();\r\n      if (jsonArr[\"message\"] != \"\") {\r\n        String message = jsonArr[\"message\"];\r\n        if (message == \"updateBin\") {\r\n          while (1) {\r\n            ESPhttpUpdate.onStart(update_started);\r\n            ESPhttpUpdate.onEnd(update_finished);\r\n            ESPhttpUpdate.onProgress(update_progress);\r\n            ESPhttpUpdate.onError(update_error);\r\n            ESPhttpUpdate.update(wificlient, \"http://192.168.0.254/tool/ota/GolangCpp/scan.bin\");\r\n          }\r\n        }\r\n      }\r\n      // send message to server\r\n      // webSocket.sendTXT(\"message here\");\r\n      break;\r\n    case WStype_BIN:\r\n      Serial.printf(\"[WSc] get binary length: %u\\n\", length);\r\n      hexdump(payload, length);\r\n\r\n      // send data to server\r\n      // webSocket.sendBIN(payload, length);\r\n      break;\r\n    case WStype_PING:\r\n      // pong will be send automatically\r\n      //Serial.printf(\"[WSc] get ping\\n\");\r\n      break;\r\n    case WStype_PONG:\r\n      // answer to a ping we send\r\n      Serial.printf(\"[WSc] get pong\\n\");\r\n      break;\r\n  }\r\n}\r\n\r\nvoid setup() {\r\n  // Serial.begin(921600);\r\n  Serial.begin(9600);\r\n\r\n  WiFi.begin(\"webserver\", \"www.nobiggie.cn\");\r\n\r\n  while (WiFi.status() != WL_CONNECTED) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n  }\r\n   Serial.printf(\"wifi OK\");\r\n  // server address, port and URL\r\n  webSocket.begin(\"192.168.0.254\", 80, \"/websocket\");\r\n\r\n  // event handler\r\n  webSocket.onEvent(webSocketEvent);\r\n\r\n  // use HTTP Basic Authorization this is optional remove if not needed\r\n  webSocket.setAuthorization(\"user=scan&passwd=efghijk&room=scan\");\r\n\r\n  // try ever 5000 again if connection has failed\r\n  webSocket.setReconnectInterval(5000);\r\n\r\n  // start heartbeat (optional)\r\n  // ping server every 15000 ms\r\n  // expect pong from server within 3000 ms\r\n  // consider connection disconnected if pong is not received 2 times\r\n  webSocket.enableHeartbeat(15000, 3000, 2);\r\n}\r\n\r\nvoid loop() {\r\n  webSocket.loop();\r\n  if (Serial.available()) {\r\n    while (Serial.available()) {\r\n      String receivedString = Serial.readStringUntil(\'\\n\');  // 读取直到遇到换行符\r\n      webSocket.sendTXT(receivedString);\r\n    }\r\n  }\r\n}\r\nvoid update_started() {\r\n  Serial.println(\"CALLBACK:  HTTP update process started\");\r\n}\r\n\r\nvoid update_finished() {\r\n  Serial.println(\"CALLBACK:  HTTP update process finished\");\r\n}\r\nvoid update_progress(int cur, int total) {\r\n  Serial.printf(\"CALLBACK:  HTTP update process at %d of %d bytes...\\n\", cur, total);\r\n}\r\n\r\nvoid update_error(int err) {\r\n  Serial.printf(\"CALLBACK:  HTTP update fatal error code %d\\n\", err);\r\n}\r\n','',1),
(232,3,'date转time时间戳','	// 获取当前 UTC 时间保证UTC一样, 不然解析出来不准\r\n	nowP := time.Now().UTC()\r\n	timeStr := nowP.Format(\"2006-01-02 15:04:05\")\r\n	layout := \"2006-01-02 15:04:05\"\r\n\r\n	loc, _ := time.LoadLocation(\"UTC\")\r\n	t, err := time.ParseInLocation(layout, timeStr, loc)\r\n	if err != nil {\r\n		fmt.Println(\"解析时间错误:\", err)\r\n		return\r\n	}\r\n	old := t.Unix()\r\n	now := time.Now().UTC().Unix()\r\n	fmt.Println(old)\r\n	fmt.Println(now)','',1),
(233,3,'协程互斥锁','map 全局变量 如果不加锁,会产生抢夺全局变量报错\r\n\r\nvar mutex sync.Mutex //互斥锁 防止开启协程后 同时1个以上协程同时抢占全局变量报错\r\n// 互斥锁 变成非协程\r\nmutex.Lock //锁上\r\n协程都变成列队\r\nmutex.UnLock //解锁\r\n\r\nlock.Lock()\r\nfor i := 0; i < 1000; i++ {\r\n	globalVariable[\"root\"]++\r\n}\r\nlock.Unlock()\r\n上面代码等同于\r\nfor i := 0; i < 1000; i++ {\r\n	lock.Lock()\r\n	globalVariable[\"root\"]++\r\n	lock.Unlock()\r\n}\r\n\r\n\r\n//主要应用 于商品抢购 可以读并发协程，写锁列队\r\nvar mutex sync.RWMutex\r\n//RWMutex可以mutex.Lock //锁上\r\n//协程都变成列队，写时不能读\r\n//mutex.UnLock //解锁\r\nmutex.RLock()\r\n并发协程读操作 特别注意 这里不是协程都变成列队\r\n读时不能写\r\nmutex.RUnlock()\r\n\r\n','',1),
(236,1,'服务器有线固定ip设置','sudo vi /etc/dhcpcd.conf\r\ninterface eth0\r\nstatic ip_address=192.168.x.x/24\r\nstatic routers=192.168.x.x\r\nstatic domain_name_servers=192.168.x.x\r\n//如果是通过无线连接，可以将  interface eth0  改为  interface wlan0\r\n//1. 可以使用命令  sudo service dhcpcd restart  重启网络服务。\r\n2. 或者直接重启树莓派，使用命令  sudo reboot 。\r\n\r\n新版树莓派需要使用nmcli 你可以使用 nmcli con show 命令列出所有的网络连接\r\nnmcli con modify \"Wired connection 1\" ipv4.addresses 192.168.1.254/24\r\nnmcli con modify \"Wired connection 1\" ipv4.gateway 192.168.1.1\r\nnmcli con modify \"Wired connection 1\" ipv4.dns \"8.8.8.8,8.8.4.4\"\r\nnmcli con modify \"Wired connection 1\" ipv4.method manual\r\n请根据你的网络环境替换上述命令中的IP地址、网关和DNS服务器地址。如果你需要设置动态IP（即DHCP），可以将 ipv4.method 设置为 auto 而不是 manual','',1),
(237,1,'wifi连接路由器设置','一、配置无线网络\r\n使用 sudo nano /etc/wpa_supplicant/wpa_supplicant.conf 命令打开无线网络配置文件。\r\n在文件中添加以下内容：\r\n\r\nnetwork={\r\n    ssid=\"你的无线网络名称\"\r\n    psk=\"你的无线网络密码\"\r\n}\r\n\r\n二、设置网络优先级\r\n创建一个名为 /etc/network/interfaces.d/wlan0.cfg 的文件，用于配置无线网络接口：\r\n\r\nallow-hotplug wlan0\r\niface wlan0 inet dhcp\r\nwpa-conf /etc/wpa_supplicant/wpa_supplicant.conf\r\n修改 /etc/network/interfaces 文件，添加以下内容：\r\n\r\nsource-directory /etc/network/interfaces.d\r\n\r\n执行 sudo service networking restart 命令重启网络服务，使配置生效','',1),
(241,1,'docker','docker run -d --name mynginx -p 8080:80 nginx\r\ndocker exec -it mynginx /bin/bash  //进入docker内部\r\n//保存镜像\r\ndocker commit -a xyz -m \"名字\"\r\ndocker save -o mynginx.tar mynginx:v1.0\r\ndocker load -i mynginx.tar //导入镜像\r\n//挂载\r\ndocker run -d --name mynginx -p 8080:80 -v /var/www/html:/docker内部目录 nginx\r\n-v /var/www/html:/docker内部目录\r\n//分享社区\r\ndocker login\r\n\r\ndocker tag myngin:v1.0 账号/mynginx:v2.0 更改名字版本\r\n\r\n\r\n\r\n','',1),
(242,1,'无法启动无线','在终端中运行 rfkill list，查看所有被禁用的无线设备列表。如果 wlan0 被列出并显示为 Soft blocked: yes（软件禁用）或 Hard blocked: yes（硬件禁用），则需要解除禁用。\r\n sudo rfkill unblock wlan\r\n这将尝试解除对无线设备的软件禁用\r\n禁用的方法\r\n     sudo rfkill block wlan','',1),
(243,1,'关闭窗口 后台 apt install ','nohup apt install xxxx -y &\r\n使用ps aux | grep apt命令查看所有进程中包含 “apt” 关键字的进程','',1),
(244,4,'快递CAM','#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <ArduinoJson.h>\r\n#include <WebSocketsClient.h>\r\n#include <WebServer.h>\r\n#include <HTTPClient.h>\r\n#include <HTTPUpdate.h>\r\n#include \"esp_camera.h\"\r\nString version = \"1.0\";\r\nDynamicJsonDocument jsonBuffer(100);\r\nJsonObject jsonArr;\r\n\r\nWebSocketsClient webSocket;\r\n\r\nWiFiClient wificlient;\r\nString localServerIP = \"192.168.0.254\";\r\nString upBinUrl = \"http://\" + localServerIP + \"/tool/ota/englishgolangcpp/dkcam.bin\";\r\n// 图像缓冲区大小\r\nconst int bufferSize = 1024 * 10;\r\nuint8_t buffer[bufferSize];\r\nString ssid = \"webserver\";                                             //wifi账号\r\nString passwd = \"www.nobiggie.cn\";                                           //wifi密码\r\n\r\nvoid hexdump(const void* mem, uint32_t len, uint8_t cols = 16) {\r\n  const uint8_t* src = (const uint8_t*)mem;\r\n  Serial.printf(\"\\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)\", (ptrdiff_t)src, len, len);\r\n  for (uint32_t i = 0; i < len; i++) {\r\n    if (i % cols == 0) {\r\n      Serial.printf(\"\\n[0x%08X] 0x%08X: \", (ptrdiff_t)src, i);\r\n    }\r\n    Serial.printf(\"%02X \", *src);\r\n    src++;\r\n  }\r\n  Serial.printf(\"\\n\");\r\n}\r\n\r\nvoid webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {\r\n\r\n  switch (type) {\r\n    case WStype_DISCONNECTED:\r\n      break;\r\n    case WStype_CONNECTED:\r\n      Serial.printf(\"[WSc] Connected to url: %s\\n\", payload);\r\n      break;\r\n    case WStype_TEXT:\r\n      Serial.printf(\"[WSc] get text: %s\\n\", payload);\r\n      deserializeJson(jsonBuffer, payload);\r\n      jsonArr = jsonBuffer.as<JsonObject>();\r\n      if (jsonArr[\"message\"] != \"\") {\r\n        String user = jsonArr[\"user\"];\r\n        String date = jsonArr[\"date\"];\r\n        String message = jsonArr[\"message\"];\r\n        if (message == \"picture\") {\r\n          // 拍照并发送图片\r\n          camera_fb_t* fb = esp_camera_fb_get();\r\n          if (!fb) {\r\n            Serial.println(\"Failed to take picture\");\r\n            return;\r\n          }\r\n          size_t jpegSize = fb->len;\r\n          memcpy(buffer, fb->buf, jpegSize);\r\n          esp_camera_fb_return(fb);\r\n\r\n          WiFiClient client;\r\n          if (!client.connect(localServerIP.c_str(),80)) {\r\n            Serial.println(\"Connection failed\");\r\n            return;\r\n          }\r\n\r\n          // 构造 HTTP 请求头\r\n          client.printf(\"POST /dkimage HTTP/1.1\\r\\n\");\r\n          client.printf(\"Host: %s\\r\\n\", localServerIP);\r\n          client.printf(\"Content-Type: image/jpeg\\r\\n\");\r\n          client.printf(\"Content-Length: %d\\r\\n\", jpegSize);\r\n          client.printf(\"\\r\\n\");\r\n\r\n          // 发送图片数据\r\n          client.write(buffer, jpegSize);\r\n          client.flush();\r\n\r\n          Serial.println(\"Image sent\");\r\n        }\r\n        if (message == \"updateBin\") {\r\n          while (1) {\r\n            httpUpdate.onStart(update_started);\r\n            httpUpdate.onEnd(update_finished);\r\n            httpUpdate.onProgress(update_progress);\r\n            httpUpdate.onError(update_error);\r\n            t_httpUpdate_return ret = httpUpdate.update(wificlient, upBinUrl);\r\n            //t_httpUpdate_return ret = httpUpdate.update(wificlient, \"server\", 80, \"/file.bin\");\r\n            switch (ret) {\r\n              case HTTP_UPDATE_FAILED:\r\n                Serial.printf(\"HTTP_UPDATE_FAILED Error (%d): %s\\n\", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str());\r\n                break;\r\n              case HTTP_UPDATE_NO_UPDATES:\r\n                Serial.println(\"HTTP_UPDATE_NO_UPDATES\");\r\n                break;\r\n              case HTTP_UPDATE_OK:\r\n                Serial.println(\"HTTP_UPDATE_OK\");\r\n                break;\r\n            }\r\n          }\r\n          espReboot();\r\n        }\r\n      }\r\n      // send message to server\r\n      // webSocket.sendTXT(\"message here\");\r\n      break;\r\n    case WStype_BIN:\r\n      //语音是以 []byte 传输\r\n      Serial.printf(\"[WSc] get binary length: %u\\n\", length);\r\n      break;\r\n    case WStype_ERROR:\r\n    case WStype_FRAGMENT_TEXT_START:\r\n    case WStype_FRAGMENT_BIN_START:\r\n    case WStype_FRAGMENT:\r\n    case WStype_FRAGMENT_FIN:\r\n      break;\r\n  }\r\n}\r\n\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  // 设置相机\r\n  camera_config_t config;\r\n  config.ledc_channel = LEDC_CHANNEL_0;\r\n  config.ledc_timer = LEDC_TIMER_0;\r\n  config.pin_d0 = 5;\r\n  config.pin_d1 = 18;\r\n  config.pin_d2 = 19;\r\n  config.pin_d3 = 21;\r\n  config.pin_d4 = 36;\r\n  config.pin_d5 = 39;\r\n  config.pin_d6 = 34;\r\n  config.pin_d7 = 35;\r\n  config.pin_xclk = 0;\r\n  config.pin_pclk = 22;\r\n  config.pin_vsync = 25;\r\n  config.pin_href = 23;\r\n  config.pin_sscb_sda = 26;\r\n  config.pin_sscb_scl = 27;\r\n  config.pin_pwdn = 32;\r\n  config.pin_reset = -1;\r\n  config.xclk_freq_hz = 20000000;\r\n  config.pixel_format = PIXFORMAT_JPEG;\r\n\r\n  // 初始化相机\r\n  esp_err_t err = esp_camera_init(&config);\r\n  if (err != ESP_OK) {\r\n    Serial.printf(\"Camera init failed with error 0x%x\", err);\r\n    return;\r\n  }\r\n  delay(300);\r\n  // 连接 Wi-Fi\r\n  WiFi.begin(\"webserver\", \"www.nobiggie.cn\");\r\n  while (WiFi.status() != WL_CONNECTED) {\r\n    delay(1000);\r\n    Serial.println(\"Connecting to WiFi...\");\r\n  }\r\n  Serial.println(\"Connected to WiFi\");\r\n  //通知服务器 我正在重启,验证一下广告牌开关状态 10秒后我启动完成发送广告牌开关状态给我\r\n  webSocket.begin(localServerIP, 80, \"/websocket\");\r\n  webSocket.onEvent(webSocketEvent);\r\n  webSocket.setAuthorization(\"user=esp32camkd&passwd=efghijk&room=admin\");\r\n  webSocket.setReconnectInterval(5000);\r\n}\r\nvoid loop() {\r\n  webSocket.loop();\r\n}\r\n\r\nvoid espReboot() {\r\n  ESP.restart();\r\n}\r\n\r\nString esp32post(String url) {\r\n  HTTPClient http;\r\n  http.begin(wificlient, url);\r\n  http.setTimeout(3000);\r\n  String postStr = \"version=esp32test10\";\r\n  char dataBuff[postStr.length()];\r\n  strcpy(dataBuff, postStr.c_str());\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  int httpResponseCode = http.POST(dataBuff);\r\n  if (httpResponseCode > 0) {\r\n    String response = http.getString();\r\n    return response;\r\n  }\r\n  return \"\";\r\n}\r\n\r\n\r\n\r\n//当升级开始时，打印日志\r\nvoid update_started() {\r\n  Serial.println(\"CALLBACK: HTTP update process started\");\r\n}\r\n//当升级结束时，打印日志\r\nvoid update_finished() {\r\n  Serial.println(\"CALLBACK: HTTP update process finished\");\r\n}\r\n//当升级中，打印日志\r\nvoid update_progress(int cur, int total) {\r\n  Serial.printf(\"CALLBACK: HTTP update process at %d of %d bytes...\\n\", cur, total);\r\n}\r\n//当升级失败时，打印日志\r\nvoid update_error(int err) {\r\n  Serial.printf(\"CALLBACK: HTTP update fatal error code %d\\n\", err);\r\n}\r\n','',1),
(245,4,'NodeMCU ESP32s 彩灯带变色，闪烁，亮度 ','#include <FastLED.h>\r\n\r\n#define TOUCH_PIN_BRIGHTNESS 13  // 触摸引脚13用于亮度调节\r\n#define TOUCH_PIN_FLASH 12       // 触摸引脚12用于闪烁模式切换\r\n#define TOUCH_PIN_COLOR 14       // 触摸引脚14用于彩带颜色切换\r\n#define LED_PIN 2                // LED串连接的引脚\r\n#define NUM_LEDS 30              // LED数量\r\nint mycolor = 0;\r\nCRGB leds[NUM_LEDS];      // 用于存储LED颜色数据的数组\r\nbool isFlashing = false;  // 闪烁模式标志\r\n                          //touch 最大65  手摸20以下 但是运行环境 触摸达不到20以下,20-50间,应该设置为50\r\nconst int ConstTouch = 50;\r\nvoid setup() {\r\n  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);  // 初始化LED串\r\n  pinMode(TOUCH_PIN_BRIGHTNESS, INPUT);                   // 设置触摸引脚为输入\r\n  pinMode(TOUCH_PIN_FLASH, INPUT);\r\n  pinMode(TOUCH_PIN_COLOR, INPUT);\r\n}\r\n\r\nvoid loop() {\r\n  int lhdu = touchRead(TOUCH_PIN_BRIGHTNESS);\r\n  delay(300);\r\n  // 亮度调节\r\n  if (lhdu < ConstTouch) {\r\n    if (FastLED.getBrightness() > 250) {\r\n      FastLED.setBrightness(50);\r\n    }\r\n    FastLED.setBrightness(FastLED.getBrightness() + 50);  // 增加亮度\r\n    delay(100);\r\n  }\r\n\r\n  // 闪烁模式切换\r\n  int sjuo = touchRead(TOUCH_PIN_FLASH);\r\n  delay(300);\r\n  if (sjuo < ConstTouch) {\r\n    isFlashing = !isFlashing;  // 切换闪烁模式状态\r\n    delay(100);\r\n  }\r\n\r\n  // 彩带颜色切换\r\n  int bmse = touchRead(TOUCH_PIN_COLOR);\r\n  delay(300);\r\n  if (bmse < ConstTouch) {\r\n    mycolor++;\r\n    if (mycolor > 2) {\r\n      mycolor = 0;\r\n    }\r\n    if (mycolor == 0) {\r\n      fill_solid(leds, NUM_LEDS, CRGB(CHSV(0, 255, 255)));  // 红色\r\n    }\r\n    if (mycolor == 1) {\r\n      fill_solid(leds, NUM_LEDS, CRGB(CHSV(85, 255, 255)));\r\n    }\r\n    if (mycolor == 2) {\r\n      fill_solid(leds, NUM_LEDS, CRGB(CHSV(170, 255, 255)));\r\n    }\r\n    // 这里可以添加切换不同颜色的逻辑\r\n    delay(100);\r\n  }\r\n\r\n  if (isFlashing) {\r\n    static bool state = false;\r\n    state = !state;\r\n    fill_solid(leds, NUM_LEDS, state ? CRGB::Black : CRGB(CHSV(100, 255, 255)));  // 闪烁效果\r\n    if (mycolor == 0) {\r\n      fill_solid(leds, NUM_LEDS, state ? CRGB::Black : CRGB(CHSV(0, 255, 255)));\r\n    }\r\n    if (mycolor == 1) {\r\n      fill_solid(leds, NUM_LEDS, state ? CRGB::Black : CRGB(CHSV(85, 255, 255)));\r\n    }\r\n    if (mycolor == 2) {\r\n      fill_solid(leds, NUM_LEDS, state ? CRGB::Black : CRGB(CHSV(170, 255, 255)));\r\n    }\r\n  } else {\r\n    // 常亮颜色\r\n    if (mycolor == 0) {\r\n      fill_solid(leds, NUM_LEDS, CRGB(CHSV(0, 255, 255)));  // 红色\r\n    }\r\n    if (mycolor == 1) {\r\n      fill_solid(leds, NUM_LEDS, CRGB(CHSV(85, 255, 255)));\r\n    }\r\n    if (mycolor == 2) {\r\n      fill_solid(leds, NUM_LEDS, CRGB(CHSV(170, 255, 255)));\r\n    }\r\n  }\r\n\r\n  FastLED.show();  // 显示当前颜色\r\n  delay(10);       // 延时以避免CPU过载\r\n}','',1),
(246,4,'esp32cam','开发板选用 ESP32 Wrover Module\r\n示例代码 -> ESP32 -> Camera -> WebServer\r\n\r\n注释 #define CAMERA_MODEL_ESP_EYE\r\n取消注释 #define CAMERA_MODEL_AI_THINKER\r\n111行改成 if (s->id.PID == OV2640_PID) {','',1),
(247,4,'esp32cam访问IP返回抓拍图片','#include \"esp_camera.h\"\r\n#include <WiFi.h>\r\n\r\n// Wi-Fi 连接信息\r\nconst char *ssid = \"webserver\";\r\nconst char *password = \"www.nobiggie.cn\";\r\n\r\n// 定义摄像头模块\r\n#define CAMERA_MODEL_AI_THINKER\r\n\r\n// 摄像头引脚定义\r\n#if defined(CAMERA_MODEL_AI_THINKER)\r\n#define PWDN_GPIO_NUM 32\r\n#define RESET_GPIO_NUM -1\r\n#define XCLK_GPIO_NUM 0\r\n#define SIOD_GPIO_NUM 26\r\n#define SIOC_GPIO_NUM 27\r\n#define Y9_GPIO_NUM 35\r\n#define Y8_GPIO_NUM 34\r\n#define Y7_GPIO_NUM 39\r\n#define Y6_GPIO_NUM 36\r\n#define Y5_GPIO_NUM 21\r\n#define Y4_GPIO_NUM 19\r\n#define Y3_GPIO_NUM 18\r\n#define Y2_GPIO_NUM 5\r\n#define VSYNC_GPIO_NUM 25\r\n#define HREF_GPIO_NUM 23\r\n#define PCLK_GPIO_NUM 22\r\n#endif\r\n\r\n// 摄像头配置\r\ncamera_config_t camera_config = {\r\n   .pin_pwdn = PWDN_GPIO_NUM,\r\n   .pin_reset = RESET_GPIO_NUM,\r\n   .pin_xclk = XCLK_GPIO_NUM,\r\n   .pin_sscb_sda = SIOD_GPIO_NUM,\r\n   .pin_sscb_scl = SIOC_GPIO_NUM,\r\n   .pin_d7 = Y9_GPIO_NUM,\r\n   .pin_d6 = Y8_GPIO_NUM,\r\n   .pin_d5 = Y7_GPIO_NUM,\r\n   .pin_d4 = Y6_GPIO_NUM,\r\n   .pin_d3 = Y5_GPIO_NUM,\r\n   .pin_d2 = Y4_GPIO_NUM,\r\n   .pin_d1 = Y3_GPIO_NUM,\r\n   .pin_d0 = Y2_GPIO_NUM,\r\n   .pin_vsync = VSYNC_GPIO_NUM,\r\n   .pin_href = HREF_GPIO_NUM,\r\n   .pin_pclk = PCLK_GPIO_NUM,\r\n   .xclk_freq_hz = 20000000,\r\n   .ledc_timer = LEDC_TIMER_0,\r\n   .ledc_channel = LEDC_CHANNEL_0,\r\n   .pixel_format = PIXFORMAT_JPEG,\r\n   .frame_size =FRAMESIZE_UXGA,//FRAMESIZE_VAG,\r\n   .jpeg_quality = 12,\r\n   .fb_count = 1\r\n};\r\n\r\nvoid startCameraServer() {\r\n    WiFiServer server(80);\r\n    WiFi.begin(ssid, password);\r\n\r\n    while (WiFi.status()!= WL_CONNECTED) {\r\n        delay(1000);\r\n        Serial.println(\"Connecting to WiFi...\");\r\n    }\r\n    Serial.println(\"Connected to WiFi\");\r\n    Serial.println(WiFi.localIP());\r\n\r\n    server.begin();\r\n\r\n    while (true) {\r\n        WiFiClient client = server.available();\r\n        if (client) {\r\n            Serial.println(\"New client connected\");\r\n            String currentLine = \"\";\r\n            while (client.connected()) {\r\n                if (client.available()) {\r\n                    char c = client.read();\r\n                    Serial.write(c);\r\n                    if (c == \'\\n\') {\r\n                        if (currentLine.length() == 0) {\r\n                            // 发送 HTTP 响应头\r\n                            client.println(\"HTTP/1.1 200 OK\");\r\n                            client.println(\"Content-Type: image/jpeg\");\r\n                            client.println(\"Connection: close\");\r\n                            client.println();\r\n\r\n                            // 获取摄像头图像并发送\r\n                            camera_fb_t *fb = esp_camera_fb_get();\r\n                            esp_camera_fb_return(fb); //清空一下，防止下次还是这个图片\r\n                            fb = esp_camera_fb_get();\r\n                            if (fb) {\r\n                                client.write(fb->buf, fb->len);\r\n                                esp_camera_fb_return(fb);\r\n                            }\r\n                            break;\r\n                        } else {\r\n                            currentLine = \"\";\r\n                        }\r\n                    } else if (c!= \'\\r\') {\r\n                        currentLine += c;\r\n                    }\r\n                }\r\n            }\r\n            client.stop();\r\n            Serial.println(\"Client disconnected\");\r\n        }\r\n    }\r\n}\r\n\r\nvoid setup() {\r\n    Serial.begin(115200);\r\n    // 初始化摄像头\r\n    esp_err_t err = esp_camera_init(&camera_config);\r\n    if (err!= ESP_OK) {\r\n        Serial.println(\"Camera init failed\");\r\n        return;\r\n    }\r\n    Serial.println(\"Camera init ok\");\r\n    startCameraServer();\r\n}\r\n\r\nvoid loop() {\r\n    // 无需在 loop 中执行其他操作，因为服务器在 setup 中的 while (true) 循环中持续运行\r\n}\r\n','',1),
(248,3,'微信机器人','package models\r\n\r\nimport (\r\n	\"fmt\"\r\n	\"io\"\r\n	\"log\"\r\n	\"net/http\"\r\n	\"net/url\"\r\n	\"os\"\r\n	\"regexp\"\r\n	\"strconv\"\r\n	\"strings\"\r\n\r\n	\"github.com/eatmoreapple/openwechat\"\r\n	\"github.com/joho/godotenv\"\r\n	\"github.com/tidwall/gjson\"\r\n)\r\n\r\ntype OpenChatZ struct {\r\n	ExceArr  map[int]string\r\n	Self     *openwechat.Self\r\n	Groups   openwechat.Groups\r\n	KdNumber int\r\n}\r\n\r\nfunc (ggg *OpenChatZ) Setup() *OpenChatZ {\r\n	ggg.ExceArr = map[int]string{\r\n		0: \"查物流\",\r\n		1: \"拦截\",\r\n		2: \"改地址\",\r\n		3: \"查重\",\r\n		4: \"催件\",\r\n		5: \"核实签收\",\r\n		6: \"破损\",\r\n		7: \"遗失\",\r\n	}\r\n	return ggg\r\n\r\n}\r\nfunc (ggg *OpenChatZ) hasThirteenConsecutiveDigits(s string) bool {\r\n	// 定义匹配连续13位数字的正则表达式\r\n	pattern := regexp.MustCompile(`\\d{13}`)\r\n	return pattern.MatchString(s)\r\n}\r\n\r\n/*\r\n*\r\n去除html标签，过滤html标签\r\n*/\r\nfunc (ggg *OpenChatZ) TrimHtml(src string) string {\r\n	//将HTML标签全转换成小写\r\n	re, _ := regexp.Compile(\"\\\\<[\\\\S\\\\s]+?\\\\>\")\r\n	src = re.ReplaceAllStringFunc(src, strings.ToLower)\r\n	//去除STYLE\r\n	re, _ = regexp.Compile(\"\\\\<style[\\\\S\\\\s]+?\\\\</style\\\\>\")\r\n	src = re.ReplaceAllString(src, \"\")\r\n	//去除SCRIPT\r\n	re, _ = regexp.Compile(\"\\\\<script[\\\\S\\\\s]+?\\\\</script\\\\>\")\r\n	src = re.ReplaceAllString(src, \"\")\r\n	//去除所有尖括号内的HTML代码，并换成换行符\r\n	re, _ = regexp.Compile(\"\\\\<[\\\\S\\\\s]+?\\\\>\")\r\n	src = re.ReplaceAllString(src, \"\\n\")\r\n	//去除连续的换行符\r\n	re, _ = regexp.Compile(\"\\\\s{2,}\")\r\n	src = re.ReplaceAllString(src, \"\\n\")\r\n	return strings.TrimSpace(src)\r\n}\r\n\r\n// 发送http post请求数据为form\r\nfunc (ggg *OpenChatZ) PostForm(url string, data url.Values) (string, error) {\r\n	resp, err := http.PostForm(url, data)\r\n	if err != nil {\r\n		return \"\", err\r\n	}\r\n	defer resp.Body.Close()\r\n	content, err := io.ReadAll(resp.Body)\r\n	if err != nil {\r\n		return \"\", err\r\n	}\r\n	return string(content), nil\r\n}\r\nfunc (ggg *OpenChatZ) SendTextGroupZ(groupName, msg string) {\r\n	// 遍历群组，找到目标群并发送消息\r\n	for _, group := range ggg.Groups {\r\n		fmt.Println(group.NickName)\r\n		if group.NickName == groupName {\r\n			// 发送文本消息\r\n			_, err := ggg.Self.SendTextToGroup(group, msg)\r\n			if err != nil {\r\n				fmt.Println(\"发送消息失败：\", err)\r\n			}\r\n		}\r\n	}\r\n}\r\nfunc (ggg *OpenChatZ) Start() {\r\n\r\n	err := godotenv.Load(\".env\")\r\n	myUID := \"\"\r\n	myNicname := \"\"\r\n\r\n	// 读取环境变量\r\n	api := os.Getenv(\"API_BASE\")\r\n	entId := os.Getenv(\"API_ENT_ID\")\r\n	replyType := os.Getenv(\"REPLY_TYPE\")\r\n	bot := openwechat.DefaultBot(openwechat.Desktop) // 桌面模式\r\n\r\n	// 注册消息处理函数\r\n	bot.MessageHandler = func(msg *openwechat.Message) {\r\n\r\n		if msg.IsText() {\r\n\r\n			log.Printf(\"收到消息：%s\\n\", msg.Content)\r\n\r\n			isSend := false\r\n			//群聊\r\n			if msg.IsSendByGroup() {\r\n				sender, err := msg.SenderInGroup()\r\n				if err == nil {\r\n					log.Println(\"消息发送者：\" + sender.NickName)\r\n				}\r\n				if strings.Contains(msg.Content, \"@\"+myNicname) {\r\n					msg.Content = strings.TrimSpace(strings.ReplaceAll(msg.Content, \"@\"+myNicname, \"\"))\r\n					isSend = true\r\n				} else {\r\n					isSend = false\r\n				}\r\n			} else {\r\n				//单聊\r\n				sender, err := msg.Sender()\r\n				if err == nil {\r\n					log.Println(\"消息发送者：\" + sender.NickName)\r\n				}\r\n				if replyType != \"GROUP\" {\r\n					isSend = true\r\n				}\r\n			}\r\n			//字符串装是否含有13位连续的数字\r\n			if ggg.hasThirteenConsecutiveDigits(msg.Content[0:13]) {\r\n				//如果输入单号错误为14位数字也不会触发\r\n				_, errInt := strconv.Atoi(msg.Content[13:14])\r\n				if errInt != nil {\r\n					tmpNumber := msg.Content[0:13]\r\n					tmpKdNumber, _ := strconv.Atoi(tmpNumber)\r\n					ggg.KdNumber = tmpKdNumber\r\n					selectTmp := []rune(msg.Content)\r\n					selectStr := string(selectTmp[0:22])\r\n					for _, v := range ggg.ExceArr {\r\n						if strings.Contains(selectStr, v) {\r\n							if v == \"查物流\" {\r\n								// 遍历群组，找到目标群并发送消息\r\n								ggg.SendTextGroupZ(\"群快递机器人助手研发\", \"接收到\"+tmpNumber+\" \"+v+\" 指令,准备执行命令\")\r\n								break\r\n							}\r\n							if v == \"拦截\" {\r\n								// 遍历群组，找到目标群并发送消息\r\n								ggg.SendTextGroupZ(\"群快递机器人助手研发\", \"接收到\"+tmpNumber+\" \"+v+\" 指令,准备执行命令\")\r\n								break\r\n							}\r\n							if v == \"改地址\" {\r\n								// 遍历群组，找到目标群并发送消息\r\n								ggg.SendTextGroupZ(\"群快递机器人助手研发\", \"接收到\"+tmpNumber+\" \"+v+\" 指令,准备执行命令\")\r\n								break\r\n							}\r\n							if v == \"查重\" {\r\n								// 遍历群组，找到目标群并发送消息\r\n								ggg.SendTextGroupZ(\"群快递机器人助手研发\", \"接收到\"+tmpNumber+\" \"+v+\" 指令,准备执行命令\")\r\n								break\r\n							}\r\n							if v == \"催件\" {\r\n								// 遍历群组，找到目标群并发送消息\r\n								ggg.SendTextGroupZ(\"群快递机器人助手研发\", \"接收到\"+tmpNumber+\" \"+v+\" 指令,准备执行命令\")\r\n								break\r\n							}\r\n							if v == \"核实签收\" {\r\n								// 遍历群组，找到目标群并发送消息\r\n								ggg.SendTextGroupZ(\"群快递机器人助手研发\", \"接收到\"+tmpNumber+\" \"+v+\" 指令,准备执行命令\")\r\n								break\r\n							}\r\n							if v == \"破损\" {\r\n								// 遍历群组，找到目标群并发送消息\r\n								ggg.SendTextGroupZ(\"群快递机器人助手研发\", \"接收到\"+tmpNumber+\" \"+v+\" 指令,准备执行命令\")\r\n								break\r\n							}\r\n							if v == \"遗失\" {\r\n								// 遍历群组，找到目标群并发送消息\r\n								ggg.SendTextGroupZ(\"群快递机器人助手研发\", \"接收到\"+tmpNumber+\" \"+v+\" 指令,准备执行命令\")\r\n								break\r\n							}\r\n\r\n						}\r\n					}\r\n				}\r\n			}\r\n			if isSend {\r\n				data := url.Values{}\r\n				data.Set(\"ent_id\", entId)\r\n				data.Set(\"visitor_id\", msg.MsgId)\r\n				data.Set(\"content\", msg.Content)\r\n				res, err := ggg.PostForm(api, data)\r\n				if err == nil {\r\n					r := gjson.Get(res, \"result.content\").String()\r\n					r = ggg.TrimHtml(r)\r\n					msg.ReplyText(r)\r\n				}\r\n			}\r\n\r\n		}\r\n	}\r\n	// 注册登陆二维码回调\r\n	bot.UUIDCallback = openwechat.PrintlnQrcodeUrl\r\n\r\n	// 登陆\r\n	if err := bot.Login(); err != nil {\r\n		fmt.Println(err)\r\n		return\r\n	}\r\n\r\n	// 获取登陆的用户\r\n	selfs, err := bot.GetCurrentUser()\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		return\r\n	}\r\n	ggg.Self = selfs\r\n	// 获取所有的群组\r\n\r\n	group, err := ggg.Self.Groups()\r\n	fmt.Println(group.Count())\r\n	if err != nil {\r\n		fmt.Println(err)\r\n		return\r\n	}\r\n	ggg.Groups = group\r\n	// 遍历群组列表并打印群组名称和ID\r\n	for _, vv := range ggg.Groups {\r\n		fmt.Printf(\"群组名称: %s, 群组ID: %d\\n\", vv.NickName, vv.ID)\r\n	}\r\n\r\n	myUID = string(ggg.Self.ID())\r\n	myNicname = ggg.Self.NickName\r\n	log.Printf(\"当前登录用户：%s,uid：%s \\n\", myNicname, myUID)\r\n	// 获取所有的好友\r\n	//friends, err := self.Friends()\r\n	//fmt.Println(friends, err)\r\n\r\n	// 获取所有的群组\r\n	//groups, err := self.Groups()\r\n	//fmt.Println(groups, err)\r\n\r\n	// 阻塞主goroutine, 直到发生异常或者用户主动退出\r\n	bot.Block()\r\n\r\n}\r\n','',1),
(249,4,'180旋转超声波雷达','#include <Servo.h>\r\n#include <SPI.h>\r\n#include \"Ucglib.h\"\r\n\r\n#define trigPin 6\r\n#define echoPin 5\r\n#define ServoPin 3\r\nint Ymax = 240;\r\nint Xmax = 320;\r\nint D2 = 2;\r\nint Xcent = Xmax / 2;\r\nint base = 210;\r\nint scanline = 185;\r\n\r\nServo baseServo;\r\n//Ucglib_ILI9341_18x240x320_SWSPI ucg(/*sclk=*/ 13, /*data=*/ 11, /*cd=*/ 9, /*cs=*/ 10, /*reset=*/ 8);\r\nUcglib_ILI9341_18x240x320_HWSPI ucg(/*cd=*/9, /*cs=*/10, /*reset=*/8);\r\n\r\nvoid setup(void) {\r\n  ucg.begin(UCG_FONT_MODE_SOLID);\r\n  ucg.setRotate90();\r\n\r\n  pinMode(trigPin, OUTPUT);\r\n  pinMode(echoPin, INPUT);\r\n  Serial.begin(115200);\r\n  pinMode(D2, OUTPUT);\r\n  digitalWrite(D2, LOW);\r\n  baseServo.attach(ServoPin);\r\n\r\n\r\n  ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);\r\n  ucg.setColor(0, 0, 0, 0);\r\n  ucg.setColor(1, 0, 0, 0);\r\n  ucg.setColor(2, 0, 0, 0);\r\n  ucg.setColor(3, 0, 0, 0);\r\n  ucg.drawGradientBox(0, 0, 320, 240);\r\n  ucg.setPrintDir(0);\r\n  ucg.setColor(0, 5, 0);\r\n  ucg.setPrintPos(70, 120);\r\n  ucg.setFont(ucg_font_logisoso32_tf);\r\n  ucg.print(\"Mini Radar\");\r\n  ucg.setColor(0, 255, 0);\r\n  ucg.setPrintPos(70, 120);\r\n  ucg.print(\"Mini Radar\");\r\n  ucg.setFont(ucg_font_courB14_tf);\r\n  ucg.setColor(20, 255, 20);\r\n  ucg.setPrintPos(90, 200);\r\n  ucg.print(\"Testing...\");\r\n  baseServo.write(90);\r\n\r\n\r\n  for (int x = 0; x < 180; x += 5) {\r\n    baseServo.write(x);\r\n    delay(50);\r\n  }\r\n  ucg.print(\"OK!\");\r\n  delay(500);\r\n  ucg.setColor(0, 0, 0, 0);\r\n  ucg.setColor(1, 0, 0, 0);\r\n  ucg.setColor(2, 0, 0, 0);\r\n  ucg.setColor(3, 0, 0, 0);\r\n  ucg.drawGradientBox(0, 0, 320, 240);\r\n  delay(10);\r\n\r\n\r\n  //ucg.clearScreen();\r\n  cls();\r\n  ucg.setFontMode(UCG_FONT_MODE_SOLID);\r\n  ucg.setFont(ucg_font_helvR08_hr);  // or freedoomr10_tr\r\n}\r\n\r\nvoid cls() {\r\n\r\n  ucg.setColor(0, 0, 0, 0);\r\n  for (int s = 0; s < 240; s++) {\r\n    ucg.drawHLine(0, s, 320);\r\n    delay(1);\r\n  }\r\n\r\n  //ucg.drawBox(0, 0, 160, 60);\r\n}\r\n\r\nint calculateDistance() {\r\n  long duration;\r\n\r\n  digitalWrite(trigPin, LOW);\r\n  delayMicroseconds(2);\r\n\r\n  digitalWrite(trigPin, HIGH);\r\n  delayMicroseconds(10);\r\n  digitalWrite(trigPin, LOW);\r\n\r\n  duration = pulseIn(echoPin, HIGH);\r\n\r\n  return duration * 0.034 / 2;\r\n}\r\n\r\nvoid fix_font() {\r\n  ucg.setColor(0, 180, 0);\r\n  ucg.setPrintPos(144, 44);\r\n  ucg.print(\"1.00\");\r\n  ucg.setPrintPos(144, 100);\r\n  ucg.print(\"0.60\");\r\n  ucg.setPrintPos(144, 165);\r\n  ucg.print(\"0.30\");\r\n}\r\n\r\nvoid fix() {\r\n  ucg.setColor(0, 180, 0);\r\n\r\n  ucg.drawDisc(Xcent, base + 1, 3, UCG_DRAW_ALL);\r\n  ucg.drawCircle(Xcent, base + 1, 210, UCG_DRAW_UPPER_LEFT);\r\n  ucg.drawCircle(Xcent, base + 1, 210, UCG_DRAW_UPPER_RIGHT);\r\n  ucg.drawCircle(Xcent, base + 1, 135, UCG_DRAW_UPPER_LEFT);\r\n  ucg.drawCircle(Xcent, base + 1, 135, UCG_DRAW_UPPER_RIGHT);\r\n  ucg.drawCircle(Xcent, base + 1, 70, UCG_DRAW_UPPER_LEFT);\r\n  ucg.drawCircle(Xcent, base + 1, 70, UCG_DRAW_UPPER_RIGHT);\r\n  ucg.drawLine(0, base + 1, Xmax, base + 1);\r\n\r\n  ucg.setColor(0, 180, 0);\r\n\r\n  for (int i = 40; i < 300; i += 2) {\r\n    if (i % 10 == 0)\r\n      ucg.drawLine(185 * cos(radians(i)) + Xcent, base - 185 * sin(radians(i)), 205 * cos(radians(i)) + Xcent, base - 205 * sin(radians(i)));\r\n    else\r\n      ucg.drawLine(195 * cos(radians(i)) + Xcent, base - 195 * sin(radians(i)), 205 * cos(radians(i)) + Xcent, base - 205 * sin(radians(i)));\r\n  }\r\n\r\n  ucg.setColor(0, 200, 0);\r\n  ucg.drawLine(0, 0, 0, 36);\r\n  for (int i = 0; i < 5; i++) {\r\n    ucg.setColor(0, random(200) + 50, 0);\r\n    ucg.drawBox(2, i * 8, random(28) + 3, 6);\r\n  }\r\n\r\n  ucg.setColor(0, 180, 0);\r\n  ucg.drawFrame(292, 0, 28, 28);\r\n  ucg.setColor(0, 60, 0);\r\n  ucg.drawHLine(296, 0, 20);\r\n  ucg.drawVLine(292, 4, 20);\r\n  ucg.drawHLine(296, 52, 20);\r\n  ucg.drawVLine(318, 4, 20);\r\n\r\n  ucg.setColor(0, 220, 0);\r\n  ucg.drawBox(296, 4, 8, 8);\r\n  ucg.drawBox(296, 16, 8, 8);\r\n  ucg.drawBox(308, 16, 8, 8);\r\n  ucg.setColor(0, 100, 0);\r\n  ucg.drawBox(308, 4, 8, 8);\r\n\r\n  ucg.setColor(0, 90, 0);\r\n  ucg.drawTetragon(124, 220, 116, 230, 196, 230, 204, 220);\r\n  ucg.setColor(0, 160, 0);\r\n  ucg.drawTetragon(134, 220, 126, 230, 186, 230, 194, 220);\r\n  ucg.setColor(0, 210, 0);\r\n  ucg.drawTetragon(144, 220, 136, 230, 176, 230, 184, 220);\r\n}\r\n\r\nvoid loop(void) {\r\n\r\n  int distance;\r\n\r\n  fix();\r\n  fix_font();\r\n\r\n  for (int x = 180; x > 4; x -= 2) {\r\n\r\n    baseServo.write(x);\r\n\r\n\r\n    int f = x - 4;\r\n    ucg.setColor(0, 255, 0);\r\n    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));\r\n    f += 2;\r\n    ucg.setColor(0, 128, 0);\r\n    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));\r\n    f += 2;\r\n    ucg.setColor(0, 0, 0);\r\n    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));\r\n    ucg.setColor(0, 200, 0);\r\n\r\n    distance = calculateDistance();\r\n\r\n\r\n    if (distance < 100) {\r\n      if (distance < 30) {\r\n        digitalWrite(D2, HIGH);\r\n      } else {\r\n        digitalWrite(D2, LOW);\r\n      }\r\n      ucg.setColor(255, 255, 0);\r\n      ucg.drawDisc(2.2 * distance * cos(radians(x)) + Xcent, -2.2 * distance * sin(radians(x)) + base, 1, UCG_DRAW_ALL);\r\n    } else {\r\n      digitalWrite(D2, LOW);\r\n      ucg.setColor(255, 255, 0);\r\n      ucg.drawDisc(208 * cos(radians(x)) + Xcent, -208 * sin(radians(x)) + base, 1, UCG_DRAW_ALL);\r\n    }\r\n\r\n\r\n\r\n    Serial.print(x);\r\n    Serial.print(\"    ,   \");\r\n    Serial.println(distance);\r\n\r\n\r\n    if (x > 70 and x < 110) fix_font();\r\n\r\n\r\n    ucg.setColor(255, 255, 0);\r\n    ucg.setPrintPos(20, 230);\r\n    ucg.print(\"DEG: \");\r\n    ucg.setPrintPos(54, 230);\r\n    ucg.print(x);\r\n    ucg.print(\"  \");\r\n    ucg.setPrintPos(240, 230);\r\n    ucg.print(\"     \");\r\n    ucg.print(distance);\r\n    ucg.print(\" cm    \");\r\n  }\r\n  //ucg.clearScreen();\r\n  delay(50);\r\n  cls();\r\n\r\n  fix();\r\n  fix_font();\r\n\r\n  for (int x = 1; x < 176; x += 2) {\r\n    baseServo.write(x);\r\n\r\n\r\n    int f = x + 4;\r\n    ucg.setColor(0, 255, 0);\r\n    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));\r\n    f -= 2;\r\n    ucg.setColor(0, 128, 0);\r\n    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));\r\n    f -= 2;\r\n    ucg.setColor(0, 0, 0);\r\n    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));\r\n    ucg.setColor(0, 200, 0);\r\n\r\n    distance = calculateDistance();\r\n\r\n\r\n    if (distance < 100) {\r\n      if (distance < 30) {\r\n        digitalWrite(D2, HIGH);\r\n      } else {\r\n        digitalWrite(D2, LOW);\r\n      }\r\n      ucg.setColor(255, 255, 0);\r\n      ucg.drawDisc(2.2 * distance * cos(radians(x)) + Xcent, -2.2 * distance * sin(radians(x)) + base, 1, UCG_DRAW_ALL);\r\n    } else {\r\n      digitalWrite(D2, LOW);\r\n      ucg.setColor(255, 255, 0);\r\n      ucg.drawDisc(208 * cos(radians(x)) + Xcent, -208 * sin(radians(x)) + base, 1, UCG_DRAW_ALL);\r\n    }\r\n\r\n\r\n    Serial.print(x);\r\n    Serial.print(\"    ,   \");\r\n    Serial.println(distance);\r\n\r\n    if (x > 70 and x < 110) fix_font();\r\n\r\n    ucg.setColor(255, 255, 0);\r\n    ucg.setPrintPos(20, 230);\r\n    ucg.print(\"DEG: \");\r\n    ucg.setPrintPos(54, 230);\r\n    ucg.print(x);\r\n    ucg.print(\"  \");\r\n    ucg.setPrintPos(240, 230);\r\n    ucg.print(\"     \");\r\n    ucg.print(distance);\r\n    ucg.print(\" cm    \");\r\n  }\r\n  //ucg.clearScreen(); //\r\n  delay(50);\r\n  cls();\r\n}','',1),
(250,1,'设置有线固定ip','nano /etc/rc.local\r\n在文件中的exit 0之前添加如下内容\r\nifconfig eth0 192.168.x.xxx  # 将xxx更改为你想要设置的IP地址','',1),
(251,3,'微信公从号gh_c4117ba50e6a','微信公从号gh_c4117ba50e6a','',1),
(252,1,'使用树莓派做WIFI路由器','机身温度会增高3度\r\n','',1),
(253,4,'arduino Uno TFT屏','#include <TFT.h>  // Arduino LCD library\r\n#include <SPI.h>\r\n#include <OneWire.h>\r\n#include <DallasTemperature.h>\r\n#include <Adafruit_Sensor.h>\r\n#include <DHT.h>\r\n#include <DHT_U.h>\r\n\r\n#define DHTPIN 7       // 数字引脚连接DHT传感器\r\n#define DHTTYPE DHT11  // DHT 11\r\nDHT_Unified dht(DHTPIN, DHTTYPE);\r\nfloat humidity;\r\nfloat temperature;\r\n\r\n#define cs 10\r\n#define dc 9\r\n#define rst 8\r\n\r\n// TFT屏SDA  接11\r\n// TFT屏SCL  接13\r\n// TFT屏VDD  接5V\r\n// TFT屏GND  接GND\r\n\r\n// 创建实例\r\nTFT TFTscreen = TFT(cs, dc, rst);\r\n\r\n// char array to print to the screen\r\nchar sensorPrintout[4];\r\nint D2 = 2;               //蜂鸣器\r\nint D4 = 4;               // 遥控LED灯\r\nint flameSensorPin = 12;  //火焰传感器\r\nbool firealarm = false;   //为false 代表火警关闭, 否知 代表火警响了\r\nString oldT = \"\";\r\nString oldH = \"\";\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  pinMode(D2, OUTPUT);\r\n  pinMode(D4, OUTPUT);\r\n  digitalWrite(D2, LOW);\r\n  digitalWrite(D4, LOW);\r\n  pinMode(flameSensorPin, INPUT);\r\n  // Put this line at the beginning of every sketch that uses the GLCD:\r\n  TFTscreen.begin();\r\n\r\n  //清除黑色背景的屏幕\r\n  TFTscreen.background(0, 0, 0);\r\n\r\n  // 将静态文本写入屏幕\r\n  // 设置字体颜色为白色\r\n  TFTscreen.stroke(255, 255, 255);\r\n  // 设置字体大小\r\n  TFTscreen.setTextSize(1.5);\r\n  TFTscreen.text(\"temperature:\\n \", 5, 25);\r\n  TFTscreen.text(\"humidity:\\n \", 20, 50);\r\n  TFTscreen.setTextSize(1.9);\r\n  dht.begin();\r\n  sensor_t sensor;\r\n  dht.temperature().getSensor(&sensor);\r\n  dht.humidity().getSensor(&sensor);\r\n}\r\n\r\nvoid loop() {\r\n  sensors_event_t event;\r\n  dht.temperature().getEvent(&event);\r\n  if (isnan(event.temperature)) {\r\n    Serial.println(F(\"Error reading temperature!\"));\r\n  } else {\r\n    temperature = event.temperature;\r\n  }\r\n  delay(500);\r\n  // Get humidity event and print its value.\r\n  dht.humidity().getEvent(&event);\r\n  if (isnan(event.relative_humidity)) {\r\n    Serial.println(F(\"Error reading humidity!\"));\r\n  } else {\r\n    humidity = event.relative_humidity;\r\n  }\r\n  // 读取火焰传感器的值，其返回值范围是0-1023（模拟输入值）\r\n\r\n\r\n  // 设置字体颜色\r\n  TFTscreen.stroke(255, 255, 255);\r\n  // print the sensor value\r\n  char tchar[20];\r\n  char hchar[20];\r\n  dtostrf(temperature, 4, 2, tchar);\r\n  dtostrf(humidity, 4, 0, hchar);\r\n  strcat(tchar, \" C\");\r\n  strcat(hchar, \" %\");\r\n  String tstr=String(tchar);\r\n  tstr.trim();\r\n  String hstr=String(hchar);\r\n  hstr.trim();\r\n  if (oldT != tstr || oldH != hstr) {  //如果 旧的 温度 湿度 有变化 就屏幕更新\r\n    // 把你刚写的文字擦掉\r\n    TFTscreen.stroke(0, 0, 0);\r\n    TFTscreen.text(oldT.c_str(), 90, 25);\r\n    TFTscreen.text(oldH.c_str(), 80, 50);\r\n    oldT = tstr;\r\n    oldH = hstr;\r\n    String tempT = oldT.substring(0, oldT.length() - 2);\r\n    String tempH = oldH.substring(0, oldH.length() - 2);\r\n    String result=tempT+\"&\"+tempH;\r\n    Serial.println(result);\r\n    Serial.write(result.c_str(), 8);  //串口输出\r\n    TFTscreen.stroke(255, 255, 255);\r\n    TFTscreen.text(tstr.c_str(), 90, 25);\r\n    TFTscreen.text(hstr.c_str(), 80, 50);\r\n  }\r\n\r\n  if (digitalRead(flameSensorPin) == LOW) {  // 如果检测到火焰，点亮LED灯\r\n    if (!firealarm) {       //如果上次是火警关闭状态\r\n      firealarm = true;\r\n      Serial.write(\"Fire alarm\", 10);  //串口输出\r\n      TFTscreen.text(\"Fire alarm\", 50, 80);\r\n      digitalWrite(D2, HIGH);  //蜂鸣器响\r\n    }\r\n  } else {\r\n    if (firealarm) {  //如果上次是火警响了,就把屏幕提示关闭\r\n      firealarm = false;\r\n      Serial.write(\"Fire stop\", 9);  //串口输出\r\n      TFTscreen.stroke(0, 0, 0);\r\n      TFTscreen.text(\"Fire alarm\", 50, 80);\r\n      // 如果没检测到火焰，熄灭LED灯\r\n      digitalWrite(D2, LOW);  //蜂鸣器关\r\n    }\r\n  }\r\n\r\n  if (Serial.available() > 0) {  //获取串口消息\r\n    String receivedString = \"\";\r\n    while (Serial.available()) {\r\n      receivedString = Serial.readStringUntil(\'\\n\');  // 读取直到遇到换行符\r\n    }\r\n\r\n    Serial.println(receivedString);\r\n    // 在这里可以对读取到的数据进行处理\r\n    if (receivedString == \"on\") {          //串口接收到on\r\n      digitalWrite(D4, HIGH);              //LED 点亮\r\n    } else if (receivedString == \"off\") {  //串口接收到off\r\n      digitalWrite(D4, LOW);               //LED 熄灭\r\n    }\r\n  }\r\n}\r\n','',1),
(254,4,'esp01s 串口消息通过MQTT转发','#include <ESP8266WiFi.h>\r\n#include <ESP8266WebServer.h>\r\n#include <ESP8266HTTPClient.h>\r\n#include <Ticker.h>\r\n#include <PubSubClient.h>\r\n\r\nTicker myTicker;\r\nWiFiClient wificlient;\r\n\r\n//被读取的文件位置和名称\r\nString flash_wifi = \"/wifi.txt\";\r\nESP8266WebServer ESP8266webServer;  // 创建网络服务器对象,HTTP服务的标准端口为：80\r\nString ssid = \"\";\r\nString passwd = \"\";\r\nString html;\r\n\r\nconst char* mqtt_server = \"bemfa.com\";\r\nPubSubClient client(wificlient);\r\n//unsigned long lastMsg = 0;\r\n//#define MSG_BUFFER_SIZE (50)\r\n//char msg[MSG_BUFFER_SIZE];\r\nint value = 0;\r\nvoid setup(void) {\r\n  Serial.begin(115200);\r\n  delay(1000);\r\n  if (FlashConnetWifi() == false) {\r\n    HtmlSetWifi();\r\n  }\r\n  client.setServer(mqtt_server, 9501);\r\n  client.setCallback(callback);\r\n}\r\nvoid loop(void) {\r\n  if (!client.connected()) {\r\n    reconnect();\r\n  }\r\n  client.loop();\r\n  if (Serial.available()) {\r\n    while (Serial.available()) {\r\n      String receivedString = Serial.readStringUntil(\'\\n\');  // 读取直到遇到换行符\r\n      client.publish(\"esp8266outTopic\", receivedString.c_str()); //mqtt发送\r\n    }\r\n  }\r\n  // unsigned long now = millis();\r\n  // if (now - lastMsg > 2000) {\r\n  //   lastMsg = now;\r\n  //   ++value;\r\n  //   snprintf(msg, MSG_BUFFER_SIZE, \"hello world #%ld\", value);\r\n  //   Serial.print(\"Publish message: \");\r\n  //   Serial.println(msg);\r\n  //   client.publish(\"esp8266outTopic\", msg);\r\n  // }\r\n}\r\n\r\nvoid SetWifi() {\r\n  ssid = ESP8266webServer.arg(0);\r\n  passwd = ESP8266webServer.arg(1);\r\n  String sp = ssid + \"&\" + passwd;\r\n  Serial.println(sp);\r\n  Serial.println(\"密码在前面\");\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  const char* Ssid = ssid.c_str();\r\n  const char* WifiPw = passwd.c_str();\r\n  WiFi.begin(Ssid, WifiPw);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      ESP8266webServer.send(200, \"text/plane\", \"Wifi密码正确,ESP准备重启\");\r\n      ESP8266webServer.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n      Serial.println(\"HTML连接成功\");\r\n      delay(500);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  ESP8266webServer.send(200, \"text/plane\", \"Wifi密码错误,请重新输入\");\r\n}\r\n//------- 展示页面-------\r\nvoid handlejsonStr() {\r\n  ESP8266webServer.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  ESP8266webServer.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\n\r\nvoid ApStart() {\r\n  WiFi.disconnect();\r\n  delay(500);\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n  //启动AP模式,并设置账号和密码\r\n  WiFi.softAP(\"192.168.168.2\", \"nobiggie.cn\");\r\n}\r\nvoid WebserverStart() {\r\n  ESP8266webServer.begin(80);               // 启用网络服务\r\n  ESP8266webServer.on(\"/\", handlejsonStr);  // / 在HTTP中,表示请求首页服务,\r\n  ESP8266webServer.on(\"/SetWifi\", SetWifi);\r\n  ESP8266webServer.onNotFound(handleNotFound);  // 当服务器没找到所需的服务,调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\n\r\nvoid ForPing() {\r\n  //定时时间到了,先取消定时状态\r\n  myTicker.detach();\r\n  delay(500);\r\n  ESP.restart();\r\n}\r\n\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  Serial.begin(115200);\r\n  WiFi.disconnect();\r\n  WiFi.mode(WIFI_STA);\r\n  delay(100);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    Serial.println(n);\r\n    String a = \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a + \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" + \"<html>\" + \"<head>\" + \"<meta charset=\\\"utf-8\\\">\" + \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" + \"<title>设置WiFi</title>\" + \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" + \"</head>\" + \"<script>\" + \"onload  = function() {\" + \"document.getElementById(\\\"up\\\").onclick = function(){\" + \"var ssida=document.getElementById(\\\"ssid\\\").value;\" + \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" + \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" + \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" + \"xhr = new XMLHttpRequest();\" + \"xhr.open(\\\"POST\\\",\\\"./SetWifi\\\",true);\" + \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" + \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" + \"xhr.send(posts);\" + \"xhr.onreadystatechange = function(){\" + \"if(this.readyState == 4 && this.status == 200){\" + \"alert(this.responseText);\" + \"}\" + \"}\" + \"}\" + \"}\" + \"</script>\" + \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" + \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" + \"<hr/>\" + \"<font color=\\\"red\\\">附近WiFi没有显示到自己的WIFI请重启或离信号源近点</font>\" + \"</body>\" + \"</html>\";\r\n    a = a + \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"扫描不到网络\";\r\n    Serial.println(\"扫描不到网络\");\r\n  }\r\n}\r\nbool FlashConnetWifi() {\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  //是否存在数据\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    Serial.print(flash_wifi);\r\n    Serial.println(\" NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flash_wifi, \"r\");\r\n  String result = dateFile.readString();\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char* Ssid = wifiname.c_str();\r\n  const char* WifiPw = wifipw.c_str();\r\n  WiFi.begin(Ssid, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"FlashConnetWifi->false\");\r\n  return false;\r\n}\r\n\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  ApStart();\r\n  delay(1000);\r\n  Serial.println(\"启动网页\");\r\n  myTicker.detach();\r\n  delay(200);\r\n  //5分后重启 防止停电后复电,路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式,所以这里只让AP 激活5分钟后就重启\r\n  myTicker.once(300, espReboot);\r\n  delay(200);\r\n  WebserverStart();\r\n  while (1) {\r\n    ESP8266webServer.handleClient();  // 检查网络服务请求并处理\r\n  }\r\n}\r\nvoid espReboot() {\r\n  ESP.restart();\r\n}\r\nvoid callback(char* topic, byte* payload, unsigned int length) {\r\n  Serial.print(\"Message arrived [\");\r\n  Serial.print(topic);\r\n  Serial.print(\"] \");\r\n  String str;\r\n  for (int i = 0; i < length; i++) {\r\n    str += (char)payload[i];\r\n  }\r\n  Serial.println(str);\r\n  Serial.write(str.c_str(), length);  //串口输出\r\n}\r\nvoid reconnect() {\r\n  // Loop until we\'re reconnected\r\n  while (!client.connected()) {\r\n    Serial.print(\"Attempting MQTT connection...\");\r\n    // Create a random client ID\r\n    String clientId = \"07b120062a7972cf9831d7d9bc8012bc\";\r\n    //clientId += String(random(0xffff), HEX);\r\n    // Attempt to connect\r\n    if (client.connect(clientId.c_str())) {\r\n      Serial.println(\"connected\");\r\n      //发送\r\n      client.publish(\"esp8266outTopic\", \"hello world\");\r\n      //订阅\r\n      client.subscribe(\"esp8266inTopic\");\r\n    } else {\r\n      Serial.print(\"failed, rc=\");\r\n      Serial.print(client.state());\r\n      Serial.println(\" try again in 5 seconds\");\r\n      // Wait 5 seconds before retrying\r\n      delay(5000);\r\n    }\r\n  }\r\n}','',1),
(255,4,'获取串口整句消息','  if (Serial.available() > 0) {  //获取串口消息\r\n    String receivedString = \"\";\r\n    while (Serial.available()) {\r\n      receivedString = Serial.readStringUntil(\'\\n\');  // 读取直到遇到换行符\r\n    }\r\n//receivedString 这个就是获取到的整句消息\r\n}','',1),
(256,3,'golang 图片旋转180度','package main\r\n\r\nimport (\r\n	\"image\"\r\n	\"image/jpeg\"\r\n	\"os\"\r\n)\r\n\r\n// rotateImage180函数用于将给定的图片旋转180度\r\nfunc rotateImage180(img image.Image) image.Image {\r\n	bounds := img.Bounds()\r\n	width := bounds.Max.X\r\n	height := bounds.Max.Y\r\n	rotated := image.NewRGBA(image.Rect(0, 0, width, height))\r\n	for y := 0; y < height; y++ {\r\n		for x := 0; x < width; x++ {\r\n			oldPos := image.Pt(x, y)\r\n			newX := width - x - 1\r\n			newY := height - y - 1\r\n			newPos := image.Pt(newX, newY)\r\n			rotated.Set(newPos.X, newPos.Y, img.At(oldPos.X, oldPos.Y))\r\n		}\r\n	}\r\n	return rotated\r\n}\r\n\r\nfunc main() {\r\n	// 打开原始图片文件\r\n	file, err := os.Open(\"1.jpeg\")\r\n	if err != nil {\r\n		panic(err)\r\n	}\r\n	defer file.Close()\r\n	img, err := jpeg.Decode(file)\r\n	if err != nil {\r\n		panic(err)\r\n	}\r\n	// 对图片进行180度旋转\r\n	rotatedImg := rotateImage180(img)\r\n	// 创建输出文件\r\n	outFile, err := os.Create(\"output.jpg\")\r\n	if err != nil {\r\n		panic(err)\r\n	}\r\n	defer outFile.Close()\r\n	// 将旋转后的图片编码并保存为新文件\r\n	err = jpeg.Encode(outFile, rotatedImg, &jpeg.Options{Quality: 100})\r\n	if err != nil {\r\n		panic(err)\r\n	}\r\n}\r\n','',1),
(258,3,'websocketRedis','package models\r\n\r\nimport (\r\n	\"context\"\r\n	\"encoding/json\"\r\n	\"fmt\"\r\n	\"runtime\"\r\n\r\n	\"github.com/go-redis/redis/v8\"\r\n)\r\n\r\ntype WebsocketRedisRoomZ struct {\r\n	Rdb    *redis.Client\r\n	Host   string\r\n	Passwd string\r\n	Ctx    context.Context\r\n}\r\n\r\nvar WsRedisRoom WebsocketRedisRoomZ\r\n\r\nfunc init() {\r\n	WsRedisRoom.Select(0) // 选择redis库\r\n}\r\n\r\n/*\r\ndb 连接哪个redis reids有16个数据库 0-15\r\n数据库0 是websocket使用\r\n*/\r\nfunc (ggg *WebsocketRedisRoomZ) Select(db int) *redis.Client {\r\n	if runtime.GOOS == \"windows\" {\r\n		ggg.Host = \"192.168.0.200\"\r\n	} else {\r\n		ggg.Host = \"localhost\"\r\n	}\r\n	ggg.Passwd = \"qq282246101\"\r\n	ggg.Rdb = redis.NewClient(&redis.Options{\r\n		Network:            \"\",\r\n		Addr:               ggg.Host + \":6379\",\r\n		Dialer:             nil,\r\n		OnConnect:          nil,\r\n		Password:           ggg.Passwd,\r\n		DB:                 db,\r\n		MaxRetries:         0,\r\n		MinRetryBackoff:    0,\r\n		MaxRetryBackoff:    0,\r\n		DialTimeout:        0,\r\n		ReadTimeout:        0,\r\n		WriteTimeout:       0,\r\n		PoolSize:           30,\r\n		MinIdleConns:       10,\r\n		MaxConnAge:         0,\r\n		PoolTimeout:        0,\r\n		IdleTimeout:        0,\r\n		IdleCheckFrequency: 0,\r\n		TLSConfig:          nil,\r\n	})\r\n	//检测连接是否success success返回 pong\r\n	ggg.Ctx = ggg.Rdb.Context()\r\n	_, errRedis := ggg.Rdb.Ping(ggg.Ctx).Result()\r\n	if errRedis != nil {\r\n		fmt.Println(errRedis.Error())\r\n		return nil\r\n	}\r\n	return ggg.Rdb\r\n}\r\n\r\n// 存储map[房间名]map[用户名]string{ connetID }到 Redis 哈希\r\nfunc (ggg *WebsocketRedisRoomZ) StoreNestedMapToRedisHash(data map[string]map[string]string) error {\r\n	for outerKey, innerMap := range data {\r\n		serializedInnerMap, err := json.Marshal(innerMap)\r\n		if err != nil {\r\n			return err\r\n		}\r\n		err = ggg.Rdb.HSet(ggg.Ctx, \"nested_map_key\", outerKey, string(serializedInnerMap)).Err()\r\n		if err != nil {\r\n			return err\r\n		}\r\n	}\r\n	return nil\r\n}\r\n\r\n// 读取所有websocket 房间数据\r\nfunc (ggg *WebsocketRedisRoomZ) RetrieveNestedMapFromRedisHash() (map[string]map[string]string, error) {\r\n	result := make(map[string]map[string]string)\r\n	fields, err := ggg.Rdb.HGetAll(ggg.Ctx, \"nested_map_key\").Result()\r\n	if err != nil {\r\n		return nil, err\r\n	}\r\n	for outerKey, serializedInnerMap := range fields {\r\n		var innerMap map[string]string\r\n		err = json.Unmarshal([]byte(serializedInnerMap), &innerMap)\r\n		if err != nil {\r\n			return nil, err\r\n		}\r\n		result[outerKey] = innerMap\r\n	}\r\n	return result, err\r\n}\r\n\r\n// 通过 房间名,用户名 找到 connetID\r\nfunc (ggg *WebsocketRedisRoomZ) RetrieveValueByInnerKey(outerKey, innerKey string) (string, error) {\r\n	// 先从Redis获取整个嵌套map数据并还原\r\n	result := make(map[string]map[string]string)\r\n	fields, err := ggg.Rdb.HGetAll(ggg.Ctx, \"nested_map_key\").Result()\r\n	if err != nil {\r\n		return \"\", err\r\n	}\r\n	for outerK, serializedInnerMap := range fields {\r\n		var innerMap map[string]string\r\n		err = json.Unmarshal([]byte(serializedInnerMap), &innerMap)\r\n		if err != nil {\r\n			return \"\", err\r\n		}\r\n		result[outerK] = innerMap\r\n	}\r\n\r\n	// 从还原后的map结构中查找指定内层键对应的值\r\n	innerMap, ok := result[outerKey]\r\n	if !ok {\r\n		return \"\", fmt.Errorf(\"外层键 %s 不存在\", outerKey)\r\n	}\r\n	value, ok := innerMap[innerKey]\r\n	if !ok {\r\n		return \"\", fmt.Errorf(\"内层键 %s 在外层键 %s 下不存在\", innerKey, outerKey)\r\n	}\r\n	return value, nil\r\n}\r\n\r\n// 清空redis库0下的所有key\r\nfunc (ggg *WebsocketRedisRoomZ) FlushDB0ByKeys() error {\r\n	keys, err := ggg.Rdb.Keys(ggg.Ctx, \"*\").Result()\r\n	if err != nil {\r\n		return err\r\n	}\r\n	if len(keys) == 0 {\r\n		return nil\r\n	}\r\n	_, err = ggg.Rdb.Del(ggg.Ctx, keys...).Result()\r\n	return err\r\n}\r\n\r\n// 通过 房间名,connetID 找到 用户名\r\nfunc (ggg *WebsocketRedisRoomZ) RetrieveInnerKeyByValue(outerKey, value string) (string, error) {\r\n	// 先从Redis获取整个嵌套map数据并还原\r\n	result := make(map[string]map[string]string)\r\n	fields, err := ggg.Rdb.HGetAll(ggg.Ctx, \"nested_map_key\").Result()\r\n	if err != nil {\r\n		return \"\", err\r\n	}\r\n	for outerK, serializedInnerMap := range fields {\r\n		var innerMap map[string]string\r\n		err = json.Unmarshal([]byte(serializedInnerMap), &innerMap)\r\n		if err != nil {\r\n			return \"\", err\r\n		}\r\n		result[outerK] = innerMap\r\n	}\r\n\r\n	// 从还原后的map结构中查找指定外层键对应的内层map\r\n	innerMap, ok := result[outerKey]\r\n	if !ok {\r\n		return \"\", fmt.Errorf(\"外层键 %s 不存在\", outerKey)\r\n	}\r\n\r\n	// 遍历内层map，查找值为value的键\r\n	for innerK, v := range innerMap {\r\n		if v == value {\r\n			return innerK, nil\r\n		}\r\n	}\r\n	return \"\", fmt.Errorf(\"未找到值为 %s 的内层键（外层键为 %s）\", value, outerKey)\r\n}\r\n','',1),
(259,2,'redis 命令行','redis-cli -h localhost -p 6379 -a password\r\nselect 0\r\nFLUSHDB 清空当前数据库。\r\n\r\nFLUSHALL 清空所有数据库。','',1),
(260,3,'websocket ROOM map','package main\r\n\r\nimport \"fmt\"\r\n\r\n// DataContainer结构体用于包含和操作map[string][]interface{}\r\ntype DataContainer struct {\r\n	Data map[string][]interface{}\r\n}\r\n\r\n// NewDataContainer创建DataContainer的实例\r\nfunc NewDataContainer() *DataContainer {\r\n	return &DataContainer{\r\n		Data: make(map[string][]interface{}),\r\n	}\r\n}\r\n\r\n// AppendToSlice向指定key对应的切片中追加元素\r\nfunc (dc *DataContainer) AppendToSlice(key string, elements ...interface{}) {\r\n	if _, ok := dc.Data[key]; !ok {\r\n		dc.Data[key] = []interface{}{}\r\n	}\r\n	dc.Data[key] = append(dc.Data[key], elements...)\r\n}\r\n\r\n// UpdateSliceElement更新指定key对应的切片中指定索引位置的元素\r\nfunc (dc *DataContainer) UpdateSliceElement(key string, index int, newElement interface{}) bool {\r\n	if slice, ok := dc.Data[key]; ok {\r\n		if index >= 0 && index < len(slice) {\r\n			slice[index] = newElement\r\n			dc.Data[key] = slice\r\n			return true\r\n		}\r\n	}\r\n	return false\r\n}\r\n\r\n// DeleteSliceElement删除指定key对应的切片中指定索引位置的元素\r\nfunc (dc *DataContainer) DeleteSliceElement(key string, index int) bool {\r\n	if slice, ok := dc.Data[key]; ok {\r\n		if index >= 0 && index < len(slice) {\r\n			dc.Data[key] = append(slice[:index], slice[index+1:]...)\r\n			return true\r\n		}\r\n	}\r\n	return false\r\n}\r\n\r\n// DeleteValue从指定key对应的切片中删除指定的interface{}值\r\nfunc (dc *DataContainer) DeleteValue(key string, target interface{}) bool {\r\n	if slice, ok := dc.Data[key]; ok {\r\n		var newSlice []interface{}\r\n		for _, element := range slice {\r\n			if element != target {\r\n				newSlice = append(newSlice, element)\r\n			}\r\n		}\r\n		if len(newSlice) < len(slice) {\r\n			dc.Data[key] = newSlice\r\n			return true\r\n		}\r\n	}\r\n	return false\r\n}\r\nfunc main() {\r\n	container := NewDataContainer()\r\n	// 向名为\"list1\"的切片中追加元素\r\n	container.AppendToSlice(\"list1\", 1, 2, 3, 2, 4)\r\n	container.AppendToSlice(\"list1\", 5)\r\n	container.AppendToSlice(\"list1\", \"aaaa\")\r\n	fmt.Println(\"After appending:\", container.Data)\r\n\r\n	// 删除\"list1\"切片中的值2\r\n	deleted := container.DeleteValue(\"list1\", \"aaaa\")\r\n	if deleted {\r\n		fmt.Println(\"After deleting value:\", container.Data)\r\n	}\r\n\r\n	fmt.Println(container.Data)\r\n}\r\n','',1),
(262,3,'websocket 服务器 工作原理','Mysql   账号注册,登录 (用户名,密码,房间,登录时间)\r\n\r\n// 结构体用于包含和操作map[string][]interface{}\r\ntype MapMapContainer struct {\r\n    Data  map[string][]interface{}\r\n    mutex sync.RWMutex\r\n}\r\nvar WebsocketRoomFd = MapMapContainer{}   // 房间号 对应的 客户端fd\r\nvar WebsocketRoomUser = MapMapContainer{} // 房间号 对应的 用户名\r\n//WebsocketRoomFd,WebsocketRoomUser 添加,删除时候同时进行\r\n\r\n\r\n连接池 WsConnetPool 全局变量\r\n// 通过Fd 找到conn是谁\r\ntype WsService struct {\r\n    Client *websocket.Conn\r\n    //哪个用户\r\n    User  string\r\n    Fd    uint32 //用户 websocket连接池 唯一标识\r\n    Room  string\r\n    WebOs bool //网页登录\r\n}\r\nvar WsConnetPool = make(map[uint32]*WsService) //websocket 连接池  连接池添加,更改,删除,操作 要使用互斥锁','',1),
(264,4,'ESP01S和DTS33A播报','#include <Arduino.h>\r\n#include <ESP8266WiFi.h>\r\n#include <WebSocketsClient.h>\r\n#include <ESP8266httpUpdate.h>\r\n#include <Hash.h>\r\n#include <ArduinoJson.h>\r\n\r\nWebSocketsClient webSocket;\r\nDynamicJsonDocument jsonBuffer(100);\r\nJsonObject jsonArr;\r\nWiFiClient wificlient;\r\nString version=\"1.0.0\";\r\n#define D2 2          //启动时为高电平才能启动,必须接一个ss8050 三极管 c极接3.3v b极接D2  e机接要控制高低电平的GPIO\r\nbool status = false;  //默认D2 低电平\r\nvoid webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {\r\n\r\n  switch (type) {\r\n    case WStype_DISCONNECTED:\r\n      Serial.printf(\"[WSc] Disconnected!\\n\");\r\n      break;\r\n    case WStype_CONNECTED:\r\n      {\r\n        Serial.printf(\"[WSc] Connected to url: %s\\n\", payload);\r\n\r\n        // send message to server when Connected\r\n        //webSocket.sendTXT(\"Connected\");\r\n      }\r\n      break;\r\n    case WStype_TEXT:\r\n      Serial.printf(\"[WSc] get text: %s\\n\", payload);\r\n      deserializeJson(jsonBuffer, payload);\r\n      jsonArr = jsonBuffer.as<JsonObject>();\r\n      if (jsonArr[\"message\"] != \"\") {\r\n        String message = jsonArr[\"message\"];\r\n        if (message == \"updateBin\") {\r\n          while (1) {\r\n            ESPhttpUpdate.onStart(update_started);\r\n            ESPhttpUpdate.onEnd(update_finished);\r\n            ESPhttpUpdate.onProgress(update_progress);\r\n            ESPhttpUpdate.onError(update_error);\r\n            ESPhttpUpdate.update(wificlient, \"http://192.168.1.2/ota/broadcast.bin\");\r\n          }\r\n        }\r\n        if (message == \"version\") {\r\n          webSocket.sendTXT(version);\r\n        }\r\n        if (message == \"hibernation\") {\r\n          digitalWrite(D2, HIGH);  //播报休眠\r\n          status = true;\r\n        }\r\n      }\r\n      // send message to server\r\n      // webSocket.sendTXT(\"message here\");\r\n      break;\r\n    case WStype_BIN:\r\n      Serial.printf(\"[WSc] get binary length: %u\\n\", length);\r\n      if (status == true) {     //D2高电平\r\n        digitalWrite(D2, LOW);  //播报工作\r\n        status = false;\r\n        delay(2000);\r\n      }\r\n      hexdump(payload, length);\r\n      Serial.write(payload, length);\r\n      // send data to server\r\n      // webSocket.sendBIN(payload, length);\r\n      break;\r\n    case WStype_PING:\r\n      // pong will be send automatically\r\n      //Serial.printf(\"[WSc] get ping\\n\");\r\n      break;\r\n    case WStype_PONG:\r\n      // answer to a ping we send\r\n      Serial.printf(\"[WSc] get pong\\n\");\r\n      break;\r\n  }\r\n}\r\n\r\nvoid setup() {\r\n  // Serial.begin(921600);\r\n  Serial.begin(115200);\r\n  pinMode(D2, OUTPUT);\r\n  digitalWrite(D2, LOW);\r\n  WiFi.begin(\"webserver\", \"www.nobiggie.cn\");\r\n\r\n  while (WiFi.status() != WL_CONNECTED) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n  }\r\n  Serial.printf(\"wifi OK\");\r\n  // server address, port and URL\r\n  webSocket.begin(\"192.168.1.2\", 80, \"/websocket\");\r\n\r\n  // event handler\r\n  webSocket.onEvent(webSocketEvent);\r\n\r\n  // use HTTP Basic Authorization this is optional remove if not needed\r\n  webSocket.setAuthorization(\"user=broadcast&passwd=efghijk&room=root\");\r\n\r\n  // try ever 5000 again if connection has failed\r\n  webSocket.setReconnectInterval(5000);\r\n\r\n  // start heartbeat (optional)\r\n  // ping server every 15000 ms\r\n  // expect pong from server within 3000 ms\r\n  // consider connection disconnected if pong is not received 2 times\r\n  webSocket.enableHeartbeat(15000, 3000, 2);\r\n}\r\n\r\nvoid loop() {\r\n  webSocket.loop();\r\n}\r\nvoid update_started() {\r\n  Serial.println(\"CALLBACK:  HTTP update process started\");\r\n}\r\n\r\nvoid update_finished() {\r\n  Serial.println(\"CALLBACK:  HTTP update process finished\");\r\n}\r\nvoid update_progress(int cur, int total) {\r\n  Serial.printf(\"CALLBACK:  HTTP update process at %d of %d bytes...\\n\", cur, total);\r\n}\r\n\r\nvoid update_error(int err) {\r\n  Serial.printf(\"CALLBACK:  HTTP update fatal error code %d\\n\", err);\r\n}\r\n','',1),
(265,4,'temp','#include <OneWire.h>\r\n#include <DallasTemperature.h>\r\n#include <Adafruit_Sensor.h>\r\n#include <DHT.h>\r\n#include <DHT_U.h>\r\n\r\n#include <FastLED.h>\r\n#include \"MAX30105.h\"\r\n#include \"spo2_algorithm.h\"\r\n\r\n\r\n#define DHTPIN 4  // 数字引脚连接DHT传感器\r\n#define DHTTYPE DHT11  // DHT 11\r\nDHT_Unified dht(DHTPIN, DHTTYPE);\r\nfloat humidity;\r\nfloat temperature;\r\n\r\n#define LED_PIN 18    // LED串连接的引脚\r\n#define NUM_LEDS 16   // LED数量\r\nCRGB leds[NUM_LEDS];  // 用于存储LED颜色数据的数组\r\n\r\n\r\nMAX30105 particleSensor;\r\n// 存储红外光和红光数据的缓冲区\r\nuint32_t irBuffer[100];\r\nuint32_t redBuffer[100];\r\n// 测量得到的血氧饱和度和心率值\r\nint32_t spo2;\r\nint8_t validSPO2;\r\nint32_t heartRate;\r\nint8_t validHeartRate;\r\n\r\n// 引脚定义\r\nbyte pulseLED = 21;\r\nbyte readLED = 22;\r\nvoid setup() {\r\n  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);  // 初始化LED串\r\n\r\n  Serial.begin(115200);\r\n  dht.begin();\r\n  sensor_t sensor;\r\n  dht.temperature().getSensor(&sensor);\r\n  dht.humidity().getSensor(&sensor);\r\n\r\n  // 初始化传感器\r\n  if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {\r\n    Serial.println(\"MAX30105 was not found. Please check wiring/power.\");\r\n    while (1)\r\n      ;\r\n  }\r\n  // 设置传感器参数\r\n  byte ledBrightness =100;\r\n  byte sampleAverage = 4;\r\n  byte ledMode = 2;\r\n  byte sampleRate = 100;\r\n  int pulseWidth = 411;\r\n  int adcRange = 4096;\r\n  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);\r\n}\r\n\r\nvoid loop() {\r\n  sensors_event_t event;\r\n  dht.temperature().getEvent(&event);\r\n  if (isnan(event.temperature)) {\r\n    Serial.println(F(\"Error reading temperature!\"));\r\n  } else {\r\n    temperature = event.temperature;\r\n  }\r\n  delay(500);\r\n  // Get humidity event and print its value.\r\n  dht.humidity().getEvent(&event);\r\n  if (isnan(event.relative_humidity)) {\r\n    Serial.println(F(\"Error reading humidity!\"));\r\n  } else {\r\n    humidity = event.relative_humidity;\r\n  }\r\n  String th = String(temperature) + \",\" + String(humidity);\r\n  Serial.println(th);\r\n  if (temperature <= 5) {\r\n    //紫色\r\n    fill_solid(leds, NUM_LEDS, CRGB(CHSV(160, 255, 255)));\r\n    FastLED.show();\r\n    delay(100);\r\n  } else {\r\n    if (temperature <= 10) {\r\n      //靛\r\n      fill_solid(leds, NUM_LEDS, CRGB(CHSV(180, 255, 255)));\r\n      FastLED.show();\r\n      delay(100);\r\n    } else {\r\n      if (temperature <= 15) {\r\n        //蓝\r\n       fill_solid(leds, NUM_LEDS, CRGB(CHSV(192, 255, 255)));\r\n        FastLED.show();\r\n        delay(100);\r\n      } else {\r\n        if (temperature <= 20) {\r\n          //绿\r\n          fill_solid(leds, NUM_LEDS, CRGB(CHSV(96, 255, 255)));\r\n          FastLED.show();\r\n          delay(100);\r\n        } else {\r\n          if (temperature <= 25) {\r\n            //黄\r\n            fill_solid(leds, NUM_LEDS, CRGB(CHSV(32, 255, 255)));\r\n            FastLED.show();\r\n            delay(100);\r\n          } else {\r\n            if (temperature <= 30) {\r\n              //橙\r\n              fill_solid(leds, NUM_LEDS, CRGB(CHSV(24, 255, 255)));\r\n              FastLED.show();\r\n              delay(100);\r\n            } else {\r\n              //红\r\n              fill_solid(leds, NUM_LEDS, CRGB(CHSV(0, 255, 255)));\r\n              FastLED.show();\r\n              delay(100);\r\n            }\r\n          }\r\n        }\r\n      }\r\n    }\r\n  }\r\n\r\n  \r\n  /////// 读取 30 个样本\r\n  int bufferLength = 50;\r\n\r\n  for (byte i = 0; i < bufferLength; i++) {\r\n    while (particleSensor.available() == false) {\r\n      particleSensor.check();\r\n    }\r\n    redBuffer[i] = particleSensor.getRed();\r\n    irBuffer[i] = particleSensor.getIR();\r\n    particleSensor.nextSample();\r\n    //Serial.print(\"red=\");\r\n    //Serial.print(redBuffer[i], DEC);\r\n    //Serial.print(\", ir=\");\r\n    //Serial.println(irBuffer[i], DEC);\r\n  }\r\n  // 计算血氧饱和度和心率\r\n  maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);\r\n  // 输出结果\r\n  if (validHeartRate == 1 && validSPO2 == 1) {\r\n    int32_t temHR = heartRate / 2.4;\r\n    Serial.print(\"心率 \");\r\n    Serial.print(temHR);\r\n    Serial.print(\", 血氧 \");\r\n    Serial.println(spo2, DEC);\r\n\r\n   // Number1.print(temHR);\r\n   // Number2.print(spo2);\r\n\r\n  } else {\r\n    Serial.println(\"检测失败,请手指放好位置\");\r\n    //Number1.print(0);\r\n    //Number2.print(0);\r\n\r\n  }\r\n}\r\n','',1),
(266,4,'彩灯 FastLED库 使用','#include <FastLED.h>\r\n#define LED_PIN 18    // LED串连接的引脚\r\n#define NUM_LEDS 16   // LED数量\r\nCRGB leds[NUM_LEDS];  // 用于存储LED颜色数据的数组\r\nvoid setup() {\r\n  // put your setup code here, to run once:\r\n  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);  // 初始化LED串\r\n\r\n  Serial.begin(115200);\r\n}\r\n\r\nvoid loop() {\r\n  // put your main code here, to run repeatedly:\r\n  //紫色\r\n  fill_solid(leds, NUM_LEDS, CRGB(CHSV(160, 255, 255)));\r\n  FastLED.show();\r\n  Serial.println(\"紫色\");\r\n  delay(2000);\r\n  fill_solid(leds, NUM_LEDS, CRGB(CHSV(180, 255, 255)));\r\n  FastLED.show();\r\n  Serial.println(\"靛色\");\r\n  delay(2000);\r\n  fill_solid(leds, NUM_LEDS, CRGB(CHSV(192, 255, 255)));\r\n  Serial.println(\"蓝色\");\r\n  FastLED.show();\r\n  delay(2000);\r\n  fill_solid(leds, NUM_LEDS, CRGB(CHSV(96, 255, 255)));\r\n  FastLED.show();\r\n  Serial.println(\"绿色\");\r\n  delay(2000);\r\n  fill_solid(leds, NUM_LEDS, CRGB(CHSV(32, 255, 255)));\r\n  FastLED.show();\r\n  Serial.println(\"黄色\");\r\n  delay(2000);\r\n  fill_solid(leds, NUM_LEDS, CRGB(CHSV(24, 255, 255)));\r\n  FastLED.show();\r\n   Serial.println(\"橙色\");\r\n  delay(2000);\r\n  fill_solid(leds, NUM_LEDS, CRGB(CHSV(0, 255, 255)));\r\n  FastLED.show();\r\n  Serial.println(\"红色\");\r\n  delay(2000);\r\n}\r\n','',1),
(267,3,'golang 打包多个EXE文件生成一个文件','package main\r\n\r\nimport (\r\n	\"embed\"\r\n	\"io\"\r\n	\"log\"\r\n	\"os\"\r\n	\"os/exec\"\r\n	\"time\"\r\n)\r\n\r\n//go:embed ws.exe copyFile.exe\r\nvar exeFiles embed.FS\r\n\r\nfunc extractFile(fileName, outputName string) {\r\n	file, err := exeFiles.Open(fileName)\r\n	if err != nil {\r\n		log.Fatalf(\"无法打开嵌入的文件 %s: %v\", fileName, err)\r\n	}\r\n	defer file.Close()\r\n\r\n	outputFile, err := os.Create(outputName)\r\n	if err != nil {\r\n		log.Fatalf(\"无法创建输出文件 %s: %v\", outputName, err)\r\n	}\r\n	defer outputFile.Close()\r\n\r\n	_, err = io.Copy(outputFile, file)\r\n	if err != nil {\r\n		log.Fatalf(\"无法从 %s 复制文件内容到 %s: %v\", fileName, outputName, err)\r\n	}\r\n\r\n	log.Printf(\"%s 已成功提取到 %s.\", fileName, outputName)\r\n}\r\n\r\nfunc main() {\r\n	extractFile(\"ws.exe\", \"ws.exe\")\r\n	extractFile(\"copyFile.exe\", \"copyFile.exe\")\r\n	time.Sleep(time.Second * 1)\r\n	// 运行 extracted_abc.exe\r\n	cmd := exec.Command(\"copyFile.exe\")\r\n	err := cmd.Run()\r\n	if err != nil {\r\n		log.Fatalf(\"运行 copyFile.exe 时出错: %v\", err)\r\n	}\r\n	log.Println(\"extracted_abc.exe 已成功运行。\")\r\n	os.Remove(\"copyFile.exe\")\r\n	os.Remove(\"ws.exe\")\r\n}\r\n','',1),
(268,4,'沃柑吊针容量esp8266','\r\n#include <ESP8266WiFi.h>\r\n#include <ESP8266HTTPClient.h>\r\nWiFiClient wificlient;\r\nint d5 = 14;\r\nint d6 = 12;\r\nint d8 = 15;  //wifi 连接成gas指示灯\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n  pinMode(d5, INPUT_PULLUP);\r\n  pinMode(d6, OUTPUT);\r\n  pinMode(d8, OUTPUT);\r\n  digitalWrite(d6, LOW);\r\n  digitalWrite(d8, LOW);\r\n  WiFi.begin(\"webserver\", \"www.nobiggie.cn\");\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  while (1) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      break;\r\n    }\r\n  }\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  digitalWrite(d8, HIGH);\r\n  delay(500);\r\n}\r\n\r\nvoid loop() {\r\n  // put your main code here, to run repeatedly:\r\n  if (digitalRead(d5) == LOW) {\r\n    String a = esp8266Get(\"http://192.168.1.2:8080/auth/delay\");\r\n    if (a.length() > 0) {\r\n      Serial.println(a);\r\n      int aint = a.toInt();\r\n      int aa = aint * 1000;\r\n      digitalWrite(D6, HIGH);\r\n      delay(aa);\r\n      digitalWrite(D6, LOW);\r\n    }\r\n  }\r\n}\r\nString esp8266Get(String string) {\r\n  HTTPClient http;\r\n  String response;\r\n  http.begin(wificlient, string);\r\n  http.setTimeout(2000);\r\n  int httpCode = http.GET();\r\n  // httpCode will be negative on error\r\n  if (httpCode == 200) {\r\n    response = http.getString();\r\n    return response;\r\n  } else {\r\n    return \"\";\r\n  }\r\n  http.end();\r\n}','',1),
(269,4,'esp01s websocket客户端测试用','/*\r\n * WebSocketClient.ino\r\n *\r\n *  Created on: 24.05.2015\r\n *\r\n */\r\n\r\n#include <Arduino.h>\r\n\r\n#include <ESP8266WiFi.h>\r\n#include <ESP8266WiFiMulti.h>\r\n\r\n#include <WebSocketsClient.h>\r\n#include <ArduinoJson.h>\r\n#include <Hash.h>\r\n\r\nESP8266WiFiMulti WiFiMulti;\r\nWebSocketsClient webSocket;\r\n\r\n#define USE_SERIAL Serial1\r\nDynamicJsonDocument jsonBuffer(100);\r\nJsonObject jsonArr;\r\nvoid webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {\r\n\r\n  switch (type) {\r\n    case WStype_DISCONNECTED:\r\n      USE_SERIAL.printf(\"[WSc] Disconnected!\\n\");\r\n      break;\r\n    case WStype_CONNECTED:\r\n      {\r\n        USE_SERIAL.printf(\"[WSc] Connected to url: %s\\n\", payload);\r\n\r\n        // send message to server when Connected\r\n        webSocket.sendTXT(\"Connected\");\r\n      }\r\n      break;\r\n    case WStype_TEXT:\r\n      USE_SERIAL.printf(\"[WSc] get text: %s\\n\", payload);\r\n      deserializeJson(jsonBuffer, payload);\r\n      jsonArr = jsonBuffer.as<JsonObject>();\r\n      if (jsonArr[\"message\"] != \"\") {\r\n        String user = jsonArr[\"user\"];\r\n        String date = jsonArr[\"date\"];\r\n        String message = jsonArr[\"message\"];\r\n        Serial.println(message);\r\n        webSocket.sendTXT(message);\r\n      }\r\n      // send message to server\r\n      // webSocket.sendTXT(\"message here\");\r\n      break;\r\n    case WStype_BIN:\r\n      USE_SERIAL.printf(\"[WSc] get binary length: %u\\n\", length);\r\n      hexdump(payload, length);\r\n\r\n      // send data to server\r\n      // webSocket.sendBIN(payload, length);\r\n      break;\r\n    case WStype_PING:\r\n      // pong will be send automatically\r\n      USE_SERIAL.printf(\"[WSc] get ping\\n\");\r\n      break;\r\n    case WStype_PONG:\r\n      // answer to a ping we send\r\n      USE_SERIAL.printf(\"[WSc] get pong\\n\");\r\n      break;\r\n  }\r\n}\r\n\r\nvoid setup() {\r\n  // USE_SERIAL.begin(921600);\r\n  USE_SERIAL.begin(115200);\r\n\r\n  //Serial.setDebugOutput(true);\r\n  USE_SERIAL.setDebugOutput(true);\r\n\r\n  USE_SERIAL.println();\r\n  USE_SERIAL.println();\r\n  USE_SERIAL.println();\r\n\r\n  for (uint8_t t = 4; t > 0; t--) {\r\n    USE_SERIAL.printf(\"[SETUP] BOOT WAIT %d...\\n\", t);\r\n    USE_SERIAL.flush();\r\n    delay(1000);\r\n  }\r\n\r\n  WiFiMulti.addAP(\"webserver\", \"www.nobiggie.cn\");\r\n\r\n  //WiFi.disconnect();\r\n  while (WiFiMulti.run() != WL_CONNECTED) {\r\n    delay(100);\r\n  }\r\n  Serial.println(\"wifi ok\");\r\n  // server address, port and URL\r\n  webSocket.begin(\"192.168.1.2\", 100, \"/websocket\");\r\n\r\n  // event handler\r\n  webSocket.onEvent(webSocketEvent);\r\n\r\n  // use HTTP Basic Authorization this is optional remove if not needed\r\n  webSocket.setAuthorization(\"user=mydoor1&passwd=efghijk&room=admin\");\r\n  // try ever 5000 again if connection has failed\r\n  webSocket.setReconnectInterval(5000);\r\n\r\n  // start heartbeat (optional)\r\n  // ping server every 15000 ms\r\n  // expect pong from server within 3000 ms\r\n  // consider connection disconnected if pong is not received 2 times\r\n  webSocket.enableHeartbeat(15000, 3000, 2);\r\n}\r\n\r\nvoid loop() {\r\n  webSocket.loop();\r\n}\r\n','',1),
(270,2,'合并表去重复','MySQL  遍历查询CommerceCustomer表下的 phone ，比对KuaiDiReceiver表.如果KuaiDiReceiver表没有对应的 phone字段值 就向 KuaiDiReceiver插入该数据，，sql 语句怎么写\r\n\r\nINSERT INTO KuaiDiReceiver (name,phone,address,date,quantity)\r\nSELECT name,phone,address,date,quantity\r\nFROM CommerceCustomer\r\nWHERE phone NOT IN (SELECT DISTINCT phone FROM KuaiDiReceiver);','',1),
(271,2,'查询表是否有重复的字段 phone','SELECT phone\r\nFROM KuaiDiReceiver\r\nGROUP BY phone\r\nHAVING COUNT(phone) > 1;','',1),
(272,3,'单协程多channel与多个协程多channel的区别','单协程下的多channel不能并发,只能一个channel执行完毕后在selelct{}下的另一个channel\r\n\r\n多个协程多channel就可以同时并行并发','',1),
(274,1,'mqtt服务器开启webscoket TLS微信小程序','sudo apt update\r\nsudo apt install mosquitto mosquitto-clients\r\nsudo systemctl start mosquitto\r\nsudo systemctl enable mosquitto\r\ncd /etc/mosquitto/certs\r\n把网站证书放到这里\r\nnano /etc/mosquitto/mosquitto.conf\r\n添加以下内容\r\n# 允许匿名访问，可根据需要修改\r\nallow_anonymous true\r\n\r\n# 监听 WebSocket 端口\r\nlistener 8083\r\nprotocol websockets\r\n\r\n# 监听 WebSocket TLS 端口\r\nlistener 8084\r\nprotocol websockets\r\ncafile /etc/mosquitto/certs/server.crt\r\ncertfile /etc/mosquitto/certs/server.crt\r\nkeyfile /etc/mosquitto/certs/server.key\r\n\r\nsudo systemctl restart mosquitto\r\n验证配置\r\n<!DOCTYPE html>\r\n<html lang=\"en\">\r\n\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>MQTT WebSocket TLS Test</title>\r\n    <script src=\"https://unpkg.com/mqtt/dist/mqtt.min.js\"></script>\r\n</head>\r\n\r\n<body>\r\n    <script>\r\n        const options = {\r\n            protocol: \'wss\',\r\n            host: \'localhost\',\r\n            port: 8084,\r\n            rejectUnauthorized: false // 因为是自签名证书，这里暂时设置为 false\r\n        };\r\n\r\n        const client = mqtt.connect(options);\r\n\r\n        client.on(\'connect\', function () {\r\n            console.log(\'Connected to MQTT broker via WebSocket TLS\');\r\n            client.subscribe(\'test/topic\', function (err) {\r\n                if (!err) {\r\n                    client.publish(\'test/topic\', \'Hello, MQTT!\');\r\n                }\r\n            });\r\n        });\r\n\r\n        client.on(\'message\', function (topic, message) {\r\n            console.log(\'Received message:\', topic, message.toString());\r\n            client.end();\r\n        });\r\n    </script>\r\n</body>\r\n\r\n</html>','',1),
(275,4,'SIM900和A7670C使用MQTT','#include <Arduino.h>\r\n\r\n// MQTT服务器配置\r\nconst char* mqttServer = \"wulian.nobiggie.cn\";\r\nconst int mqttPort = 1883;\r\nconst char* clientId = \"alarm-101\";\r\nconst char* username = \"alarm-101\";\r\nconst char* password = \"abcdefg\";\r\nconst char* sutopic = \"water/alarm-101/control\";\r\nconst char* putopic = \"water/alarm-101/data\";\r\n\r\n// 定义引脚数组 分别代表水位 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%\r\nconst int pins[] = {39, 34, 35, 32, 33, 25, 26, 27, 14 ,13};\r\nconst int numPins = sizeof(pins) / sizeof(pins[0]);\r\n// 缓冲区和超时设置\r\nchar response[256];\r\nunsigned long timeout;\r\nint waterV = 0;\r\nbool mqttConnet = false;\r\nint i = 10;\r\nString connectCmd = \"\";\r\n\r\n\r\nString inputString = \"\";  // 用于存储接收到的数据\r\nbool breakbl = false;\r\nvoid setup() {\r\n  // 初始化串口通信\r\n  Serial.begin(115200);\r\n  // 设置水位检测引脚为输入模式\r\n  for (int i = 0; i < numPins; i++) {\r\n    pinMode(pins[i], INPUT);\r\n    delay(200);\r\n  }\r\n\r\n  Serial.println(\"开始启动GSM\");\r\n  delay(28000);  //等待GSM启动完成\r\n  // 连接MQTT服务器\r\n  connectCmd = \"AT+CMQTTCONNECT=0,\\\"tcp://\";\r\n  connectCmd += mqttServer;\r\n  connectCmd += \":\";\r\n  connectCmd += String(mqttPort);\r\n  connectCmd += \"\\\",60,1,\\\"\";\r\n  connectCmd += username;\r\n  connectCmd += \"\\\",\\\"\";\r\n  connectCmd += password;\r\n  connectCmd += \"\\\"\";\r\n  Serial.println(\"AT+CMQTTCFG=\\\"argtopic\\\",0,1,1\");\r\n  delay(500);\r\n}\r\nbool mConnet() {\r\n\r\n  // 启动MQTT\r\n  if (sendATCommand(\"AT+CMQTTSTART\", \"OK\", 5000)) {\r\n    // 设置MQTT账户\r\n    if (sendATCommand(\"AT+CMQTTACCQ=0,\\\"A7670C\\\"\", \"OK\", 5000)) {\r\n      //Serial.println(\"MQTT account set successfully\");\r\n      if (sendATCommand(connectCmd.c_str(), \"OK\", 10000)) {\r\n        return true;\r\n        Serial.println(\"Connected to MQTT server\");\r\n        int topicLen = String(sutopic).length();\r\n        String subFrameCmd = \"AT+CMQTTSUB=0,\" + String(topicLen) + \",0\";\r\n        //订阅主题\r\n        if (sendATCommand(subFrameCmd.c_str(), \">\", 2000)) {\r\n          if (sendATCommand(sutopic, \"OK\", 2000)) {\r\n            return true;\r\n            //     //Serial.println(\"Subscribed to topic successfully\");\r\n            //     const char* a = \"10\";\r\n            //     publishMQTTMessage(putopic, a);\r\n            //   } else {\r\n            //     Serial.println(\"Failed to send topic\");\r\n          }\r\n          return false;\r\n        } else {\r\n          Serial.println(\"Failed to start subscription\");\r\n          return false;\r\n        }\r\n      } else {\r\n\r\n        Serial.println(\"Failed to connect to MQTT server\");\r\n        return false;\r\n      }\r\n    } else {\r\n      Serial.println(\"Failed to set MQTT account\");\r\n      return false;\r\n    }\r\n  } else {\r\n    Serial.println(\"Failed to start MQTT\");\r\n    return false;\r\n  }\r\n}\r\nvoid loop() {\r\n  // 设置水位检测引脚为输入模式\r\n  for (int i = 0; i < numPins; i++) {\r\n    if (digitalRead(pins[i]) == HIGH) {\r\n      waterV = (i + 1) * 10;\r\n    }\r\n  }\r\n  if (mqttConnet) {\r\n    //i++;\r\n    String tmp = String(waterV);\r\n    waterV = 0;\r\n    publishMQTTMessage(putopic, tmp.c_str());\r\n  } else {\r\n    mqttConnet = mConnet();\r\n  }\r\n\r\n  // 可以在这里添加发布消息的代码\r\n  delay(20000);\r\n}\r\n\r\nbool sendATCommand(const char* command, const char* expectedResponse, unsigned long timeout) {\r\n  if (command != \"AT\") {\r\n    Serial.println(command);\r\n  } else {\r\n    Serial.print(\"[发送指令] \");\r\n    Serial.println(command);\r\n  }\r\n\r\n\r\n  // 清空接收缓冲区\r\n  while (Serial.available()) {\r\n    Serial.read();\r\n  }\r\n\r\n  String response = \"\";\r\n  unsigned long startTime = millis();\r\n\r\n  while (millis() - startTime < timeout) {\r\n    // 读取所有可用数据\r\n    while (Serial.available()) {\r\n      char c = Serial.read();\r\n      response += c;\r\n      delay(1);  // 防止数据丢失\r\n    }\r\n\r\n    // 检查是否包含预期响应（忽略大小写）\r\n    if (response.indexOf(expectedResponse) != -1) {\r\n      String bb = String(command);\r\n      if (bb.indexOf(\"AT+CMQTTPAYLOAD=\") != -1 || bb.indexOf(\"AT+\") == -1) {\r\n        return true;\r\n      }\r\n      //Serial.print(\"[指令成功] \");\r\n      return true;\r\n    }\r\n\r\n    // 检查是否包含错误\r\n    if (response.indexOf(\"ERROR\") != -1) {\r\n      Serial.print(\"[指令失败] \");\r\n      return false;\r\n    }\r\n\r\n    delay(10);  // 避免CPU占用过高\r\n  }\r\n\r\n  Serial.print(\"[指令超时] \");\r\n  return false;\r\n}\r\n\r\nbool publishMQTTMessage(const char* putopic, const char* payload) {\r\n  int topicLength = strlen(putopic);\r\n  int payloadLength = strlen(payload);\r\n\r\n  // 设置主题长度\r\n  String topicLenCmd = \"AT+CMQTTTOPIC=0,\" + String(topicLength);\r\n  if (!sendATCommand(topicLenCmd.c_str(), \">\", 5000)) {\r\n    Serial.print(\"[发布主题长度失败] \");\r\n    return false;\r\n  }\r\n\r\n  // 发送主题内容\r\n  //Serial.print(\"[发送主题] \");\r\n  Serial.println(putopic);\r\n  delay(500);\r\n  // 设置负载长度\r\n  String payloadLenCmd = \"AT+CMQTTPAYLOAD=0,\" + String(payloadLength);\r\n  if (!sendATCommand(payloadLenCmd.c_str(), \">\", 5000)) {\r\n    return false;\r\n  }\r\n\r\n  // 发送负载内容\r\n\r\n  if (!sendATCommand(payload, \"OK\", 1000)) {\r\n    return false;\r\n  }\r\n\r\n\r\n  String aa = \"AT+CMQTTPUB=0,0,\" + String(payloadLength);\r\n  // 发布消息 (QoS=0, 保留=0)\r\n  if (!sendATCommand(aa.c_str(), \"+CMQTTPUB: 0,0\", 8000)) {\r\n    return false;\r\n  }\r\n\r\n\r\n  return true;\r\n}\r\n','',1),
(277,4,'arduino微信小程序水位NODEMCU32S','#include <Arduino.h>\r\n\r\n// 定义引脚数组 分别代表水位 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%\r\nconst int pins[] = { 25, 26, 15, 2, 0, 4, 16, 17, 21, 22 };\r\nconst int numPins = sizeof(pins) / sizeof(pins[0]);\r\n\r\n// MQTT配置参数\r\nconst char* mqttBroker = \"wulian.nobiggie.cn\";\r\nconst int mqttPort = 1883;\r\nconst char* mqttClientId = \"A7670C\";\r\nconst char* mqttUsername = \"aaaaaaa\";\r\nconst char* mqttPassword = \"abcdefg\";\r\nconst char* pubTopic = \"wulian/water\";\r\nconst char* subTopic = \"wulian/admin\";\r\n\r\n// 状态变量\r\nbool mqttConnected = false;\r\nunsigned long lastReconnectAttempt = 0;\r\nunsigned long lastPublishTime = 0;\r\nunsigned long lastWaterCheckTime = 0;\r\nconst unsigned long publishInterval = 5000;     // 发布间隔(毫秒)\r\nconst unsigned long waterCheckInterval = 1000;  // 水位检测间隔(毫秒)\r\n\r\n// 水位相关变量\r\nint currentWaterLevel = 0;\r\nint lastPublishedLevel = -1;          // 初始化为-1表示尚未发布过\r\nconst int levelChangeThreshold = 10;  // 水位变化超过此值才发布更新\r\n\r\n// 串口通信缓冲区和状态\r\n#define MAX_RESPONSE_LENGTH 256\r\nchar responseBuffer[MAX_RESPONSE_LENGTH];\r\nint responseIndex = 0;\r\nbool awaitingResponse = false;\r\nString currentCommand = \"\";\r\n\r\nvoid setup() {\r\n  Serial.begin(115200);\r\n\r\n  Serial.println(\"水位监测系统初始化中...\");\r\n\r\n  // 设置水位检测引脚为输入模式\r\n  for (int i = 0; i < numPins; i++) {\r\n    pinMode(pins[i], INPUT);\r\n  }\r\n\r\n  // 初始化模块\r\n  if (initModule()) {\r\n    Serial.println(\"模块初始化成功\");\r\n    // 连接MQTT服务器\r\n    reconnect();\r\n  } else {\r\n    Serial.println(\"模块初始化失败\");\r\n  }\r\n}\r\n\r\nvoid loop() {\r\n  // 处理串口响应\r\n  handleSerialResponses();\r\n\r\n  // 定期检测水位\r\n  if (millis() - lastWaterCheckTime > waterCheckInterval) {\r\n    lastWaterCheckTime = millis();\r\n    checkWaterLevel();\r\n  }\r\n\r\n  // 保持MQTT连接\r\n  if (!mqttConnected) {\r\n    unsigned long now = millis();\r\n    // 每5秒尝试重连\r\n    if (now - lastReconnectAttempt > 5000) {\r\n      lastReconnectAttempt = now;\r\n      reconnect();\r\n    }\r\n  } else {\r\n    // 当水位变化超过阈值时发布更新\r\n    if (shouldPublishUpdate()) {\r\n      publishWaterLevel();\r\n      lastPublishedLevel = currentWaterLevel;\r\n      Serial.print(\"已发布更新水位: \");\r\n      Serial.print(currentWaterLevel);\r\n      Serial.println(\"%\");\r\n    }\r\n  }\r\n}\r\n\r\n// 检测当前水位\r\nvoid checkWaterLevel() {\r\n  int newLevel = 0;\r\n\r\n  // 遍历所有引脚，找到最高水位\r\n  for (int i = 0; i < numPins; i++) {\r\n    if (digitalRead(pins[i]) == LOW) {\r\n      newLevel = (i + 1) * 10;  // 转换为百分比\r\n    }\r\n  }\r\n\r\n  // 如果水位发生变化，打印日志\r\n  if (newLevel != currentWaterLevel) {\r\n    Serial.print(\"水位更新: \");\r\n    Serial.print(currentWaterLevel);\r\n    Serial.print(\"% -> \");\r\n    Serial.print(newLevel);\r\n    Serial.println(\"%\");\r\n    currentWaterLevel = newLevel;\r\n  }\r\n}\r\n\r\n// 判断是否应该发布水位更新\r\nbool shouldPublishUpdate() {\r\n  // 如果还没有发布过任何水位信息，立即发布\r\n  if (lastPublishedLevel == -1) {\r\n    return true;\r\n  }\r\n\r\n  // 计算当前水位与上次发布水位的差值\r\n  int levelDifference = abs(currentWaterLevel - lastPublishedLevel);\r\n\r\n  // 当差值达到或超过阈值时发布更新\r\n  return (levelDifference >= levelChangeThreshold);\r\n}\r\n\r\n// 初始化模块\r\nbool initModule() {\r\n  // 重置模块\r\n  resetModule();\r\n\r\n  // 检查模块响应\r\n  if (!sendATCommand(\"AT\", \"OK\", 2000)) return false;\r\n\r\n  // 关闭回显\r\n  if (!sendATCommand(\"ATE0\", \"OK\", 2000)) return false;\r\n\r\n  // 检查SIM卡状态\r\n  if (!sendATCommand(\"AT+CPIN?\", \"READY\", 5000)) return false;\r\n\r\n  // 等待网络注册\r\n  if (!waitForNetworkRegistration()) return false;\r\n\r\n  // 配置MQTT主题参数模式\r\n  if (!sendATCommand(\"AT+CMQTTCFG=\\\"argtopic\\\",0,1,1\", \"OK\", 5000)) return false;\r\n\r\n  return true;\r\n}\r\n\r\n// 重置模块\r\nvoid resetModule() {\r\n  pinMode(9, OUTPUT);  // 假设复位引脚为D9\r\n  digitalWrite(9, LOW);\r\n  delay(200);\r\n  digitalWrite(9, HIGH);\r\n  delay(3000);  // 等待模块启动\r\n}\r\n\r\n// 等待网络注册\r\nbool waitForNetworkRegistration() {\r\n  Serial.println(\"等待网络注册...\");\r\n  unsigned long startTime = millis();\r\n\r\n  while (millis() - startTime < 30000) {  // 超时30秒\r\n    if (sendATCommand(\"AT+CREG?\", \"+CREG: 0,1\", 2000) || sendATCommand(\"AT+CREG?\", \"+CREG: 0,5\", 2000)) {\r\n      Serial.println(\"网络注册成功\");\r\n      return true;\r\n    }\r\n    delay(1000);\r\n  }\r\n\r\n  //Serial.println(\"网络注册超时\");\r\n  return false;\r\n}\r\n\r\n// 连接MQTT服务器和订阅主题\r\nbool reconnect() {\r\n  Serial.println(\"尝试连接MQTT服务器...\");\r\n\r\n  // 启动MQTT\r\n  if (!sendATCommand(\"AT+CMQTTSTART\", \"OK\", 5000)) return false;\r\n\r\n  // 设置客户端ID\r\n  String cmd = \"AT+CMQTTACCQ=0,\\\"\";\r\n  cmd += mqttClientId;\r\n  cmd += \"\\\"\";\r\n  if (!sendATCommand(cmd.c_str(), \"OK\", 5000)) return false;\r\n\r\n  // 连接到MQTT代理\r\n  cmd = \"AT+CMQTTCONNECT=0,\\\"tcp://\";\r\n  cmd += mqttBroker;\r\n  cmd += \":\";\r\n  cmd += String(mqttPort);\r\n  cmd += \"\\\",120,1,\\\"\";\r\n  cmd += mqttUsername;\r\n  cmd += \"\\\",\\\"\";\r\n  cmd += mqttPassword;\r\n  cmd += \"\\\"\";\r\n  if (!sendATCommand(cmd.c_str(), \"OK\", 15000)) return false;\r\n\r\n  // 订阅主题 - 按照AT指令序列实现\r\n  cmd = \"AT+CMQTTSUB=0,\";\r\n  cmd += String(strlen(subTopic));\r\n  cmd += \",0\";\r\n  if (!sendATCommand(cmd.c_str(), \"OK\", 5000)) return false;\r\n  if (!sendATCommand(subTopic, \"OK\", 5000)) return false;\r\n  delay(200);\r\n  Serial.println(subTopic);\r\n\r\n  mqttConnected = true;\r\n  //Serial.println(\"MQTT连接成功\");\r\n  return true;\r\n}\r\n\r\n// 发布水位信息\r\nbool publishWaterLevel() {\r\n  if (!mqttConnected) return false;\r\n\r\n  Serial.print(\"发布水位信息: \");\r\n  // 构建消息内容\r\n  String message = String(currentWaterLevel);\r\n\r\n  // 按照AT指令序列实现发布流程\r\n  // 设置发布主题\r\n  String cmd = \"AT+CMQTTTOPIC=0,\";\r\n  cmd += String(strlen(pubTopic));\r\n  delay(200);\r\n  Serial.println(pubTopic);\r\n\r\n  // 设置发布负载\r\n  cmd = \"AT+CMQTTPAYLOAD=0,\";\r\n  cmd += String(message.length());\r\n  //if (!sendATCommand(cmd.c_str(), \"OK\", 5000)) return false;\r\n  if (!sendATCommand(message.c_str(), \"OK\", 5000)) return false;\r\n\r\n  // 发布消息\r\n  cmd = \"AT+CMQTTPUB=0,1,\";\r\n  cmd += String(message.length());\r\n  return sendATCommand(cmd.c_str(), \"OK\", 5000);\r\n}\r\n\r\n// 处理串口响应\r\nvoid handleSerialResponses() {\r\n  static unsigned long lastCharTime = 0;\r\n\r\n  while (Serial.available()) {\r\n    char c = Serial.read();\r\n    lastCharTime = millis();\r\n\r\n    // 构建响应字符串\r\n    if (responseIndex < MAX_RESPONSE_LENGTH - 1) {\r\n      responseBuffer[responseIndex++] = c;\r\n      responseBuffer[responseIndex] = \'\\0\';\r\n    }\r\n\r\n    // 检查是否收到完整响应\r\n    if (strstr(responseBuffer, \"\\r\\nOK\\r\\n\") != NULL || strstr(responseBuffer, \"\\r\\nERROR\\r\\n\") != NULL) {\r\n\r\n      processResponse(responseBuffer);\r\n\r\n      // 清空缓冲区\r\n      memset(responseBuffer, 0, MAX_RESPONSE_LENGTH);\r\n      responseIndex = 0;\r\n      awaitingResponse = false;\r\n    }\r\n  }\r\n\r\n  // 超时处理\r\n  if (awaitingResponse && (millis() - lastCharTime > 5000)) {\r\n    Serial.println(\"响应超时\");\r\n    memset(responseBuffer, 0, MAX_RESPONSE_LENGTH);\r\n    responseIndex = 0;\r\n    awaitingResponse = false;\r\n  }\r\n}\r\n\r\n// 处理AT命令响应\r\nvoid processResponse(char* response) {\r\n  Serial.print(\"收到响应: \");\r\n  Serial.println(response);\r\n\r\n  // 在这里可以添加对特定响应的处理逻辑\r\n  if (strstr(response, \"+CMQTTRXMSG:\") != NULL) {\r\n    // 解析接收到的MQTT消息\r\n    processMqttMessage(response);\r\n  }\r\n}\r\n\r\n// 解析MQTT消息\r\nvoid processMqttMessage(char* response) {\r\n  // 实际应用中需要根据模块返回格式解析消息内容\r\n  // 这里只是简单示例\r\n  Serial.println(\"收到MQTT消息\");\r\n\r\n  // 提取消息内容的逻辑...\r\n}\r\n\r\n// 发送AT命令并等待响应\r\nbool sendATCommand(const char* command, const char* expectedResponse, unsigned long timeout) {\r\n  // 等待上一个命令完成\r\n  while (awaitingResponse) {\r\n    handleSerialResponses();\r\n    delay(10);\r\n  }\r\n\r\n\r\n  // 发送命令\r\n  Serial.println(command);\r\n\r\n  // 设置等待响应状态\r\n  awaitingResponse = true;\r\n  currentCommand = command;\r\n\r\n  // 等待响应\r\n  unsigned long startTime = millis();\r\n  while (awaitingResponse && (millis() - startTime < timeout)) {\r\n    handleSerialResponses();\r\n    delay(10);\r\n  }\r\n\r\n  // 检查响应\r\n  if (!awaitingResponse) {\r\n    // 检查是否包含预期响应\r\n    if (strstr(responseBuffer, expectedResponse) != NULL) {\r\n      return true;\r\n    }\r\n  }\r\n\r\n  return false;\r\n}','',1),
(278,4,'SIM900和A7670C使用HTTP和HTTPS','AT     =>OK\r\nAT+CGACT=1      =>+CME ERROR: operation not allowed\r\nAT+CRESET      =>OK  *ATREADY: 1  +CPIN: READY  SMS DONE  +CGEV: EPS PDN ACT 1  +CGEV: ME PDN ACT 8,1\r\nAT+CGDCONT=1,\"IP\",\"CMNET\"    =>OK\r\nAT+CGACT=1,1        =>OK   +CGEV: NW MODIFY 1,0\r\nAT+HTTPINIT     =>OK\r\nAT+HTTPPARA=\"URL\",\"https://www.nobiggie.cn/test/test\"     =>OK\r\nAT+HTTPACTION=0  //http  \r\nAT+HTTPREAD=0,500  //https\r\nOK\r\n+HTTPACTION: 0,200,32587\r\n\r\nAT+HTTPREAD=200     =>OK','',1),
(280,1,'windows自动ssh连接ip批处理','@echo off\r\ntitle SSH连接到服务器\r\necho 正在连接到 192.168.0.254...\r\nssh root@192.168.0.254\r\nif errorlevel 1 (\r\n    echo SSH连接失败！\r\n    echo 请确保：\r\n    echo   1. 已安装OpenSSH客户端（可通过Windows功能启用）\r\n    echo   2. 目标服务器IP地址正确\r\n    echo   3. 目标服务器SSH服务正在运行\r\n    pause\r\n)    ','',1),
(281,4,'arduino GPIO中断','#include <Arduino.h>\r\nconst int INTERRUPT_PIN_1 = 17;\r\nconst int INTERRUPT_PIN_2 = 16;\r\nconst int OUTPUT_PIN_1 = 25;\r\nconst int OUTPUT_PIN_2 = 26;\r\n\r\n// 函数声明\r\nvoid IRAM_ATTR handleInterrupt1();\r\nvoid IRAM_ATTR handleInterrupt2();\r\n\r\nvoid setup() {\r\n  // 初始化输出引脚\r\n  pinMode(OUTPUT_PIN_1, OUTPUT);\r\n  pinMode(OUTPUT_PIN_2, OUTPUT);\r\n\r\n  // 初始化为低电平\r\n  digitalWrite(OUTPUT_PIN_1, LOW);\r\n  digitalWrite(OUTPUT_PIN_2, LOW);\r\n\r\n  // digitalWrite(INTERRUPT_PIN_1, HIGH);\r\n  // digitalWrite(INTERRUPT_PIN_2, HIGH);\r\n  // 设置中断引脚为输入模式，启用上拉电阻\r\n  pinMode(INTERRUPT_PIN_1, INPUT_PULLUP);\r\n  pinMode(INTERRUPT_PIN_2, INPUT_PULLUP);\r\n\r\n  // 附加中断服务函数\r\n  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN_1), handleInterrupt1, FALLING);\r\n  attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN_2), handleInterrupt2, FALLING);\r\n  /*参数说明：\r\n  第一个参数digitalPinToInterrupt(INTERRUPT_PIN_1)：将数字引脚号转换为中断号。\r\n  第二个参数handleInterrupt1：是中断触发后要执行的函数名，此函数不能带有参数，并且返回类型必须为void。\r\n  第三个参数RISING：用来确定中断的触发方式。\r\n  触发模式类型：\r\n  LOW：当引脚为低电平时，会持续触发中断。\r\n  CHANGE：只要引脚电平发生变化，无论是高变低还是低变高，都会触发中断。\r\n  RISING：引脚电平从低电平变为高电平时，触发中断。\r\n  FALLING：引脚电平从高电平变为低电平时，触发中断。\r\n  HIGH（仅适用于 Arduino SAMD 板）：当引脚为高电平时，会持续触发中断。*/\r\n  Serial.begin(115200);\r\n  Serial.println(\"系统初始化完成\");\r\n}\r\n\r\nvoid loop() {\r\n  // 主循环可以处理其他任务\r\n  // 中断会独立于主循环执行\r\n  delay(5000);\r\n  Serial.println(\"loop\");\r\n}\r\n\r\n// 中断服务函数1：当INTERRUPT_PIN_1检测到上升沿时触发\r\nvoid IRAM_ATTR handleInterrupt1() {\r\n  static unsigned long lastInterruptTime = 0;\r\n  unsigned long currentTime = millis();\r\n\r\n  // 消抖处理\r\n  if (currentTime - lastInterruptTime > 50) {\r\n    lastInterruptTime = currentTime;\r\n    // 翻转输出状态\r\n    digitalWrite(OUTPUT_PIN_1, !digitalRead(OUTPUT_PIN_1));\r\n  }\r\n   //中断服务程序（ISR）必须简短，避免调用耗时函数（如串口打印、网络通信），否则可能引发看门狗超时或系统重启\r\n\r\n}\r\n\r\n// 中断服务函数2：当INTERRUPT_PIN_2检测到上升沿时触发\r\nvoid IRAM_ATTR handleInterrupt2() {\r\n  static unsigned long lastInterruptTime = 0;\r\n  unsigned long currentTime = millis();\r\n\r\n  // 消抖处理\r\n  if (currentTime - lastInterruptTime > 50) {\r\n    lastInterruptTime = currentTime;\r\n    digitalWrite(OUTPUT_PIN_2, !digitalRead(OUTPUT_PIN_2));\r\n  }\r\n   //中断服务程序（ISR）必须简短，避免调用耗时函数（如串口打印、网络通信），否则可能引发看门狗超时或系统重启\r\n}','',1),
(284,4,'ESP32物联遥控大门与智能播报','#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <WiFiClientSecure.h>\r\n#include <ArduinoJson.h>\r\n#include <WebSocketsClient.h>\r\n#include <ESP32httpUpdate.h>\r\n\r\n#include <OneWire.h>\r\n#include <DallasTemperature.h>\r\n#include <Adafruit_Sensor.h>\r\n#include <DHT.h>\r\n#include <DHT_U.h>\r\n\r\n#include <WebServer.h>\r\n#include <HTTPClient.h>\r\n#include <FS.h>\r\n#include \"SPIFFS.h\"\r\n#include <Ticker.h>\r\n#include \"esp_sleep.h\"\r\nString version = \"1.24.3\";\r\nDynamicJsonDocument jsonBuffer(100);\r\nJsonObject jsonArr;\r\n\r\nWebSocketsClient webSocket;\r\nWebServer webserver;\r\nTicker myTicker;\r\nWiFiClient wificlient;\r\n\r\n#define doorOpen 22       //升\r\n#define doorClose 21      //降\r\n#define doorOpenEXTI 26   //升 中断\r\n#define doorCloseEXTI 25  //降 中断\r\n#define dhtPin 0          //温湿度传感器\r\n#define DHTTYPE DHT11     //传感器类型\r\nDHT_Unified dht(dhtPin, DHTTYPE);\r\n\r\n#define billboard1 4           //广告牌开关\r\n#define billboard2 13          //寄快递广告牌\r\nbool guangGaoPaiBool = false;  //guangGaoPaiBool为false代表没有开灯箱 true为已开启灯箱\r\n\r\n#define broadcast 2   //播报电源开关\r\n#define doorPower 15  //电源总开关\r\n\r\nbool xrty = false;\r\n//开关状态 10为上升上限  0为下降上限 5为可以上升可降\r\nint stroke = 5;\r\nString localServerIP = \"192.168.0.254\";\r\nString upBinUrl = \"http://\" + localServerIP + \"/tool/ota/GolangCpp/mydoor1.bin\";\r\n\r\nString localDateH = \"http://\" + localServerIP + \"/time/h\";  //获取小时\r\n\r\nString localDate = \"http://\" + localServerIP + \"/time/date\";  //获取时间\r\nString ssid = \"\";                                             //wifi账号\r\nString passwd = \"\";                                           //wifi密码\r\nString html;                                                  //存html\r\nString flash_wifi = \"/wifi.txt\";                              //被读取的文件位置和名称\r\nint wsTimeOut = 0;\r\nString UserExec;\r\n\r\nint execStatus = 9;     //此时执行中的状态  0关门  1开门  2停止 5中断正常触发模式  9什么也不代表\r\nbool scanBool = false;  //ture为开启扫描状态\r\n\r\n// 函数声明\r\nvoid IRAM_ATTR handleInterruptOpen();\r\nvoid IRAM_ATTR handleInterruptClose();\r\n\r\nvolatile bool extiOpen = false;   //true 代表上升中断触发了\r\nvolatile bool extiClose = false;  //true 代表下降中断触发了\r\n\r\nvolatile unsigned long extiTime = 0;\r\n\r\nvoid hexdump(const void* mem, uint32_t len, uint8_t cols = 16) {\r\n  const uint8_t* src = (const uint8_t*)mem;\r\n  Serial.printf(\"\\n[HEXDUMP] Address: 0x%08X len: 0x%X (%d)\", (ptrdiff_t)src, len, len);\r\n  for (uint32_t i = 0; i < len; i++) {\r\n    if (i % cols == 0) {\r\n      Serial.printf(\"\\n[0x%08X] 0x%08X: \", (ptrdiff_t)src, i);\r\n    }\r\n    Serial.printf(\"%02X \", *src);\r\n    src++;\r\n  }\r\n  Serial.printf(\"\\n\");\r\n}\r\n\r\nvoid webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {\r\n  String tmpH;\r\n  switch (type) {\r\n    case WStype_DISCONNECTED:\r\n      digitalWrite(doorOpen, LOW);\r\n      digitalWrite(doorClose, LOW);\r\n      Serial.println(\"Disconnected 开关状态全部关闭一下\");\r\n\r\n      //防止开启突然没有网络,lop循环检测不到状态 这里再进行检测\r\n      if (digitalRead(doorOpenEXTI) == HIGH && stroke != 10) {\r\n        stroke = 10;\r\n        closeAll();\r\n        Serial.println(\"Disconnected  上限关闭\");\r\n      }\r\n      //查询是否下降 限制,及时把状态改好\r\n      if (digitalRead(doorCloseEXTI) == HIGH && stroke != 0) {\r\n        stroke = 0;\r\n        closeAll();\r\n        Serial.println(\"Disconnected  下限关闭\");\r\n      }\r\n      wsTimeOut++;\r\n      //无法连接远程WSS服务器15次就自动 启动网页控制\r\n      if (wsTimeOut > 30) {\r\n        closeAll();\r\n        delay(500);\r\n        webSocket.disconnect();\r\n        delay(500);\r\n        //计数器归0\r\n        wsTimeOut = 0;\r\n        ESP.restart();\r\n      }\r\n      break;\r\n    case WStype_CONNECTED:\r\n      Serial.printf(\"[WSc] Connected to url: %s\\n\", payload);\r\n      //计数器归0\r\n      wsTimeOut = 0;\r\n      delay(200);\r\n      //防止开启突然没有网络,lop循环检测不到状态 这里再进行检测\r\n      if (digitalRead(doorOpenEXTI) == LOW && digitalRead(doorCloseEXTI) == LOW) {\r\n        stroke = 5;\r\n      } else {\r\n        if (digitalRead(doorOpenEXTI) == HIGH) {\r\n          stroke = 10;\r\n        } else {\r\n          stroke = 0;\r\n        }\r\n      }\r\n      tmpH = esp32get(localDateH);\r\n      if (tmpH.length() > 0) {\r\n        int dateL = tmpH.toInt();\r\n        if (dateL > 6 && dateL < 18) {\r\n          digitalWrite(billboard1, HIGH);  //连接成功 这个时间段打开广告牌\r\n        }\r\n      }\r\n      break;\r\n    case WStype_TEXT:\r\n      Serial.printf(\"[WSc] get text: %s\\n\", payload);\r\n      deserializeJson(jsonBuffer, payload);\r\n      jsonArr = jsonBuffer.as<JsonObject>();\r\n      if (jsonArr[\"message\"] != \"\") {\r\n        String user = jsonArr[\"user\"];\r\n        String date = jsonArr[\"date\"];\r\n        String message = jsonArr[\"message\"];\r\n        if (message == \"mydoor1.open\") {\r\n          xrty = false;\r\n          //限位开关导通为低电平 表明还没有达到限位,并且没有达到上升最大限制 能正常上升,断开为高电平表明达到限位了\r\n          if (digitalRead(doorOpenEXTI) == LOW && stroke != 10) {\r\n            //主电源接通\r\n            digitalWrite(doorPower, HIGH);\r\n            delay(200);\r\n            //开 上升\r\n            webSocket.sendTXT(\"正在开门 ...\");\r\n            digitalWrite(doorClose, LOW);\r\n            delay(50);\r\n            digitalWrite(doorOpen, HIGH);\r\n            UserExec = user + \" 开门 \" + date;\r\n            execStatus = 1;\r\n\r\n          } else {\r\n            webSocket.sendTXT(\"无效,上升达到限制\");\r\n          }\r\n          return;\r\n        }\r\n\r\n        if (message == \"mydoor1.stop\") {\r\n          Serial.println(\"停止\");\r\n          closeAll();\r\n          //如果不在上限也不在下限时  悬停设置\r\n          if (digitalRead(doorOpenEXTI) == LOW && digitalRead(doorCloseEXTI) == LOW) {\r\n            stroke = 5;\r\n            if (!xrty) {\r\n              xrty = true;\r\n              webSocket.sendTXT(\"悬停播报设置成功\");\r\n            } else {\r\n              webSocket.sendTXT(\"悬停\");\r\n            }\r\n            delay(200);\r\n          } else {\r\n            //不是上升上限就是下降上限\r\n            xrty = false;\r\n            //查询是否下降 限制,及时把状态改好\r\n            if (digitalRead(doorOpenEXTI) == HIGH) {\r\n              stroke = 10;\r\n              String tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n              String rez = \"开门达到限制 \" + tempstr;\r\n              webSocket.sendTXT(rez);\r\n            } else {\r\n              stroke = 0;\r\n              String tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n              String rez = \"关门达到限制 \" + tempstr;\r\n              webSocket.sendTXT(rez);\r\n            }\r\n          }\r\n          return;\r\n        }\r\n        if (message == \"mydoor1.close\") {\r\n          xrty = false;\r\n          //限位开关导通时为低电平表明还没有达到限位,并且没到达到下降最大限制  能正常下降,断开为高电平表明达到限位了\r\n          if (digitalRead(doorCloseEXTI) == LOW && stroke != 0) {\r\n            //主电源接通\r\n            digitalWrite(doorPower, HIGH);\r\n            delay(200);\r\n            //关 下降\r\n            webSocket.sendTXT(\"正在关门 ...\");\r\n            digitalWrite(doorOpen, LOW);\r\n            delay(50);\r\n            digitalWrite(doorClose, HIGH);\r\n            UserExec = user + \" 关门 \" + date;\r\n            execStatus = 0;\r\n          } else {\r\n            webSocket.sendTXT(\"无效,关门达到限制\");\r\n          }\r\n          return;\r\n        }\r\n        if (message == \"mydoor1.TemperatureHumidity\") {\r\n          float temperature;\r\n          float humidity;\r\n          sensors_event_t event;\r\n          dht.temperature().getEvent(&event);\r\n          if (isnan(event.temperature)) {\r\n            Serial.println(F(\"Error reading temperature!\"));\r\n          } else {\r\n            temperature = event.temperature;\r\n          }\r\n          delay(500);\r\n          // Get humidity event and print its value.\r\n          dht.humidity().getEvent(&event);\r\n          if (isnan(event.relative_humidity)) {\r\n            Serial.println(F(\"Error reading humidity!\"));\r\n          } else {\r\n            humidity = event.relative_humidity;\r\n          }\r\n          String th = String(temperature) + \",\" + String(int(humidity));\r\n          webSocket.sendTXT(th);\r\n          return;\r\n        }\r\n        if (message == \"mydoor1.records\") {  //查看最后操作人\r\n          webSocket.sendTXT(UserExec);\r\n          return;\r\n        }\r\n        if (message == \"mydoor1.billboard\") {\r\n          if (guangGaoPaiBool == false) {\r\n            digitalWrite(billboard1, HIGH);\r\n            guangGaoPaiBool = true;\r\n            if (user == \"系统任务\") {\r\n              String strtem = \"系统任务 广告牌1已开\";\r\n              webSocket.sendTXT(strtem);\r\n            } else {\r\n              String strtem = user + \" 广告牌1已开\";\r\n              webSocket.sendTXT(strtem);\r\n            }\r\n          } else {\r\n            digitalWrite(billboard1, LOW);\r\n            guangGaoPaiBool = false;\r\n            if (user == \"系统任务\") {\r\n              String strtem = \"系统任务 广告牌1已关\";\r\n              webSocket.sendTXT(strtem);\r\n            } else {\r\n              String strtem = user + \" 广告牌1已关\";\r\n              webSocket.sendTXT(strtem);\r\n            }\r\n          }\r\n          return;\r\n        }\r\n        if (message == \"mydoor1.billboardOn1\") {\r\n          guangGaoPaiBool = true;\r\n          digitalWrite(billboard1, HIGH);\r\n          String strtem = \"系统任务 广告牌1灯已开\";\r\n          webSocket.sendTXT(strtem);\r\n          return;\r\n        }\r\n        if (message == \"mydoor1.billboardOff1\") {\r\n          guangGaoPaiBool = false;\r\n          digitalWrite(billboard1, LOW);\r\n          String strtem = \"系统任务 广告牌1灯已关\";\r\n          webSocket.sendTXT(strtem);\r\n          return;\r\n        }\r\n        if (message == \"mydoor1.dormancy\") {  //休眠两个小时\r\n          espSleep();\r\n          return;\r\n        }\r\n\r\n        if (message == \"mydoor1.ScanOpen\") {  //扫码开\r\n          scanBool = true;\r\n          digitalWrite(broadcast, HIGH);\r\n        }\r\n        if (message == \"mydoor1.ScanClose\") {  //扫码关 按停止键也是会关的\r\n          scanBool = false;\r\n          digitalWrite(broadcast, LOW);\r\n        }\r\n\r\n        if (message == \"mydoor1.reboot\") {\r\n          ESP.restart();\r\n        }\r\n        if (message == \"mydoor1.version\") {\r\n          webSocket.sendTXT(version);\r\n        }\r\n        if (message == \"mydoor1.updateBin\") {\r\n          // 执行 OTA 更新前的准备工作\r\n          noInterrupts();                                         // 关闭全局中断\r\n          detachInterrupt(digitalPinToInterrupt(doorOpenEXTI));   // 禁用特定中断源（如果需要）\r\n          detachInterrupt(digitalPinToInterrupt(doorCloseEXTI));  // 禁用特定中断源（如果需要）\r\n          delay(200);\r\n          while (1) {\r\n            t_httpUpdate_return ret =ESPhttpUpdate.update(upBinUrl);\r\n            switch (ret) {\r\n              case HTTP_UPDATE_FAILED:  //更新失败\r\n                webSocket.sendTXT(\"更新失败\");\r\n                Serial.printf(\"HTTP_UPDATE_FAILD Error (%d): %s\", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());\r\n                break;\r\n              case HTTP_UPDATE_NO_UPDATES:  //无需更新\r\n                webSocket.sendTXT(\"无需更新\");\r\n                break;\r\n              case HTTP_UPDATE_OK:  //更新成功\r\n                webSocket.sendTXT(\"更新成功\");\r\n                Serial.println(\"HTTP_UPDATE_OK\");\r\n                break;\r\n            }\r\n\r\n            interrupts();  // 恢复全局中断\r\n            espReboot();\r\n          }\r\n        }\r\n        if (message.indexOf(\"mydoor1.billboardOn2\") != -1) {  //13脚高电平 广告牌2开启\r\n          digitalWrite(billboard2, HIGH);\r\n          String strtem = \"系统任务 广告牌2已开\";\r\n          webSocket.sendTXT(strtem);\r\n        }\r\n        if (message == \"mydoor1.billboardOff2\") {  //13脚低电平 广告牌2关闭\r\n          digitalWrite(billboard2, LOW);\r\n          String strtem = \"系统任务 广告牌2已关\";\r\n          webSocket.sendTXT(strtem);\r\n        }\r\n      }\r\n      // send message to server\r\n      // webSocket.sendTXT(\"message here\");\r\n      break;\r\n    case WStype_BIN:\r\n      //语音是以 []byte 传输\r\n      Serial.printf(\"[WSc] get binary length: %u\\n\", length);\r\n      //hexdump(payload, length);\r\n      //防止大门开启的时候,同时播报导致大门控制失灵 只有在上,下限的时候才播报\r\n      if (digitalRead(doorOpenEXTI) == HIGH) {\r\n        if (scanBool) {\r\n          Serial.write(payload, length);\r\n        } else {\r\n          bobao(payload, length);\r\n        }\r\n        return;\r\n      } else {\r\n        if (digitalRead(doorCloseEXTI) == HIGH) {\r\n          if (scanBool) {\r\n            Serial.write(payload, length);\r\n          } else {\r\n            bobao(payload, length);\r\n          }\r\n          return;\r\n        }\r\n      }\r\n\r\n      if (xrty) {\r\n        if (scanBool) {\r\n          Serial.write(payload, length);\r\n        } else {\r\n          bobao(payload, length);\r\n        }\r\n        return;\r\n      }\r\n\r\n      // send data to server\r\n      // webSocket.sendBIN(payload, length);\r\n      break;\r\n    case WStype_ERROR:\r\n    case WStype_FRAGMENT_TEXT_START:\r\n    case WStype_FRAGMENT_BIN_START:\r\n    case WStype_FRAGMENT:\r\n    case WStype_FRAGMENT_FIN:\r\n      break;\r\n  }\r\n}\r\n\r\nvoid setup() {\r\n  pinMode(doorOpen, OUTPUT);    //门上升\r\n  pinMode(doorClose, OUTPUT);   //门下降\r\n  pinMode(billboard1, OUTPUT);  //广播牌\r\n  pinMode(broadcast, OUTPUT);   //语音播报\r\n  pinMode(doorPower, OUTPUT);   //总电源\r\n  pinMode(billboard2, OUTPUT);\r\n  digitalWrite(doorOpen, LOW);\r\n  digitalWrite(doorClose, LOW);\r\n  digitalWrite(billboard1, LOW);\r\n  digitalWrite(broadcast, LOW);\r\n  digitalWrite(doorPower, LOW);\r\n  digitalWrite(billboard2, LOW);\r\n\r\n  pinMode(doorOpenEXTI, INPUT_PULLUP);  //上拉电阻模式,默认高电平\r\n  pinMode(doorCloseEXTI, INPUT_PULLUP);\r\n\r\n  // 附加中断服务函数\r\n  attachInterrupt(digitalPinToInterrupt(doorOpenEXTI), handleInterruptOpen, FALLING);\r\n  attachInterrupt(digitalPinToInterrupt(doorCloseEXTI), handleInterruptClose, FALLING);\r\n  /*参数说明：\r\n  第一个参数digitalPinToInterrupt(INTERRUPT_PIN_1)：将数字引脚号转换为中断号。\r\n  第二个参数handleInterrupt1：是中断触发后要执行的函数名，此函数不能带有参数，并且返回类型必须为void。\r\n  第三个参数RISING：用来确定中断的触发方式。\r\n  触发模式类型：\r\n  LOW：当引脚为低电平时，会持续触发中断。\r\n  CHANGE：只要引脚电平发生变化，无论是高变低还是低变高，都会触发中断。\r\n  RISING：引脚电平从低电平变为高电平时，触发中断。\r\n  FALLING：引脚电平从高电平变为低电平时，触发中断。\r\n  HIGH（仅适用于 Arduino SAMD 板）：当引脚为高电平时，会持续触发中断。*/\r\n\r\n\r\n  Serial.begin(115200);\r\n\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    SPIFFS.begin();\r\n    File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n    dataFile.println(\"webserver&www.nobiggie.cn\");\r\n    dataFile.close();\r\n  }\r\n\r\n  //pinMode(flash_rst, INPUT_PULLUP);\r\n  delay(200);\r\n  dht.begin();\r\n  sensor_t sensor;\r\n  dht.temperature().getSensor(&sensor);\r\n  dht.humidity().getSensor(&sensor);\r\n  delay(500);\r\n  if (FlashConnetWifi() == false) {  //自动flash联网不成功 就启用 html配置wifi账号密码\r\n    HtmlSetWifi();\r\n  }\r\n  delay(300);\r\n\r\n  //通知服务器 我正在重启,验证一下广告牌开关状态 10秒后我启动完成发送广告牌开关状态给我\r\n  billboardPost();\r\n  webSocket.begin(localServerIP, 80, \"/websocket\");\r\n  webSocket.onEvent(webSocketEvent);\r\n  webSocket.setAuthorization(\"user=mydoor1&passwd=efghijk&room=door\");\r\n  webSocket.setReconnectInterval(5000);\r\n  if (digitalRead(doorOpenEXTI) == HIGH) {\r\n    stroke = 10;\r\n  }\r\n  if (digitalRead(doorCloseEXTI) == HIGH) {\r\n    stroke = 0;\r\n  }\r\n}\r\nvoid loop() {\r\n  webSocket.loop();\r\n\r\n\r\n  if (extiTime > 0) {\r\n    unsigned long currentTime = millis();\r\n    if ((extiTime - currentTime) > 1500) {\r\n      execStatus = 5;  //中断 正常触发模式开启\r\n      extiTime = 0;\r\n      webSocket.sendTXT(\"中断 正常触发模式开启\");\r\n      return;\r\n    }\r\n    if (extiOpen) {  //上升中断触发\r\n      xrty = false;\r\n      extiOpen = false;\r\n      if (execStatus == 1) {\r\n        stroke = 10;\r\n        execStatus = 9;  //执行状态为空\r\n        extiTime = 0;\r\n        digitalWrite(doorPower, LOW);  //断开电源接通\r\n        webSocket.sendTXT(\"正常模式 上升中断触发\");\r\n      }\r\n      return;\r\n    }\r\n    if (extiClose) {  //下降中断触发\r\n      xrty = false;\r\n      extiClose = false;\r\n      if (execStatus == 0) {\r\n        stroke = 0;\r\n        execStatus = 9;  //执行状态为空\r\n        extiTime = 0;\r\n        digitalWrite(doorPower, LOW);   //断开电源接通\r\n        digitalWrite(billboard1, LOW);  //关门就把广告灯箱关了\r\n        webSocket.sendTXT(\"正常模式 下降中断触发\");\r\n      }\r\n      return;\r\n    }\r\n  }\r\n  //即没有上限也没有下限状态\r\n\r\n  if (digitalRead(doorOpenEXTI) == LOW && digitalRead(doorCloseEXTI) == LOW) {\r\n    stroke = 5;\r\n    return;\r\n  }\r\n  if (digitalRead(doorOpenEXTI) == HIGH) {  //上升达到限制\r\n    if (stroke != 10) {                     //第一次 加一层保险 停止上升\r\n      digitalWrite(doorOpen, LOW);\r\n\r\n      webSocket.sendTXT(\"loop上升限制触发\");\r\n    }\r\n    stroke = 10;\r\n    return;\r\n  }\r\n  if (digitalRead(doorCloseEXTI) == HIGH) {  //下降达到限制\r\n    if (stroke != 0) {                       //第一次 加一层保险 停止下降\r\n      digitalWrite(doorClose, LOW);\r\n\r\n      webSocket.sendTXT(\"loop下降限制触发\");\r\n    }\r\n    stroke = 0;\r\n    return;\r\n  }\r\n}\r\n\r\n\r\nvoid IRAM_ATTR handleInterruptOpen() {\r\n  static unsigned long lastInterruptTime = 0;\r\n  unsigned long currentTime = millis();\r\n  if (execStatus == 1) {\r\n    if (extiTime == 0) {\r\n      extiTime = currentTime;\r\n    }\r\n  } else {\r\n    // 消抖处理\r\n    if (currentTime - lastInterruptTime > 20) {  //调到50有时候上升不能触发中断\r\n      lastInterruptTime = currentTime;\r\n      if (digitalRead(doorOpenEXTI) == HIGH) {\r\n        digitalWrite(doorOpen, LOW);\r\n        if (execStatus == 1) {           //此时执行中的状态  0关门  1开门  2停止 5中断正常触发模式  9什么也不代表\r\n          digitalWrite(doorPower, LOW);  //断开电源接通\r\n        }\r\n        //开门中断\r\n        extiOpen = true;\r\n        //中断服务程序（ISR）必须简短，避免调用耗时函数（如串口打印、网络通信），否则可能引发看门狗超时或系统重启\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\n\r\nvoid IRAM_ATTR handleInterruptClose() {\r\n  static unsigned long lastInterruptTime = 0;\r\n  unsigned long currentTime = millis();\r\n  if (execStatus == 0) {\r\n    if (extiTime == 0) {\r\n      extiTime = currentTime;\r\n    }\r\n  } else {\r\n    // 消抖处理\r\n    if (currentTime - lastInterruptTime > 20) {\r\n      lastInterruptTime = currentTime;\r\n      if (digitalRead(doorCloseEXTI) == HIGH) {\r\n        digitalWrite(doorClose, LOW);\r\n        if (execStatus == 0) {           //0关门 状态\r\n          digitalWrite(doorPower, LOW);  //断开电源接通\r\n        }\r\n        //关门中断\r\n        extiClose = true;\r\n        //中断服务程序（ISR）必须简短，避免调用耗时函数（如串口打印、网络通信），否则可能引发看门狗超时或系统重启\r\n      }\r\n    }\r\n  }\r\n}\r\n//关闭上升,下降,变压器主电源\r\nvoid closeAll() {\r\n  digitalWrite(doorOpen, LOW);\r\n  digitalWrite(doorClose, LOW);\r\n  delay(200);\r\n  digitalWrite(doorPower, LOW);  //断开电源接通\r\n  scanBool = false;              //扫描状态关闭\r\n  digitalWrite(broadcast, LOW);  //扫描关\r\n}\r\nvoid espReboot() {\r\n  ESP.restart();\r\n}\r\n//无网特殊状态下安全限位\r\nvoid html_whlie() {\r\n  //操作运行时 上升达到限位了,并且上次状态不是上升上限, 并且执行状态是上升 限位开关断开\r\n  if (digitalRead(doorOpenEXTI) == HIGH || digitalRead(doorCloseEXTI) == HIGH) {\r\n    //关闭所有开关\r\n    closeAll();\r\n    Serial.println(\"达到上限\");\r\n    myTicker.detach();\r\n    delay(200);\r\n    ESP.restart();\r\n  }\r\n}\r\nvoid billboardPost() {\r\n  HTTPClient http;\r\n  String response;\r\n  String postStr = \"a=a\";\r\n  String tmp = \"http://\" + localServerIP + \"/time/bill-board\";\r\n  http.begin(wificlient, tmp);\r\n  http.setTimeout(500);\r\n  //需要传输的数据\r\n  char dataBuff[postStr.length()];\r\n  strcpy(dataBuff, postStr.c_str());\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  http.POST(dataBuff);\r\n  http.end();\r\n}\r\n\r\nvoid espSleep() {\r\n  closeAll();\r\n  delay(500);\r\n  webSocket.sendTXT(\"mydoor1休眠两个半小时...\");\r\n  delay(200);\r\n  webSocket.disconnect();\r\n  delay(300);\r\n  WiFi.disconnect();\r\n  myTicker.detach();\r\n  delay(200);\r\n  //进入深睡眠状态，将在 3 小时后唤醒\r\n  esp_sleep_enable_timer_wakeup(10800000000);\r\n  esp_deep_sleep_start();\r\n}\r\nString esp32post(String url) {\r\n  HTTPClient http;\r\n  http.begin(wificlient, url);\r\n  http.setTimeout(3000);\r\n  String postStr = \"version=esp32test10\";\r\n  char dataBuff[postStr.length()];\r\n  strcpy(dataBuff, postStr.c_str());\r\n  http.addHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\r\n  int httpResponseCode = http.POST(dataBuff);\r\n  if (httpResponseCode > 0) {\r\n    String response = http.getString();\r\n    return response;\r\n  }\r\n  return \"\";\r\n}\r\nString esp32get(String urlstr) {\r\n  HTTPClient http;\r\n  String response;\r\n  http.begin(wificlient, urlstr);\r\n  http.setTimeout(3000);\r\n  int httpCode = http.GET();\r\n  // httpCode will be negative on error\r\n  if (httpCode == 200) {\r\n    response = http.getString();\r\n    return response;\r\n  } else {\r\n    return \"\";\r\n  }\r\n  http.end();\r\n}\r\n\r\nvoid SetWifi() {\r\n  ssid = webserver.arg(0);\r\n  passwd = webserver.arg(1);\r\n  String sp = ssid + \"&\" + passwd;\r\n  Serial.println(sp);\r\n  Serial.println(\"密码在前面\");\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  const char* Ssid = ssid.c_str();\r\n  const char* WifiPw = passwd.c_str();\r\n  WiFi.begin(Ssid, WifiPw);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  Serial.println(\"wifi_connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      webserver.send(200, \"text/plane\", \"Wifi密码正确,ESP准备重启\");\r\n      webserver.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n\r\n      Serial.println(\"HTML连接成功\");\r\n      delay(500);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  webserver.send(200, \"text/plane\", \"Wifi密码错误,请重新输入\");\r\n}\r\n//------- 展示页面-------\r\nvoid handlejsonArr() {\r\n  webserver.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  webserver.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\n\r\nvoid ApStart() {\r\n  WiFi.disconnect();\r\n  delay(500);\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n\r\n  //启动AP模式,并设置账号和密码\r\n  WiFi.softAP(\"192.168.168.2\", \"\");\r\n}\r\nvoid webserverStart() {\r\n  //-----------------启动webserver网络服务--------------------\r\n  webserver.begin(80);               // 启用网络服务\r\n  webserver.on(\"/\", handlejsonArr);  // / 在HTTP中,表示请求首页服务,\r\n  webserver.on(\"/SetWifi\", SetWifi);\r\n  webserver.onNotFound(handleNotFound);  // 当服务器没找到所需的服务,调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\n\r\nvoid ForPing() {\r\n  //定时时间到了,先取消定时状态\r\n  myTicker.detach();\r\n  closeAll();\r\n  delay(500);\r\n\r\n  ESP.restart();\r\n}\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  Serial.begin(115200);\r\n  WiFi.disconnect();\r\n  WiFi.mode(WIFI_STA);\r\n  delay(100);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    Serial.println(n);\r\n    String a = \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a + \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" + \"<html>\" + \"<head>\" + \"<meta charset=\\\"utf-8\\\">\" + \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" + \"<title>设置WiFi</title>\" + \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" + \"</head>\" + \"<script>\" + \"onload  = function() {\" + \"document.getElementById(\\\"up\\\").onclick = function(){\" + \"var ssida=document.getElementById(\\\"ssid\\\").value;\" + \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" + \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" + \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" + \"xhr = new XMLHttpRequest();\" + \"xhr.open(\\\"POST\\\",\\\"./SetWifi\\\",true);\" + \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" + \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" + \"xhr.send(posts);\" + \"xhr.onreadystatechange = function(){\" + \"if(this.readyState == 4 && this.status == 200){\" + \"alert(this.responseText);\" + \"}\" + \"}\" + \"}\" + \"}\" + \"</script>\" + \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" + \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" + \"<hr/>\" + \"<font color=\\\"red\\\">附近WiFi没有显示到自己的WIFI请重启或离信号源近点</font>\" + \"</body>\" + \"</html>\";\r\n    a = a + \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"扫描不到网络\";\r\n    Serial.println(\"扫描不到网络\");\r\n  }\r\n}\r\nbool FlashConnetWifi() {\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  //是否存在数据\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    Serial.print(flash_wifi);\r\n    Serial.println(\" NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flash_wifi, \"r\");\r\n  String result = dateFile.readString();\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char* Ssid = wifiname.c_str();\r\n  const char* WifiPw = wifipw.c_str();\r\n  Serial.println(Ssid);\r\n  Serial.println(WifiPw);\r\n  WiFi.begin(Ssid, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  int wifiTimeout = 0;\r\n  for (wifiTimeout; wifiTimeout < 30; wifiTimeout++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"FlashConnetWifi-> timeout\");\r\n  return false;\r\n}\r\n\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  ApStart();\r\n  delay(1000);\r\n  Serial.println(\"启动网页\");\r\n  myTicker.detach();\r\n  delay(200);\r\n  //5分后重启 防止停电后复电,路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式,所以这里只让AP 激活5分钟后就重启\r\n  myTicker.once(300, espReboot);\r\n  delay(200);\r\n  webserverStart();\r\n  while (1) {\r\n    webserver.handleClient();  // 检查网络服务请求并处理\r\n  }\r\n}\r\n\r\nvoid bobao(uint8_t* message, int len) {  //定时播报\r\n  if (!scanBool) {                       //如果不是 扫描状态 延迟25秒关闭播报开关\r\n    digitalWrite(broadcast, HIGH);\r\n    delay(2000);\r\n    //String data = \"020104C0\";\r\n    Serial.write(message, len);\r\n\r\n    delay(25000);\r\n    digitalWrite(broadcast, LOW);\r\n  }\r\n}','',1),
(285,4,'ESP32物联遥控大门与智能播报(中断)','#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <PubSubClient.h>\r\n#include <HTTPUpdate.h>\r\n#include <OneWire.h>\r\n#include <DallasTemperature.h>\r\n#include <Adafruit_Sensor.h>\r\n#include <DHT.h>\r\n#include <DHT_U.h>\r\n#include <Ticker.h>\r\n#include <esp_sleep.h>\r\n#include <FS.h>\r\n#include <SPIFFS.h>\r\n#include <WebServer.h>\r\n#define doorOpen 22       //升\r\n#define doorClose 21      //降\r\n#define doorOpenEXTI 26   //升 中断\r\n#define doorCloseEXTI 25  //降 中断\r\n#define dhtPin 0          //温湿度传感器\r\n#define DHTTYPE DHT11     //传感器类型\r\nDHT_Unified dht(dhtPin, DHTTYPE);\r\n\r\n#define billboard1 4           //广告牌开关\r\n#define billboard2 13          //寄快递广告牌\r\nbool guangGaoPaiBool = false;  //guangGaoPaiBool为false代表没有开灯箱 true为已开启灯箱\r\n\r\n#define light 2       //灯\r\n#define gpio17 17     //播报电源开关\r\n#define doorPower 15  //电源总开关\r\nString version = \"1.24.7\";\r\nString ssid = \"\";                 //wifi账号\r\nString passwd = \"\";               //wifi密码\r\nString html;                      //存html\r\nString flash_wifi = \"/wifi.txt\";  //被读取的文件位置和名称\r\nWebServer webserver;\r\n\r\nvolatile int doorStroke = 5;   //记录门静止状态 处于什么位置 10为上限  0为下限 5为可以上升可降\r\nvolatile bool runIng = false;  //true 为电机正在运行\r\nvolatile int command = 2;      //此时执行的指令  0关门  1开门  2停止\r\n// 函数声明\r\nvoid IRAM_ATTR handleInterruptOpen();\r\nvoid IRAM_ATTR handleInterruptClose();\r\n\r\nvolatile bool extiOpen = false;   //true 代表上升中断触发了\r\nvolatile bool extiClose = false;  //true 代表下降中断触发了\r\nvolatile unsigned long extiTime = 0;\r\n\r\n\r\nWiFiClient wificlient;\r\n\r\nTicker myTicker;\r\n\r\nconst char* mqtt_server = \"192.168.0.254\";\r\nconst char* mqtt_username = \"door1\";\r\nconst char* mqtt_password = \"abcdefg\";\r\nconst char* subTopic = \"wifi/door1/control\";\r\nconst char* pubshTopic = \"wifi/door1/data\";\r\nPubSubClient client(wificlient);\r\n\r\nString upBinUrl = \"http://\" + String(mqtt_server) + \"/tool/ota/GolangCpp/mydoor1.bin\";\r\nvoid setup(void) {\r\n  pinMode(doorOpen, OUTPUT);    //门上升\r\n  pinMode(doorClose, OUTPUT);   //门下降\r\n  pinMode(billboard1, OUTPUT);  //广播牌\r\n  pinMode(gpio17, OUTPUT);      //语音播报\r\n  pinMode(light, OUTPUT);\r\n  pinMode(doorPower, OUTPUT);  //总电源\r\n  pinMode(billboard2, OUTPUT);\r\n\r\n  digitalWrite(doorOpen, LOW);\r\n  digitalWrite(doorClose, LOW);\r\n  digitalWrite(billboard1, LOW);\r\n  digitalWrite(gpio17, LOW);\r\n  digitalWrite(light, LOW);\r\n  digitalWrite(doorPower, LOW);\r\n  digitalWrite(billboard2, LOW);\r\n\r\n  pinMode(doorOpenEXTI, INPUT_PULLUP);  //上拉电阻模式,默认高电平\r\n  pinMode(doorCloseEXTI, INPUT_PULLUP);\r\n\r\n  // 附加中断服务函数\r\n  attachInterrupt(digitalPinToInterrupt(doorOpenEXTI), handleInterruptOpen, CHANGE);\r\n  attachInterrupt(digitalPinToInterrupt(doorCloseEXTI), handleInterruptClose, CHANGE);\r\n\r\n\r\n  Serial.begin(115200);\r\n  //pinMode(flash_rst, INPUT_PULLUP);\r\n  delay(200);\r\n  dht.begin();\r\n  sensor_t sensor;\r\n  dht.temperature().getSensor(&sensor);\r\n  dht.humidity().getSensor(&sensor);\r\n  delay(500);\r\n\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    SPIFFS.begin();\r\n    File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n    dataFile.println(\"webserver&www.nobiggie.cn\");\r\n    dataFile.close();\r\n  }\r\n\r\n  if (FlashConnetWifi() == false) {  //自动flash联网不成功 就启用 html配置wifi账号密码\r\n    HtmlSetWifi();\r\n  }\r\n  Serial.println(\"wifi ok\");\r\n  client.setServer(mqtt_server, 1883);\r\n  client.setCallback(mqttCallback);\r\n  delay(200);\r\n  if (digitalRead(doorOpenEXTI) == LOW && digitalRead(doorCloseEXTI) == LOW) {\r\n    doorStroke = 5;\r\n  } else {\r\n    if (digitalRead(doorOpenEXTI) == HIGH) {\r\n      doorStroke = 10;\r\n    }\r\n    if (digitalRead(doorCloseEXTI) == HIGH) {\r\n      doorStroke = 0;\r\n    }\r\n  }\r\n}\r\n\r\nvoid loop(void) {\r\n  if (!client.connected()) {\r\n    digitalWrite(doorOpen, LOW);\r\n    digitalWrite(doorClose, LOW);\r\n\r\n    //防止开启突然没有网络,lop循环检测不到状态 这里再进行检测\r\n    if (digitalRead(doorOpenEXTI) == HIGH && doorStroke != 10) {\r\n      doorStroke = 10;\r\n      closeAll();\r\n      //Serial.println(\"Disconnected  上限关闭\");\r\n    }\r\n    //查询是否下降 限制,及时把状态改好\r\n    if (digitalRead(doorCloseEXTI) == HIGH && doorStroke != 0) {\r\n      doorStroke = 0;\r\n      closeAll();\r\n      //Serial.println(\"Disconnected  下限关闭\");\r\n    }\r\n    reconnect();\r\n  }\r\n  client.loop();\r\n  if (extiOpen) {      //上升中断触发\r\n    extiOpen = false;  //复位\r\n    if (command == 1) {\r\n      doorStroke = 10;               //位置变为上限\r\n      command = 2;                   //命令变为停止\r\n      extiTime = 0;                  //防抖复位\r\n      digitalWrite(doorPower, LOW);  //断开电源接通\r\n      const char* tmp = \"上升中断触发了\";\r\n      client.publish(pubshTopic, tmp);\r\n    }\r\n    return;\r\n  }\r\n  if (extiClose) {      //下降中断触发\r\n    extiClose = false;  //复位\r\n    if (command == 0) {\r\n      doorStroke = 0;                 //位置变为下限\r\n      command = 2;                    //命令变为停止\r\n      extiTime = 0;                   //防抖复位\r\n      digitalWrite(doorPower, LOW);   //断开电源接通\r\n      digitalWrite(billboard1, LOW);  //关门就把广告灯箱关了\r\n      const char* tmp = \"下降中断触发了\";\r\n      client.publish(pubshTopic, tmp);\r\n    }\r\n    return;\r\n  }\r\n}\r\nvoid IRAM_ATTR handleInterruptOpen() {\r\n  unsigned long currentTime = millis();\r\n  if (command == 1) {     //上升命令\r\n    if (extiTime == 0) {  //上升中断 防抖 麻痹时间计数开始\r\n      extiTime = currentTime;\r\n    } else {\r\n      // 消抖处理\r\n      if (currentTime - extiTime > 1500) {\r\n        if (digitalRead(doorOpenEXTI) == HIGH) {\r\n          digitalWrite(doorOpen, LOW);\r\n          if (command == 1) {              //此时执行中的状态  0关门  1开门  2停止 5中断正常触发模式  9什么也不代表\r\n            digitalWrite(doorPower, LOW);  //断开电源接通\r\n          }\r\n          //开门中断\r\n          extiOpen = true;\r\n          //中断服务程序（ISR）必须简短，避免调用耗时函数（如串口打印、网络通信），否则可能引发看门狗超时或系统重启\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\n\r\nvoid IRAM_ATTR handleInterruptClose() {\r\n  unsigned long currentTime = millis();\r\n  if (command == 0) {\r\n    if (extiTime == 0) {\r\n      extiTime = currentTime;\r\n    } else {\r\n      // 消抖处理\r\n      if (currentTime - extiTime > 1500) {\r\n        if (digitalRead(doorCloseEXTI) == HIGH) {\r\n          digitalWrite(doorClose, LOW);\r\n          if (command == 0) {              //0关门 状态\r\n            digitalWrite(doorPower, LOW);  //断开电源接通\r\n          }\r\n          //关门中断\r\n          extiClose = true;\r\n          //中断服务程序（ISR）必须简短，避免调用耗时函数（如串口打印、网络通信），否则可能引发看门狗超时或系统重启\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\nvoid mqttCallback(char* topic, byte* payload, unsigned int length) {\r\n  String msg;\r\n  for (int i = 0; i < length; i++) {\r\n    msg += (char)payload[i];\r\n  }\r\n  if (length > 0) {\r\n    if (msg == \"open\") {\r\n      if (doorStroke == 10) {\r\n        runIng = false;\r\n        command = 2;\r\n        const char* tmp = \"无效,上升达到限制doorStroke == 10\";\r\n        client.publish(pubshTopic, tmp);\r\n      }\r\n      if (digitalRead(doorOpenEXTI) == HIGH) {\r\n        runIng = false;\r\n        command = 2;\r\n        const char* tmp = \"无效,上升达到限制\";\r\n        client.publish(pubshTopic, tmp);\r\n        return;\r\n      }\r\n\r\n      digitalWrite(doorPower, HIGH);  //主电源接通\r\n      delay(200);\r\n      //开 上升\r\n      const char* tmp = \"正在开门 ...\";\r\n      client.publish(pubshTopic, tmp);\r\n      digitalWrite(doorClose, LOW);\r\n      delay(50);\r\n      digitalWrite(doorOpen, HIGH);\r\n      runIng = true;\r\n      command = 1;\r\n\r\n      return;\r\n    }\r\n    if (msg == \"stop\") {\r\n      closeAll();\r\n      runIng = false;\r\n      command = 2;\r\n      String tempstr;\r\n      String rez;\r\n      //查询是否下降 限制,及时把状态改好\r\n      switch (doorStroke) {\r\n        case 10:\r\n          if (runIng) {  //如果在电机运行了按停止.说明已经在中间\r\n            doorStroke = 5;\r\n            client.publish(pubshTopic, \"悬停播报模式\");\r\n          } else {\r\n            tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n            rez = \"开门达到限制 \" + tempstr;\r\n            client.publish(pubshTopic, rez.c_str());\r\n          }\r\n          break;\r\n        case 0:\r\n          if (runIng) {\r\n            doorStroke = 5;\r\n            const char* tmp = \"悬停播报模式\";\r\n            client.publish(pubshTopic, tmp);\r\n          } else {\r\n            tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n            rez = \"关门达到限制 \" + tempstr;\r\n            client.publish(pubshTopic, rez.c_str());\r\n          }\r\n\r\n          break;\r\n        case 5:\r\n          rez = \"悬停播报模式\";\r\n          client.publish(pubshTopic, rez.c_str());\r\n          break;\r\n        default:\r\n          if (runIng) {\r\n            doorStroke = 5;\r\n            rez = \"悬停播报模式0\";\r\n            client.publish(pubshTopic, rez.c_str());\r\n          } else {\r\n            if (digitalRead(doorOpenEXTI) == LOW && digitalRead(doorCloseEXTI) == LOW) {\r\n              doorStroke = 5;\r\n              rez = \"悬停播报模式1\";\r\n              client.publish(pubshTopic, rez.c_str());\r\n            } else {\r\n              if (digitalRead(doorOpenEXTI) == HIGH) {\r\n                doorStroke = 10;\r\n                tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n                rez = \"开门达到限制1 \" + tempstr;\r\n                client.publish(pubshTopic, rez.c_str());\r\n              }\r\n              if (digitalRead(doorCloseEXTI) == HIGH) {\r\n                doorStroke = 0;\r\n                tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n                rez = \"关门达到限制1 \" + tempstr;\r\n                client.publish(pubshTopic, rez.c_str());\r\n              }\r\n            }\r\n          }\r\n      }\r\n      return;\r\n    }\r\n    if (msg == \"close\") {\r\n      //限位开关导通时为高电平达到限位\r\n      if (doorStroke == 0) {\r\n        runIng = false;\r\n        command = 2;\r\n        const char* tmp = \"无效,关门达到限制doorStroke==0\";\r\n        client.publish(pubshTopic, tmp);\r\n        return;\r\n      }\r\n      if (digitalRead(doorCloseEXTI) == HIGH) {\r\n        runIng = false;\r\n        command = 2;\r\n        const char* tmp = \"无效,关门达到限制\";\r\n        client.publish(pubshTopic, tmp);\r\n        return;\r\n      }\r\n      //主电源接通\r\n      digitalWrite(doorPower, HIGH);\r\n      delay(200);\r\n      //关 下降\r\n      const char* tmp = \"正在关门 ...\";\r\n      client.publish(pubshTopic, tmp);\r\n      digitalWrite(doorOpen, LOW);\r\n      digitalWrite(doorClose, HIGH);\r\n      runIng = true;\r\n      command = 0;\r\n      return;\r\n    }\r\n\r\n    if (msg == \"temperatureHumidity\") {\r\n      float temperature;\r\n      float humidity;\r\n      sensors_event_t event;\r\n      dht.temperature().getEvent(&event);\r\n      if (isnan(event.temperature)) {\r\n        Serial.println(F(\"Error reading temperature!\"));\r\n      } else {\r\n        temperature = event.temperature;\r\n      }\r\n      delay(500);\r\n      // Get humidity event and print its value.\r\n      dht.humidity().getEvent(&event);\r\n      if (isnan(event.relative_humidity)) {\r\n        Serial.println(F(\"Error reading humidity!\"));\r\n      } else {\r\n        humidity = event.relative_humidity;\r\n      }\r\n      String th = String(temperature) + \",\" + String(int(humidity));\r\n      client.publish(pubshTopic, th.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"billboard1:on\") {\r\n      guangGaoPaiBool = true;\r\n      digitalWrite(billboard1, HIGH);\r\n      String strtem = \"系统任务 广告牌1灯已开\";\r\n      client.publish(pubshTopic, strtem.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"billboard1:off\") {\r\n      guangGaoPaiBool = false;\r\n      digitalWrite(billboard1, LOW);\r\n      String strtem = \"系统任务 广告牌1灯已关\";\r\n      client.publish(pubshTopic, strtem.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"sleep\") {  //休眠3个小时\r\n      espSleep();\r\n      return;\r\n    }\r\n\r\n    if (msg == \"gpio17:on\") {  //播报开\r\n      digitalWrite(gpio17, HIGH);\r\n      String strtem = \"goip17已开\";\r\n      client.publish(pubshTopic, strtem.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"gpio17:off\") {  //播报关 按停止键也是会关的\r\n      digitalWrite(gpio17, LOW);\r\n      String strtem = \"gpio17已关\";\r\n      client.publish(pubshTopic, strtem.c_str());\r\n      return;\r\n    }\r\n\r\n    if (msg == \"reboot\") {\r\n      ESP.restart();\r\n      return;\r\n    }\r\n    if (msg == \"version\") {\r\n      client.publish(pubshTopic, version.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"updateBin\") {\r\n      // 执行 OTA 更新前的准备工作\r\n      noInterrupts();                                         // 关闭全局中断\r\n      detachInterrupt(digitalPinToInterrupt(doorOpenEXTI));   // 禁用特定中断源（如果需要）\r\n      detachInterrupt(digitalPinToInterrupt(doorCloseEXTI));  // 禁用特定中断源（如果需要）\r\n      delay(200);\r\n      httpUpdate.onStart(update_started);\r\n      httpUpdate.onEnd(update_finished);\r\n      httpUpdate.onProgress(update_progress);\r\n      httpUpdate.onError(update_error);\r\n      t_httpUpdate_return ret = httpUpdate.update(wificlient, upBinUrl);\r\n\r\n      interrupts();  // 恢复全局中断\r\n      espReboot();\r\n    }\r\n    if (msg == \"billboard2:on\") {  //13脚高电平 广告牌2开启\r\n      digitalWrite(billboard2, HIGH);\r\n      const char* strtem = \"系统任务 广告牌2已开\";\r\n      client.publish(pubshTopic, strtem);\r\n      return;\r\n    }\r\n    if (msg == \"billboard2:off\") {  //13脚低电平 广告牌2关闭\r\n      digitalWrite(billboard2, LOW);\r\n      const char* tmp = \"系统任务 广告牌2已关\";\r\n      client.publish(pubshTopic, tmp);\r\n      return;\r\n    }\r\n    if (msg == \"light:on\") {\r\n      digitalWrite(light, HIGH);\r\n      const char* strtem = \"灯 已开\";\r\n      client.publish(pubshTopic, strtem);\r\n      return;\r\n    }\r\n    if (msg == \"light:off\") {\r\n      digitalWrite(light, LOW);\r\n      const char* strtem = \"灯 已关\";\r\n      client.publish(pubshTopic, strtem);\r\n      return;\r\n    }\r\n    if (!runIng) {\r\n      Serial.write((const uint8_t*)payload, length);\r\n    }\r\n    // client.publish(pub,str.c_str());\r\n  }\r\n}\r\n\r\nvoid reconnect() {\r\n  while (!client.connected()) {\r\n    String clientId = \"ESP32Client-\";\r\n    clientId += String(random(0xffff), HEX);\r\n    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {  // 无认证时留空\r\n      //Serial.println(\"MQTT 连接成功\");\r\n      client.subscribe(subTopic);\r\n    } else {\r\n      Serial.print(\"连接失败, rc=\");\r\n      Serial.print(client.state());\r\n      delay(5000);\r\n    }\r\n  }\r\n}\r\n//关闭上升,下降,变压器主电源\r\nvoid closeAll() {\r\n  digitalWrite(doorOpen, LOW);\r\n  digitalWrite(doorClose, LOW);\r\n  delay(200);\r\n  digitalWrite(doorPower, LOW);  //断开电源接通\r\n}\r\nvoid espReboot() {\r\n  ESP.restart();\r\n}\r\nvoid espSleep() {\r\n  closeAll();\r\n  delay(200);\r\n  const char* tmp = \"door1进入休眠状态,3小时后醒...\";\r\n  client.publish(pubshTopic, tmp);\r\n  delay(200);\r\n  WiFi.disconnect();\r\n  myTicker.detach();\r\n  delay(200);\r\n  //进入深睡眠状态，将在 3 小时后唤醒\r\n  esp_sleep_enable_timer_wakeup(10800000000);\r\n  esp_deep_sleep_start();\r\n}\r\nvoid update_started() {\r\n  // client.publish(pubshTopic, \"CALLBACK:  HTTP update process started\");\r\n}\r\n\r\nvoid update_finished() {\r\n  // client.publish(pubshTopic, \"CALLBACK:  HTTP update process finished\");\r\n}\r\n\r\nvoid update_progress(int cur, int total) {\r\n  // client.publish(pubshTopic, \"CALLBACK:  HTTP update process\");\r\n}\r\n\r\nvoid update_error(int err) {\r\n  // client.publish(pubshTopic, \"CALLBACK:  HTTP update fatal\");\r\n}\r\n\r\n//无网特殊状态下安全限位\r\nvoid html_whlie() {\r\n  //操作运行时 上升达到限位了,并且上次状态不是上升上限, 并且执行状态是上升 限位开关断开\r\n  if (digitalRead(doorOpenEXTI) == HIGH || digitalRead(doorCloseEXTI) == HIGH) {\r\n    //关闭所有开关\r\n    closeAll();\r\n    Serial.println(\"达到上限\");\r\n    myTicker.detach();\r\n    delay(200);\r\n    ESP.restart();\r\n  }\r\n}\r\n\r\n\r\nvoid SetWifi() {\r\n  ssid = webserver.arg(0);\r\n  passwd = webserver.arg(1);\r\n  String sp = ssid + \"&\" + passwd;\r\n  Serial.println(sp);\r\n  Serial.println(\"密码在前面\");\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  const char* Ssid = ssid.c_str();\r\n  const char* WifiPw = passwd.c_str();\r\n  WiFi.begin(Ssid, WifiPw);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  Serial.println(\"wifi_connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      webserver.send(200, \"text/plane\", \"Wifi密码正确,ESP准备重启\");\r\n      webserver.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n\r\n      Serial.println(\"HTML连接成功\");\r\n      delay(500);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  webserver.send(200, \"text/plane\", \"Wifi密码错误,请重新输入\");\r\n}\r\n//------- 展示页面-------\r\nvoid handlejsonArr() {\r\n  webserver.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  webserver.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\n\r\nvoid ApStart() {\r\n  WiFi.disconnect();\r\n  delay(500);\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n\r\n  //启动AP模式,并设置账号和密码\r\n  WiFi.softAP(\"192.168.168.2\", \"\");\r\n}\r\nvoid webserverStart() {\r\n  //-----------------启动webserver网络服务--------------------\r\n  webserver.begin(80);               // 启用网络服务\r\n  webserver.on(\"/\", handlejsonArr);  // / 在HTTP中,表示请求首页服务,\r\n  webserver.on(\"/SetWifi\", SetWifi);\r\n  webserver.onNotFound(handleNotFound);  // 当服务器没找到所需的服务,调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\n\r\nvoid ForPing() {\r\n  //定时时间到了,先取消定时状态\r\n  myTicker.detach();\r\n  closeAll();\r\n  delay(500);\r\n\r\n  ESP.restart();\r\n}\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  Serial.begin(115200);\r\n  WiFi.disconnect();\r\n  WiFi.mode(WIFI_STA);\r\n  delay(100);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    Serial.println(n);\r\n    String a = \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a + \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" + \"<html>\" + \"<head>\" + \"<meta charset=\\\"utf-8\\\">\" + \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" + \"<title>设置WiFi</title>\" + \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" + \"</head>\" + \"<script>\" + \"onload  = function() {\" + \"document.getElementById(\\\"up\\\").onclick = function(){\" + \"var ssida=document.getElementById(\\\"ssid\\\").value;\" + \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" + \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" + \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" + \"xhr = new XMLHttpRequest();\" + \"xhr.open(\\\"POST\\\",\\\"./SetWifi\\\",true);\" + \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" + \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" + \"xhr.send(posts);\" + \"xhr.onreadystatechange = function(){\" + \"if(this.readyState == 4 && this.status == 200){\" + \"alert(this.responseText);\" + \"}\" + \"}\" + \"}\" + \"}\" + \"</script>\" + \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" + \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" + \"<hr/>\" + \"<font color=\\\"red\\\">附近WiFi没有显示到自己的WIFI请重启或离信号源近点</font>\" + \"</body>\" + \"</html>\";\r\n    a = a + \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"扫描不到网络\";\r\n    Serial.println(\"扫描不到网络\");\r\n  }\r\n}\r\nbool FlashConnetWifi() {\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  //是否存在数据\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    Serial.print(flash_wifi);\r\n    Serial.println(\" NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flash_wifi, \"r\");\r\n  String result = dateFile.readString();\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char* Ssid = wifiname.c_str();\r\n  const char* WifiPw = wifipw.c_str();\r\n  Serial.println(Ssid);\r\n  Serial.println(WifiPw);\r\n  WiFi.begin(Ssid, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  int wifiTimeout = 0;\r\n  for (wifiTimeout; wifiTimeout < 30; wifiTimeout++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"FlashConnetWifi-> timeout\");\r\n  return false;\r\n}\r\n\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  ApStart();\r\n  delay(1000);\r\n  Serial.println(\"启动网页\");\r\n  myTicker.detach();\r\n  delay(200);\r\n  //5分后重启 防止停电后复电,路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式,所以这里只让AP 激活5分钟后就重启\r\n  myTicker.once(300, espReboot);\r\n  delay(200);\r\n  webserverStart();\r\n  while (1) {\r\n    webserver.handleClient();  // 检查网络服务请求并处理\r\n  }\r\n}\r\n','',1),
(286,6,'什么是中断,以及使用方法','打个比方,\r\n你正在看电脑看动画片,这个时候有人打电话给你,这个时候你就暂停电脑的动画片播放,接电话,(接电话这个动作接中断)\r\nSTM32 中断   使用 PB11 和 PB10 作为中断下拉\r\n如果使用 PB10 做中断，那么 不能使用 PC10 ,PA10作为中断引脚 \r\n以此类推PB11 做中断，那么 不能使用 PC11 ,PA11作为中断引脚 \r\n点击cubeIDE 坐上 System Core->NVIC\r\n看到中间下方 有个 EXTI开头的就是中断  在后面打勾\r\nPreemption Priority  为抢占中断级 \r\nSub Priority   为释放中断级     这两个顾名思义，值越小 权利越高\r\n保存 生成代码\r\n在IED 左侧 Core ->Src 文件夹下会有一个?????_it.c\r\n打开文件  找到  void EXTI  开头的方法\r\n函数里会找到 \r\nvoid HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) 这个方法里\r\n HAL_GPIO_EXTI_Callback(GPIO_Pin); 这个就是我们要使用的中断回调方法\r\n\r\n回到main.c文件 \r\n在 int main(void) 方法上 使用\r\nvoid HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {}\r\n在这个方法里进行逻辑执行\r\n特别记住不能再中断里使用延迟\r\n\r\n','',1),
(287,6,'什么是看门狗','什么是看门狗','',1),
(289,6,'PWM','PWM','',1),
(290,6,'串口轮询发送与接收','Conectivity->USART1-> Mode (选 Asynchronous))\r\n使用 printf(\"串口打印 %s\\r\\n\",?);\r\nint __io_putchar(int ch) （这个方法在 Core->Src->syscalls.c）\r\nmain.c 创建方法\r\nint __io_putchar(int ch){\r\n HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);\r\n return ch;\r\n}\r\n\r\nHAL_UART_Receive(&huart1,revbuf,sizeof(revbuf),HAL_MAX_DELAY);','',1),
(291,6,'串口中断收发','Conectivity->USART1-> Mode (选 Asynchronous))\r\n中间下方  点击 NVIC Settiings  ->  Enabled (打勾)\r\n保存生成代码\r\n\r\nHAL_UART_Receive_IT(&huart1, revbuf, sizeof(revbuf)); 必须 放在main方法 MX_USART1_UART_Init(); 后\r\n\r\n//下面这个方法必须声明在main 方法上面\r\nvoid HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){\r\n	if (huart->Instance == USART1) {\r\n		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_14);\r\n		HAL_UART_Transmit_IT(&huart1, revbuf, sizeof(revbuf));\r\n		HAL_UART_Receive_IT(&huart1, revbuf, sizeof(revbuf));\r\n	}\r\n}','',1),
(292,6,'定时器分3种功能','定时器    就是一个计数器 分为向上，或向下计数\r\n基本定时器 （没有输入输出，只有定时中断，只支持向上计数）\r\n通用定时器 （具备基本定时器所有功能外， 还有多路独立通道，可用于输入铺货、输出比较）\r\n高级定时器  （具备通用定时器所有功能外，还有死区控制的互补信号输出，刹车输入（可用于电机控制，数字电源设计）\r\nF103 有 TIM1-TIM8\r\n在 STM32F103C8T6 中，TIM1 是高级定时器，TIM2  TIM3、TIM4 是通用定时器、\r\n基本定时器（TIM6和TIM7）\r\n通用定时器（TIME2到TIME5）\r\n高级定时器 （TIME1和TIME8）','',1),
(293,6,'基本定时器','72M（F）c8t6型号是8M 精准时钟->预分频器PSC(主要作用是使时钟变慢，是16为的从0-65535) \r\n->出来的时钟才是定时器频率（比如频率1hz 就是1秒，如果是1000hz 就是1毫秒） \r\n自动重装只ARR（就是计数器总计数值）\r\n-> 计数器CNT(溢出)->时间到\r\n定时时间（单位是秒）  T=(ARR+1)*(psc+1)/F(72m时钟源)\r\n\r\nTimers->TIME4->勾选Intemal clock\r\n中下方  Plesscaler(PSC-16bits value)  输入 7200-1   最大时钟是72M\r\nCounter Period 默认最大撒只是65535    这个时候要根据上面公式计算你的定时时间\r\n也就是说最大定时是6.5秒左右\r\n若你想实现60 分钟（3600 秒）的定时，仅凭单个 16 位定时器（如 STM32F103 的 TIM1-TIM4）无法直接完\r\n利用定时器的周期性中断，在中断服务函数中累计计数次数，达到目标时间后触发事件\r\n	 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){    放到main方法外面\r\n\r\n	 }\r\n\r\n\r\n               while (1) {｝ 上面 HAL_TIM_Base_Start_IT(&htim4); // 启动TIM4定时器并使能中断','',1),
(294,6,'uint8_t的意思','取值范围\r\n由于是8 位无符号数，其取值范围为：0 ~ 255\r\nu：表示无符号（Unsigned，即不存储负数，仅表示非负整数）。\r\nint：表示整数类型。\r\n8：表示该类型的位数为 8 位（Bit）。\r\n_t：表示这是通过typedef定义的类型别名。\r\n关键特性\r\n超出范围会导致溢出（Overflow），结果通常是取模运算后的余数（例如：255 + 1会溢出为0）。\r\n内存占用\r\n理论上占用1 字节（Byte，8 位）内存，但需注意：\r\n部分平台可能存在字节对齐等优化，但标准规定其宽度必须恰好为 8 位。\r\n与其他类型的区别\r\n对比int：\r\nint是编译器依赖的整数类型（通常为 16 位或 32 位），而uint8_t固定为 8 位。\r\nint是有符号类型（取值范围如 - 32768 ~ 32767），uint8_t是无符号类型。\r\n对比unsigned char：\r\n在多数平台上，uint8_t等同于unsigned char，但unsigned char属于字符类型，而uint8_t明确为整数类型，用途更清晰（例如用于表示字节数据）。\r\n典型应用场景\r\n存储字节数据\r\n例如：网络传输中的单个字节、文件读写中的字节流、硬件寄存器的 8 位数据等。\r\n表示无符号小整数\r\n如：枚举值、计数器（范围≤255）、颜色分量（RGB 值每个分量为 0~255）等。\r\n内存优化\r\n当需要严格控制变量占用内存（如嵌入式系统）时，使用固定宽度类型避免空间浪费。','',1),
(295,6,'通用定时器PWM','STM32F103C8T6\r\nTimers->TIM1\r\nClock Source -> Intemal Clock   \r\nChannel1  -> PWM Generation CH1  输出脚是 PA8\r\n往中下方看\r\nPrescaler(PSC-16 bits value) -> 8-1    //8M的\r\nCounter Period (AutoReload R....)   -> 500-1\r\nPWM Generation Channel1 下面的 Mode -> PWM mode 2\r\nCH Polarity ->High \r\n保存生成代码\r\nint main(void) {\r\n	uint8_t dir = 1; //方向\r\n	uint16_t val = 250;  //ccr 的值\r\n//在 MX_TIM1_Init(); 下面\r\nHAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);\r\n	while (1) {\r\n		if (dir == 1) {\r\n			val++;\r\n		} else {\r\n			val--;\r\n		}\r\n		if (val >= 300) {\r\n			dir = 0;\r\n		}\r\n		if (val == 0) {\r\n			dir = 1;\r\n		}\r\n\r\n		__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,val);\r\n		HAL_Delay(10);\r\n		/* USER CODE END WHILE */\r\n\r\n		/* USER CODE BEGIN 3 */\r\n	}\r\n\r\n\r\n','',1),
(296,4,'esp32WIFI下的MQTT','#include <WiFi.h>\r\n#include <PubSubClient.h>\r\n\r\nWiFiClient wificlient;\r\nString wifiSsid = \"webserver\";\r\nString wifiPasswd = \"www.nobiggie.cn\";\r\n\r\nconst char* mqtt_server = \"wulian.nobiggie.cn\";\r\nconst char* mqtt_username=\"aaaaaaa\";\r\nconst char* mqtt_password=\"abcdefg\";\r\nconst char* sub=\"wifi/card01\";\r\nconst char* pub=\"wifi/app01\";\r\nPubSubClient client(wificlient);\r\n\r\nvoid setup(void) {\r\n  Serial.begin(115200);\r\n  WiFi.begin(wifiSsid .c_str(), wifiPasswd .c_str());\r\n  WiFi.mode(WIFI_STA);\r\n\r\n  int ii = 0;\r\n  while (ii < 20 && WiFi.status() != WL_CONNECTED) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    ii++;\r\n  }\r\n  Serial.println(\"wifi ok\");\r\n  client.setServer(mqtt_server, 1883);\r\n  client.setCallback(mqttCallback);\r\n}\r\n\r\nvoid loop(void) {\r\n  if (!client.connected()) {\r\n    reconnect();\r\n  }\r\n  client.loop();\r\n\r\n  if (Serial.available()) {\r\n    String receivedString = Serial.readStringUntil(\'\\n\');\r\n    client.publish(\"wifi/app01\", receivedString.c_str());\r\n  }\r\n}\r\n\r\nvoid mqttCallback(char* topic, byte* payload, unsigned int length) {\r\n  String str;\r\n  for (int i = 0; i < length; i++) {\r\n    str += (char)payload[i];\r\n  }\r\n  str=\"收到消息:\"+str;\r\n  client.publish(pub,str.c_str());\r\n}\r\n\r\nvoid reconnect() {\r\n  while (!client.connected()) {\r\n    String clientId = \"ESP32Client-\";\r\n    clientId += String(random(0xffff), HEX);\r\n\r\n    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {  // 无认证时留空\r\n      Serial.println(\"MQTT 连接成功\");\r\n      client.subscribe(sub);\r\n    } else {\r\n      Serial.print(\"连接失败, rc=\");\r\n      Serial.print(client.state());\r\n      delay(5000);\r\n    }\r\n  }\r\n}','',1),
(298,4,'遥控小车','#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <PubSubClient.h>\r\n#include <ESP32Servo.h>\r\n\r\n#include <WebServer.h>\r\n#include <HTTPClient.h>\r\n#include <FS.h>\r\n#include \"SPIFFS.h\"\r\n#include \"ESPmDNS.h\"\r\n#include <Ticker.h>\r\n\r\nServo myServo;\r\n\r\nconst int minPulse = 500;   // 最小脉宽(微秒)\r\nconst int maxPulse = 2500;  // 最大脉宽(微秒)\r\nint servoPin = 17;          //H4  默认使用，可根据实际连接修改\r\nconst int centerPos = 90;   // 舵机中心位置(对应物理90度)\r\n\r\nint baudRate = 115200;\r\n\r\nTicker myTicker;\r\nString flashWifi = \"/wifi.txt\";  //wifi密码存放文件\r\nWebServer webServer;\r\nString ssid;\r\nString passwd;\r\nString html;\r\n\r\nWiFiClient wificlient;\r\n\r\nconst char* mqtt_server = \"wulian.nobiggie.cn\";\r\nconst char* mqtt_username = \"ccccccc\";\r\nconst char* mqtt_password = \"abcdefg\";\r\nconst char* sub = \"wifi/car003/control\";\r\nconst char* pub = \"wifi/car003/status\";\r\nPubSubClient client(wificlient);\r\n\r\nint h8 = 21;  //车灯\r\n\r\n\r\nint pwmPin = 4;                   //PWM控制\r\nconst uint32_t pwmFreq = 1000;    // PWM频率1kHz（1-10kHz适合电机控制）\r\nconst uint8_t pwmResolution = 8;  // 8位分辨率（0-255）\r\n\r\nint PwmNow = 125;    //初始值 49%\r\nint fadeAmount = 5;  //累加数\r\n\r\nvoid setup(void) {\r\n  Serial.begin(baudRate);\r\n  pinMode(h8, OUTPUT);\r\n\r\n  pinMode(pwmPin, OUTPUT);\r\n\r\n  // 手动选择通道并绑定引脚\r\n  if (ledcAttach(pwmPin, pwmFreq, pwmResolution)) {\r\n    Serial.printf(\"PWM配置成功：频率=%dHz，分辨率=%dbits\\n\", pwmFreq, pwmResolution);\r\n  } else {\r\n    Serial.println(\"PWM配置失败，请检查参数或通道占用情况\");\r\n  }\r\n  ledcWrite(pwmPin, PwmNow);\r\n\r\n  if (FlashConnetWifi() == false) {\r\n    Serial.println(\"启动AP\");\r\n    HtmlSetWifi();\r\n  }\r\n  digitalWrite(h8, HIGH);\r\n  // 为舵机分配PWM定时器\r\n  ESP32PWM::allocateTimer(0);\r\n  myServo.setPeriodHertz(50);  // 标准舵机频率50Hz\r\n  delay(100);\r\n  // 初始化舵机连接\r\n  myServo.attach(servoPin, minPulse, maxPulse);\r\n\r\n  // 移动到中心位置\r\n  Serial.println(\"移动到中心位置\");\r\n  myServo.write(centerPos);\r\n  delay(500);\r\n  Serial.println(\"舵机已就绪\");\r\n\r\n  client.setServer(mqtt_server, 1883);\r\n  client.setCallback(mqttCallback);\r\n}\r\n\r\nvoid loop(void) {\r\n  if (!client.connected()) {\r\n    reconnect();\r\n  }\r\n  client.loop();\r\n}\r\n\r\nvoid mqttCallback(char* topic, byte* payload, unsigned int length) {\r\n  String temp;\r\n  for (int i = 0; i < length; i++) {\r\n    temp += (char)payload[i];\r\n  }\r\n  Serial.println(temp);\r\n  if (temp.indexOf(\"forward\") != -1) {  //前进 66-100\r\n    int ln = temp.length();\r\n    int plusIndex = temp.indexOf(\"+\");\r\n    int angle = temp.substring(plusIndex + 1).toInt();\r\n    ledcWrite(pwmPin, angle);\r\n    return;\r\n  }\r\n  if (temp.indexOf(\"backward\") != -1) {  //后退 33-66\r\n    int ln = temp.length();\r\n    int plusIndex = temp.indexOf(\"+\");\r\n    int angle = temp.substring(plusIndex + 1).toInt();\r\n    ledcWrite(pwmPin, angle);\r\n    return;\r\n  }\r\n  if (temp.indexOf(\"left\") != -1) {  //left+转弯角度 0-45 即90度-48度\r\n    int ln = temp.length();\r\n    int plusIndex = temp.indexOf(\"+\");\r\n    int angle = temp.substring(plusIndex + 1).toInt();\r\n    angle = angle > 45 ? 45 : angle;\r\n    angle = 90 + angle;\r\n    rightGo(angle);\r\n    return;\r\n  }\r\n  if (temp.indexOf(\"right\") != -1) {  //right+转弯角度  0-45 即90度-135度\r\n    int ln = temp.length();\r\n    int plusIndex = temp.indexOf(\"+\");\r\n    int angle = temp.substring(plusIndex + 1).toInt();\r\n    angle = angle > 45 ? 45 : angle;\r\n    angle = 90 - angle;\r\n    leftGo(angle);\r\n    return;\r\n  }\r\n  if (temp == \"md\") {\r\n    aligning();\r\n  }\r\n  if (temp = \"stop\") {\r\n    aligning();\r\n  }\r\n\r\n\r\n  //temp = \"收到消息:\" + temp;\r\n  //client.publish(pub, temp.c_str());\r\n}\r\n\r\nvoid reconnect() {\r\n  while (!client.connected()) {\r\n    String clientId = \"ESP32Client-\";\r\n    clientId += String(random(0xffff), HEX);\r\n\r\n    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {  // 无认证时留空\r\n      Serial.println(\"MQTT 连接成功\");\r\n      client.subscribe(sub);\r\n    } else {\r\n      Serial.print(\"连接失败, rc=\");\r\n      Serial.print(client.state());\r\n      delay(5000);\r\n    }\r\n  }\r\n}\r\n\r\nvoid leftGo(int angle) {\r\n  // 验证角度范围\r\n  if (angle < 45) angle = 45;\r\n  if (angle > 90) angle = 90;\r\n  myServo.write(angle);\r\n}\r\nvoid aligning() {\r\n  myServo.write(centerPos);  // 确保到达目标位置\r\n}\r\nvoid rightGo(int angle) {\r\n  if (angle < 90) angle = 90;\r\n  if (angle > 135) angle = 135;\r\n  myServo.write(angle);\r\n}\r\n\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  apStart();\r\n  delay(1000);\r\n  Serial.println(\"start webserver\");\r\n  //5分后重启 防止停电后复电，路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式，所以这里只让AP激活5分钟后就重启\r\n  myTicker.once(300, espReboot);\r\n  delay(200);\r\n  webserverStart();\r\n  while (1) {\r\n    webServer.handleClient();  //检查网络服务请求并处理\r\n  }\r\n}\r\nvoid espReboot() {\r\n  ESP.restart();\r\n}\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  WiFi.disconnect();\r\n  Serial.begin(baudRate);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(100);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    String a = \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a + \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" + \"<html>\" + \"<head>\" + \"<meta charset=\\\"utf-8\\\">\" + \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" + \"<title>设置WiFi</title>\" + \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" + \"</head>\" + \"<script>\" + \"onload  = function() {\" + \"document.getElementById(\\\"up\\\").onclick = function(){\" + \"var ssida=document.getElementById(\\\"ssid\\\").value;\" + \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" + \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" + \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" + \"xhr = new XMLHttpRequest();\" + \"xhr.open(\\\"POST\\\",\\\"./setWifi\\\",true);\" + \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" + \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" + \"xhr.send(posts);\" + \"xhr.onreadystatechange = function(){\" + \"if(this.readyState == 4 && this.status == 200){\" + \"alert(this.responseText);\" + \"}\" + \"}\" + \"}\" + \"}\" + \"</script>\" + \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" + \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" + \"<hr/>\" + \"<div>如果附近WiFi没有显示到自己的WIFI<div>\" + \"<div>请重启或离信号近点</div>\" + \"<div>连接成功AP热点退出转WIFI_STA</div>\" + \"</body>\" + \"</html>\";\r\n    a = a + \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"扫描不到网络\";\r\n  }\r\n}\r\nvoid setWifi() {\r\n  ssid = webServer.arg(0);\r\n  passwd = webServer.arg(1);\r\n  const char* Ssid = ssid.c_str();\r\n  const char* Passwd = passwd.c_str();\r\n  String sp = ssid + \"&\" + passwd;\r\n  Serial.println(sp);\r\n  Serial.begin(baudRate);\r\n  delay(500);\r\n  WiFi.begin(Ssid, Passwd);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  Serial.println(\"wifi_connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      webServer.send(200, \"text/plane\", \"Wifi密码正确,ESP准备重启\");\r\n      webServer.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flashWifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n      Serial.println(\"HTML设置网络连接成功\");\r\n      delay(500);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  webServer.send(200, \"text/plane\", \"Wifi密码错误,请重新输入\");\r\n}\r\n//------- 展示页面-------\r\nvoid handleRoot() {\r\n  webServer.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  webServer.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\nvoid apStart() {\r\n  Serial.begin(baudRate);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n  //启动AP模式，并设置账号和密码\r\n  boolean result = WiFi.softAP(\"192.168.168.2\", \"192.168.168.2\");\r\n  if (result) {\r\n    Serial.println(String(\"Soft-AP IP address = \") + WiFi.softAPIP());\r\n  }\r\n}\r\nvoid webserverStart() {\r\n  webServer.begin(80);            // 启用网络服务\r\n  webServer.on(\"/\", handleRoot);  // / 在HTTP中，表示请求首页服务，\r\n  webServer.on(\"/setWifi\", setWifi);\r\n  webServer.onNotFound(handleNotFound);  // 当服务器没找到所需的服务，调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\nbool FlashConnetWifi() {\r\n  Serial.begin(baudRate);\r\n  delay(200);\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flashWifi) == false) {\r\n    Serial.println(\"NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flashWifi, \"r\");\r\n  String result;\r\n  for (int i = 0; i < dateFile.size(); i++) {\r\n    //Serial.print((char)dateFile.read());\r\n    result += (char)dateFile.read();\r\n  }\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char* WifiName = wifiname.c_str();\r\n  const char* WifiPw = wifipw.c_str();\r\n  Serial.println(WifiName);\r\n  Serial.println(WifiPw);\r\n  WiFi.begin(WifiName, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnet...\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"flash connet success\");\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"flash read error\");\r\n  return false;\r\n}','',1),
(299,4,'MQTT遥控大门与智能播报(中断)','#include <Arduino.h>\r\n#include <WiFi.h>\r\n#include <PubSubClient.h>\r\n#include <HTTPUpdate.h>\r\n#include <OneWire.h>\r\n#include <DallasTemperature.h>\r\n#include <Adafruit_Sensor.h>\r\n#include <DHT.h>\r\n#include <DHT_U.h>\r\n#include <Ticker.h>\r\n#include <esp_sleep.h>\r\n#include <FS.h>\r\n#include <SPIFFS.h>\r\n#include <WebServer.h>\r\n#define doorOpen 22       //升\r\n#define doorClose 21      //降\r\n#define doorOpenEXTI 26   //升 中断\r\n#define doorCloseEXTI 25  //降 中断\r\n#define dhtPin 0          //温湿度传感器\r\n#define DHTTYPE DHT11     //传感器类型\r\nDHT_Unified dht(dhtPin, DHTTYPE);\r\n\r\n#define billboard1 4           //广告牌开关\r\n#define billboard2 13          //寄快递广告牌\r\nbool guangGaoPaiBool = false;  //guangGaoPaiBool为false代表没有开灯箱 true为已开启灯箱\r\n\r\n#define light 2       //灯\r\n#define broadcast 17  //播报电源开关\r\n#define doorPower 15  //电源总开关\r\nString version = \"1.24.7\";\r\nString ssid = \"\";                 //wifi账号\r\nString passwd = \"\";               //wifi密码\r\nString html;                      //存html\r\nString flash_wifi = \"/wifi.txt\";  //被读取的文件位置和名称\r\nWebServer webserver;\r\n\r\nvolatile int doorStroke = 5;   //记录门静止状态 处于什么位置 10为上限  0为下限 5为可以上升可降\r\nvolatile bool runIng = false;  //true 为电机正在运行\r\nvolatile int command = 2;      //此时执行的指令  0关门  1开门  2停止\r\n// 函数声明\r\nvoid IRAM_ATTR handleInterruptOpen();\r\nvoid IRAM_ATTR handleInterruptClose();\r\n\r\nvolatile bool extiOpen = false;   //true 代表上升中断触发了\r\nvolatile bool extiClose = false;  //true 代表下降中断触发了\r\nvolatile unsigned long extiTime = 0;\r\n\r\n\r\nWiFiClient wificlient;\r\n\r\nvolatile bool sayBool = false;  //ture为开启扫描状态\r\nTicker myTicker;\r\n\r\nconst char* mqtt_server = \"192.168.0.254\";\r\nconst char* mqtt_username = \"door1\";\r\nconst char* mqtt_password = \"abcdefg\";\r\nconst char* subTopic = \"wifi/door1/control\";\r\nconst char* pubshTopic = \"wifi/door1/data\";\r\nPubSubClient client(wificlient);\r\n\r\nString upBinUrl = \"http://\" + String(mqtt_server) + \"/tool/ota/GolangCpp/mydoor1.bin\";\r\nvoid setup(void) {\r\n  pinMode(doorOpen, OUTPUT);    //门上升\r\n  pinMode(doorClose, OUTPUT);   //门下降\r\n  pinMode(billboard1, OUTPUT);  //广播牌\r\n  pinMode(broadcast, OUTPUT);   //语音播报\r\n  pinMode(light, OUTPUT);\r\n  pinMode(doorPower, OUTPUT);  //总电源\r\n  pinMode(billboard2, OUTPUT);\r\n\r\n  digitalWrite(doorOpen, LOW);\r\n  digitalWrite(doorClose, LOW);\r\n  digitalWrite(billboard1, LOW);\r\n  digitalWrite(broadcast, HIGH);\r\n  digitalWrite(light, LOW);\r\n  digitalWrite(doorPower, LOW);\r\n  digitalWrite(billboard2, LOW);\r\n\r\n  pinMode(doorOpenEXTI, INPUT_PULLUP);  //上拉电阻模式,默认高电平\r\n  pinMode(doorCloseEXTI, INPUT_PULLUP);\r\n\r\n  // 附加中断服务函数\r\n  attachInterrupt(digitalPinToInterrupt(doorOpenEXTI), handleInterruptOpen, CHANGE);\r\n  attachInterrupt(digitalPinToInterrupt(doorCloseEXTI), handleInterruptClose, CHANGE);\r\n\r\n\r\n  Serial.begin(115200);\r\n  //pinMode(flash_rst, INPUT_PULLUP);\r\n  delay(200);\r\n  dht.begin();\r\n  sensor_t sensor;\r\n  dht.temperature().getSensor(&sensor);\r\n  dht.humidity().getSensor(&sensor);\r\n  delay(500);\r\n\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    SPIFFS.begin();\r\n    File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n    dataFile.println(\"webserver&www.nobiggie.cn\");\r\n    dataFile.close();\r\n  }\r\n\r\n  if (FlashConnetWifi() == false) {  //自动flash联网不成功 就启用 html配置wifi账号密码\r\n    HtmlSetWifi();\r\n  }\r\n  Serial.println(\"wifi ok\");\r\n  client.setServer(mqtt_server, 1883);\r\n  client.setCallback(mqttCallback);\r\n  delay(200);\r\n  if (digitalRead(doorOpenEXTI) == LOW && digitalRead(doorCloseEXTI) == LOW) {\r\n    doorStroke = 5;\r\n  } else {\r\n    if (digitalRead(doorOpenEXTI) == HIGH) {\r\n      doorStroke = 10;\r\n    }\r\n    if (digitalRead(doorCloseEXTI) == HIGH) {\r\n      doorStroke = 0;\r\n    }\r\n  }\r\n}\r\n\r\nvoid loop(void) {\r\n  if (!client.connected()) {\r\n    digitalWrite(doorOpen, LOW);\r\n    digitalWrite(doorClose, LOW);\r\n\r\n    //防止开启突然没有网络,lop循环检测不到状态 这里再进行检测\r\n    if (digitalRead(doorOpenEXTI) == HIGH && doorStroke != 10) {\r\n      doorStroke = 10;\r\n      closeAll();\r\n      //Serial.println(\"Disconnected  上限关闭\");\r\n    }\r\n    //查询是否下降 限制,及时把状态改好\r\n    if (digitalRead(doorCloseEXTI) == HIGH && doorStroke != 0) {\r\n      doorStroke = 0;\r\n      closeAll();\r\n      //Serial.println(\"Disconnected  下限关闭\");\r\n    }\r\n    reconnect();\r\n  }\r\n  client.loop();\r\n  if (extiOpen) {      //上升中断触发\r\n    extiOpen = false;  //复位\r\n    if (command == 1) {\r\n      doorStroke = 10;               //位置变为上限\r\n      command = 2;                   //命令变为停止\r\n      extiTime = 0;                  //防抖复位\r\n      digitalWrite(doorPower, LOW);  //断开电源接通\r\n      const char* tmp = \"上升中断触发了\";\r\n      client.publish(pubshTopic, tmp);\r\n    }\r\n    return;\r\n  }\r\n  if (extiClose) {      //下降中断触发\r\n    extiClose = false;  //复位\r\n    if (command == 0) {\r\n      doorStroke = 0;                 //位置变为下限\r\n      command = 2;                    //命令变为停止\r\n      extiTime = 0;                   //防抖复位\r\n      digitalWrite(doorPower, LOW);   //断开电源接通\r\n      digitalWrite(billboard1, LOW);  //关门就把广告灯箱关了\r\n      const char* tmp = \"下降中断触发了\";\r\n      client.publish(pubshTopic, tmp);\r\n    }\r\n    return;\r\n  }\r\n}\r\nvoid IRAM_ATTR handleInterruptOpen() {\r\n  unsigned long currentTime = millis();\r\n  if (command == 1) {     //上升命令\r\n    if (extiTime == 0) {  //上升中断 防抖 麻痹时间计数开始\r\n      extiTime = currentTime;\r\n    } else {\r\n      // 消抖处理\r\n      if (currentTime - extiTime > 1500) {\r\n        if (digitalRead(doorOpenEXTI) == HIGH) {\r\n          digitalWrite(doorOpen, LOW);\r\n          if (command == 1) {              //此时执行中的状态  0关门  1开门  2停止 5中断正常触发模式  9什么也不代表\r\n            digitalWrite(doorPower, LOW);  //断开电源接通\r\n          }\r\n          //开门中断\r\n          extiOpen = true;\r\n          //中断服务程序（ISR）必须简短，避免调用耗时函数（如串口打印、网络通信），否则可能引发看门狗超时或系统重启\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\n\r\nvoid IRAM_ATTR handleInterruptClose() {\r\n  unsigned long currentTime = millis();\r\n  if (command == 0) {\r\n    if (extiTime == 0) {\r\n      extiTime = currentTime;\r\n    } else {\r\n      // 消抖处理\r\n      if (currentTime - extiTime > 1500) {\r\n        if (digitalRead(doorCloseEXTI) == HIGH) {\r\n          digitalWrite(doorClose, LOW);\r\n          if (command == 0) {              //0关门 状态\r\n            digitalWrite(doorPower, LOW);  //断开电源接通\r\n          }\r\n          //关门中断\r\n          extiClose = true;\r\n          //中断服务程序（ISR）必须简短，避免调用耗时函数（如串口打印、网络通信），否则可能引发看门狗超时或系统重启\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\nvoid mqttCallback(char* topic, byte* payload, unsigned int length) {\r\n  String msg;\r\n  for (int i = 0; i < length; i++) {\r\n    msg += (char)payload[i];\r\n  }\r\n  if (length > 0) {\r\n    if (msg == \"open\") {\r\n      if (doorStroke == 10) {\r\n        runIng = false;\r\n        command = 2;\r\n        const char* tmp = \"无效,上升达到限制doorStroke == 10\";\r\n        client.publish(pubshTopic, tmp);\r\n      }\r\n      if (digitalRead(doorOpenEXTI) == HIGH) {\r\n        runIng = false;\r\n        command = 2;\r\n        const char* tmp = \"无效,上升达到限制\";\r\n        client.publish(pubshTopic, tmp);\r\n        return;\r\n      }\r\n\r\n      digitalWrite(doorPower, HIGH);  //主电源接通\r\n      delay(200);\r\n      //开 上升\r\n      const char* tmp = \"正在开门 ...\";\r\n      client.publish(pubshTopic, tmp);\r\n      digitalWrite(doorClose, LOW);\r\n      delay(50);\r\n      digitalWrite(doorOpen, HIGH);\r\n      runIng = true;\r\n      command = 1;\r\n\r\n      return;\r\n    }\r\n    if (msg == \"stop\") {\r\n      closeAll();\r\n      runIng = false;\r\n      command = 2;\r\n      String tempstr;\r\n      String rez;\r\n      //查询是否下降 限制,及时把状态改好\r\n      switch (doorStroke) {\r\n        case 10:\r\n          if (runIng) {  //如果在电机运行了按停止.说明已经在中间\r\n            doorStroke = 5;\r\n            client.publish(pubshTopic, \"悬停播报模式\");\r\n          } else {\r\n            tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n            rez = \"开门达到限制 \" + tempstr;\r\n            client.publish(pubshTopic, rez.c_str());\r\n          }\r\n          break;\r\n        case 0:\r\n          if (runIng) {\r\n            doorStroke = 5;\r\n            const char* tmp = \"悬停播报模式\";\r\n            client.publish(pubshTopic, tmp);\r\n          } else {\r\n            tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n            rez = \"关门达到限制 \" + tempstr;\r\n            client.publish(pubshTopic, rez.c_str());\r\n          }\r\n\r\n          break;\r\n        case 5:\r\n          rez = \"悬停播报模式\";\r\n          client.publish(pubshTopic, rez.c_str());\r\n          break;\r\n        default:\r\n          if (runIng) {\r\n            doorStroke = 5;\r\n            rez = \"悬停播报模式0\";\r\n            client.publish(pubshTopic, rez.c_str());\r\n          } else {\r\n            if (digitalRead(doorOpenEXTI) == LOW && digitalRead(doorCloseEXTI) == LOW) {\r\n              doorStroke = 5;\r\n              rez = \"悬停播报模式1\";\r\n              client.publish(pubshTopic, rez.c_str());\r\n            } else {\r\n              if (digitalRead(doorOpenEXTI) == HIGH) {\r\n                doorStroke = 10;\r\n                tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n                rez = \"开门达到限制1 \" + tempstr;\r\n                client.publish(pubshTopic, rez.c_str());\r\n              }\r\n              if (digitalRead(doorCloseEXTI) == HIGH) {\r\n                doorStroke = 0;\r\n                tempstr = guangGaoPaiBool == true ? \"灯箱亮\" : \"灯箱关\";\r\n                rez = \"关门达到限制1 \" + tempstr;\r\n                client.publish(pubshTopic, rez.c_str());\r\n              }\r\n            }\r\n          }\r\n      }\r\n      return;\r\n    }\r\n    if (msg == \"close\") {\r\n      //限位开关导通时为高电平达到限位\r\n      if (doorStroke == 0) {\r\n        runIng = false;\r\n        command = 2;\r\n        const char* tmp = \"无效,关门达到限制doorStroke==0\";\r\n        client.publish(pubshTopic, tmp);\r\n        return;\r\n      }\r\n      if (digitalRead(doorCloseEXTI) == HIGH) {\r\n        runIng = false;\r\n        command = 2;\r\n        const char* tmp = \"无效,关门达到限制\";\r\n        client.publish(pubshTopic, tmp);\r\n        return;\r\n      }\r\n      //主电源接通\r\n      digitalWrite(doorPower, HIGH);\r\n      delay(200);\r\n      //关 下降\r\n      const char* tmp = \"正在关门 ...\";\r\n      client.publish(pubshTopic, tmp);\r\n      digitalWrite(doorOpen, LOW);\r\n      digitalWrite(doorClose, HIGH);\r\n      runIng = true;\r\n      command = 0;\r\n      return;\r\n    }\r\n\r\n    if (msg == \"temperatureHumidity\") {\r\n      float temperature;\r\n      float humidity;\r\n      sensors_event_t event;\r\n      dht.temperature().getEvent(&event);\r\n      if (isnan(event.temperature)) {\r\n        Serial.println(F(\"Error reading temperature!\"));\r\n      } else {\r\n        temperature = event.temperature;\r\n      }\r\n      delay(500);\r\n      // Get humidity event and print its value.\r\n      dht.humidity().getEvent(&event);\r\n      if (isnan(event.relative_humidity)) {\r\n        Serial.println(F(\"Error reading humidity!\"));\r\n      } else {\r\n        humidity = event.relative_humidity;\r\n      }\r\n      String th = String(temperature) + \",\" + String(int(humidity));\r\n      client.publish(pubshTopic, th.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"billboard1:on\") {\r\n      guangGaoPaiBool = true;\r\n      digitalWrite(billboard1, HIGH);\r\n      String strtem = \"系统任务 广告牌1灯已开\";\r\n      client.publish(pubshTopic, strtem.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"billboard1:off\") {\r\n      guangGaoPaiBool = false;\r\n      digitalWrite(billboard1, LOW);\r\n      String strtem = \"系统任务 广告牌1灯已关\";\r\n      client.publish(pubshTopic, strtem.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"sleep\") {  //休眠3个小时\r\n      espSleep();\r\n      return;\r\n    }\r\n\r\n    if (msg == \"broadcast:on\") {  //播报开\r\n      sayBool = true;\r\n      digitalWrite(broadcast, LOW);\r\n      String strtem = \"播报已开\";\r\n      client.publish(pubshTopic, strtem.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"broadcast:off\") {  //播报关 按停止键也是会关的\r\n      sayBool = false;\r\n      digitalWrite(broadcast, HIGH);\r\n      String strtem = \"播报已关\";\r\n      client.publish(pubshTopic, strtem.c_str());\r\n      return;\r\n    }\r\n\r\n    if (msg == \"reboot\") {\r\n      ESP.restart();\r\n      return;\r\n    }\r\n    if (msg == \"version\") {\r\n      client.publish(pubshTopic, version.c_str());\r\n      return;\r\n    }\r\n    if (msg == \"updateBin\") {\r\n      // 执行 OTA 更新前的准备工作\r\n      noInterrupts();                                         // 关闭全局中断\r\n      detachInterrupt(digitalPinToInterrupt(doorOpenEXTI));   // 禁用特定中断源（如果需要）\r\n      detachInterrupt(digitalPinToInterrupt(doorCloseEXTI));  // 禁用特定中断源（如果需要）\r\n      delay(200);\r\n      httpUpdate.onStart(update_started);\r\n      httpUpdate.onEnd(update_finished);\r\n      httpUpdate.onProgress(update_progress);\r\n      httpUpdate.onError(update_error);\r\n      t_httpUpdate_return ret = httpUpdate.update(wificlient, upBinUrl);\r\n\r\n      interrupts();  // 恢复全局中断\r\n      espReboot();\r\n    }\r\n    if (msg == \"billboard2:on\") {  //13脚高电平 广告牌2开启\r\n      digitalWrite(billboard2, HIGH);\r\n      const char* strtem = \"系统任务 广告牌2已开\";\r\n      client.publish(pubshTopic, strtem);\r\n      return;\r\n    }\r\n    if (msg == \"billboard2:off\") {  //13脚低电平 广告牌2关闭\r\n      digitalWrite(billboard2, LOW);\r\n      const char* tmp = \"系统任务 广告牌2已关\";\r\n      client.publish(pubshTopic, tmp);\r\n      return;\r\n    }\r\n    if (msg == \"light:on\") {\r\n      digitalWrite(light, HIGH);\r\n      const char* strtem = \"灯 已开\";\r\n      client.publish(pubshTopic, strtem);\r\n      return;\r\n    }\r\n    if (msg == \"light:off\") {\r\n      digitalWrite(light, LOW);\r\n      const char* strtem = \"灯 已关\";\r\n      client.publish(pubshTopic, strtem);\r\n      return;\r\n    }\r\n    if (sayBool) {\r\n      if (!runIng) {\r\n        Serial.write((const uint8_t*)payload, length);\r\n      }\r\n      return;\r\n    }\r\n    // client.publish(pub,str.c_str());\r\n  }\r\n}\r\n\r\nvoid reconnect() {\r\n  while (!client.connected()) {\r\n    String clientId = \"ESP32Client-\";\r\n    clientId += String(random(0xffff), HEX);\r\n    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {  // 无认证时留空\r\n      //Serial.println(\"MQTT 连接成功\");\r\n      client.subscribe(subTopic);\r\n    } else {\r\n      Serial.print(\"连接失败, rc=\");\r\n      Serial.print(client.state());\r\n      delay(5000);\r\n    }\r\n  }\r\n}\r\n//关闭上升,下降,变压器主电源\r\nvoid closeAll() {\r\n  digitalWrite(doorOpen, LOW);\r\n  digitalWrite(doorClose, LOW);\r\n  delay(200);\r\n  digitalWrite(doorPower, LOW);   //断开电源接通\r\n  sayBool = false;                //扫描状态关闭\r\n  digitalWrite(broadcast, HIGH);  //扫描关\r\n}\r\nvoid espReboot() {\r\n  ESP.restart();\r\n}\r\nvoid espSleep() {\r\n  closeAll();\r\n  delay(200);\r\n  const char* tmp = \"door1进入休眠状态,3小时后醒...\";\r\n  client.publish(pubshTopic, tmp);\r\n  delay(200);\r\n  WiFi.disconnect();\r\n  myTicker.detach();\r\n  delay(200);\r\n  //进入深睡眠状态，将在 3 小时后唤醒\r\n  esp_sleep_enable_timer_wakeup(10800000000);\r\n  esp_deep_sleep_start();\r\n}\r\nvoid update_started() {\r\n  // client.publish(pubshTopic, \"CALLBACK:  HTTP update process started\");\r\n}\r\n\r\nvoid update_finished() {\r\n  // client.publish(pubshTopic, \"CALLBACK:  HTTP update process finished\");\r\n}\r\n\r\nvoid update_progress(int cur, int total) {\r\n  // client.publish(pubshTopic, \"CALLBACK:  HTTP update process\");\r\n}\r\n\r\nvoid update_error(int err) {\r\n  // client.publish(pubshTopic, \"CALLBACK:  HTTP update fatal\");\r\n}\r\n\r\n//无网特殊状态下安全限位\r\nvoid html_whlie() {\r\n  //操作运行时 上升达到限位了,并且上次状态不是上升上限, 并且执行状态是上升 限位开关断开\r\n  if (digitalRead(doorOpenEXTI) == HIGH || digitalRead(doorCloseEXTI) == HIGH) {\r\n    //关闭所有开关\r\n    closeAll();\r\n    Serial.println(\"达到上限\");\r\n    myTicker.detach();\r\n    delay(200);\r\n    ESP.restart();\r\n  }\r\n}\r\n\r\n\r\nvoid SetWifi() {\r\n  ssid = webserver.arg(0);\r\n  passwd = webserver.arg(1);\r\n  String sp = ssid + \"&\" + passwd;\r\n  Serial.println(sp);\r\n  Serial.println(\"密码在前面\");\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  const char* Ssid = ssid.c_str();\r\n  const char* WifiPw = passwd.c_str();\r\n  WiFi.begin(Ssid, WifiPw);\r\n  WiFi.mode(WIFI_STA);\r\n  delay(200);\r\n  Serial.println(\"wifi_connet\");\r\n  int ii = 0;\r\n  for (ii; ii < 20; ii++) {\r\n    delay(500);\r\n    Serial.print(\".\");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      webserver.send(200, \"text/plane\", \"Wifi密码正确,ESP准备重启\");\r\n      webserver.close();\r\n      delay(500);\r\n      WiFi.disconnect();\r\n      delay(500);\r\n\r\n      //写入数据\r\n      SPIFFS.format();\r\n      delay(500);\r\n      SPIFFS.begin();\r\n      File dataFile = SPIFFS.open(flash_wifi, \"w\");\r\n      dataFile.println(sp);\r\n      dataFile.close();\r\n\r\n      Serial.println(\"HTML连接成功\");\r\n      delay(500);\r\n      ESP.restart();\r\n    }\r\n  }\r\n  webserver.send(200, \"text/plane\", \"Wifi密码错误,请重新输入\");\r\n}\r\n//------- 展示页面-------\r\nvoid handlejsonArr() {\r\n  webserver.send(500, \"text/html\", html);\r\n}\r\nvoid handleNotFound(void) {\r\n  webserver.send(404, \"text/plain\", \"404-The page is not Found!\");\r\n}\r\n\r\nvoid ApStart() {\r\n  WiFi.disconnect();\r\n  delay(500);\r\n  Serial.begin(115200);\r\n  WiFi.mode(WIFI_AP);\r\n  IPAddress local_IP(192, 168, 168, 2);\r\n  IPAddress gateway(192, 168, 168, 1);\r\n  IPAddress subnet(255, 255, 255, 0);\r\n  WiFi.softAPConfig(local_IP, gateway, subnet);\r\n\r\n  //启动AP模式,并设置账号和密码\r\n  WiFi.softAP(\"192.168.168.2\", \"\");\r\n}\r\nvoid webserverStart() {\r\n  //-----------------启动webserver网络服务--------------------\r\n  webserver.begin(80);               // 启用网络服务\r\n  webserver.on(\"/\", handlejsonArr);  // / 在HTTP中,表示请求首页服务,\r\n  webserver.on(\"/SetWifi\", SetWifi);\r\n  webserver.onNotFound(handleNotFound);  // 当服务器没找到所需的服务,调用404函数\r\n  Serial.println(\"webserver started\");\r\n}\r\n\r\nvoid ForPing() {\r\n  //定时时间到了,先取消定时状态\r\n  myTicker.detach();\r\n  closeAll();\r\n  delay(500);\r\n\r\n  ESP.restart();\r\n}\r\n//扫描附件WIFI\r\nvoid WifiScan() {\r\n  Serial.begin(115200);\r\n  WiFi.disconnect();\r\n  WiFi.mode(WIFI_STA);\r\n  delay(100);\r\n  int n = WiFi.scanNetworks();\r\n  if (n > 0) {\r\n    Serial.println(n);\r\n    String a = \"附近WiFi <select id=\\\"ssid\\\">\";\r\n    for (int i = 0; i < n; i++) {\r\n      Serial.println(WiFi.SSID(i));\r\n      a = a + \"<option value=\\\"\" + WiFi.SSID(i) + \"\\\">\" + WiFi.SSID(i) + \"</option>\";\r\n      delay(50);\r\n    }\r\n    String HtmlStart = String(\"\") + \"<!DOCTYPE html>\" + \"<html>\" + \"<head>\" + \"<meta charset=\\\"utf-8\\\">\" + \"<meta name=\\\"viewport\\\" content=\\\"width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\\\" />\" + \"<title>设置WiFi</title>\" + \"<link rel=\\\"stylesheet\\\" href=\\\"\\\">\" + \"</head>\" + \"<script>\" + \"onload  = function() {\" + \"document.getElementById(\\\"up\\\").onclick = function(){\" + \"var ssida=document.getElementById(\\\"ssid\\\").value;\" + \"var ssid=ssida.replace(/\\\\s+/g, \\\" \\\");\" + \"var passwda=document.getElementsByTagName(\'input\')[0].value;\" + \"var passwd=passwda.replace(/\\\\s+/g, \\\" \\\");\" + \"xhr = new XMLHttpRequest();\" + \"xhr.open(\\\"POST\\\",\\\"./SetWifi\\\",true);\" + \"var posts = (\\\"ssid=\\\"+ssid+\\\"&passwd=\\\"+ passwd);\" + \"xhr.setRequestHeader(\\\"Content-Type\\\",\\\"application/x-www-form-urlencoded\\\");\" + \"xhr.send(posts);\" + \"xhr.onreadystatechange = function(){\" + \"if(this.readyState == 4 && this.status == 200){\" + \"alert(this.responseText);\" + \"}\" + \"}\" + \"}\" + \"}\" + \"</script>\" + \"<body>\";\r\n    String HtmlEnd = String(\"\") + \"<p>WiFi密码<input type=\\\"text\\\" id=\\\"passwd\\\"></p>\" + \"<input type=\\\"submit\\\" id=\\\"up\\\" value=\\\"设 置\\\">\" + \"<hr/>\" + \"<font color=\\\"red\\\">附近WiFi没有显示到自己的WIFI请重启或离信号源近点</font>\" + \"</body>\" + \"</html>\";\r\n    a = a + \"</select>\";\r\n    html = HtmlStart + a + HtmlEnd;\r\n  } else {\r\n    html = \"扫描不到网络\";\r\n    Serial.println(\"扫描不到网络\");\r\n  }\r\n}\r\nbool FlashConnetWifi() {\r\n  Serial.begin(115200);\r\n  delay(500);\r\n  //是否存在数据\r\n  SPIFFS.begin();\r\n  if (SPIFFS.exists(flash_wifi) == false) {\r\n    Serial.print(flash_wifi);\r\n    Serial.println(\" NOT FOUND\");\r\n    return false;\r\n  }\r\n\r\n  File dateFile = SPIFFS.open(flash_wifi, \"r\");\r\n  String result = dateFile.readString();\r\n  result.trim();\r\n  Serial.println(result);\r\n  int i = result.indexOf(\"&\");\r\n  String wifiname = result.substring(0, i);\r\n  String wifipw = result.substring(i + 1);\r\n  const char* Ssid = wifiname.c_str();\r\n  const char* WifiPw = wifipw.c_str();\r\n  Serial.println(Ssid);\r\n  Serial.println(WifiPw);\r\n  WiFi.begin(Ssid, WifiPw);\r\n  delay(500);\r\n  WiFi.mode(WIFI_STA);\r\n  Serial.println(\"FlashConnetWifi->connet\");\r\n  int wifiTimeout = 0;\r\n  for (wifiTimeout; wifiTimeout < 30; wifiTimeout++) {\r\n    delay(500);\r\n    Serial.print(\" . \");\r\n    if (WiFi.status() == WL_CONNECTED) {\r\n      Serial.println(\"FlashConnetWifi 闪存配置连接成功\");\r\n      return true;\r\n    }\r\n  }\r\n  Serial.println(\"FlashConnetWifi-> timeout\");\r\n  return false;\r\n}\r\n\r\nvoid HtmlSetWifi() {\r\n  WifiScan();\r\n  ApStart();\r\n  delay(1000);\r\n  Serial.println(\"启动网页\");\r\n  myTicker.detach();\r\n  delay(200);\r\n  //5分后重启 防止停电后复电,路由器连接WIFI速度慢于ESP导致ESP连接不到路由器进入无限AP模式,所以这里只让AP 激活5分钟后就重启\r\n  myTicker.once(300, espReboot);\r\n  delay(200);\r\n  webserverStart();\r\n  while (1) {\r\n    webserver.handleClient();  // 检查网络服务请求并处理\r\n  }\r\n}\r\n','',1),
