2025年的夏天过去了

7 月初的时候,我和小棉袄回了一趟老家。过去好些年我都是过年才回去,也就是偶尔有事才会在其他时间。上次在家过夏天我的记忆还停留在高中的时候,大学的暑假都是在学校,因为路费贵啊,毕业那年,回家没几天就南下了。 这一晃就是二十多年了,2025 年的夏天也悄悄过去了,我有些怀念她。 老房子还立着那,但并不是我小时候住的房子,买的时候我已经上初中了,所以我住这里的时间并没有多少,高中暑假在家的时候,我在堂屋睡午觉,一条菜花蛇在后门口睡觉。上大学之后再没见过了,估计它早死了吧。 家里两只猫天天飞檐走壁,今年或者明年老房子就会拆了,我觉得已经是危房了,但我爸妈还在里面养了头猪。 这里本来是家里的水田,我爸要养龙虾,就找挖机挖了个鱼池,养龙虾,鱼。搞了好几年,每年我爸能弄个几千块钱吧。这是去年拍的照片。 今年国家又拨款改田,小田改大田,于是就回填了,想着以后也没人弄了。 改田后就租给人种了,我看秧长的并不好。 从家门口走出去五十米,就是我的小学,但最早的校舍早就拆除了,楼房是我四年级的时候盖好的,现在村里租给了一个工厂加工豆皮,老师的宿舍也全部卖给了一个村民。 可以看到,六十年代建造的学校房子其实还剩了一片,断壁残垣,梁已经都塌了,瓦落了一地,一排柱子没剩多少了,只有红色的砖墙还立着。记忆中这几间房开始是老师的食堂,供销社,村医务室。后来村里给了一孤寡老书记住,另外部分租给人开酒厂。那老头天天聚集一帮人打上大人,喝茶,我外公就是常客。他最后一天的上午就是在这里,和他的牌友们打了半天牌,中午回去就在树上上吊了。 等到那个老头死了,酒厂也没开下去,酒厂的老板娘出去打工,老板混了几年,离婚,出走,这一片房子就再也没人住过了,任凭风吹雨打,直到现在的模样。 水泥路旁都被人见缝插针的种上了农作物,这边是芝麻,路是村里的,所以谁种就是谁的。 这家屋后种了一些花,我没记错的话应该叫太阳花。 我外公外婆的墓,今年改田后在路上只能看到坟上的草了。我爬了半天过去,四周的旱田都改成了水田,中间几座坟凹在里面,地都是稀的。 这是今年改的大田,以前田埂没这么高,现在他们把梯田推成了平田。 一块块小田连成了一片,稀稀拉拉的秧,癞子一样,租田大户今年全靠国家补贴了。现在基本都是机械化作业了,村里也没几头牛。 堰里的水挺满的,虽然一直干旱。小时候觉得这口堰好大好大,游泳根本游不到头,现在水浅的地方全部填了。它的名字叫妖堰,小时候传说有鬼,我们都很少下去玩,怕被拉走。 刚推平的水田,看得出来没有任何肥力,也旱的开裂了,秧才那么一点点,今年能收点喂鸡都不错了。 水沟两边种满了黄豆,应该是吧,我已经分不清黄豆和绿豆了。 我们管这种野生的瓜叫喜瓜,还没熟。小时候没有零食吃,夏天的棉花地里有很多这种瓜,还没鸡蛋大,但成熟了还是很好吃的。运气好能碰到变异的喜瓜,比鸭蛋还大,吃起来特别开心特别香。 走到我从小成长的地方了,这是我家的山,里面埋着我的爷爷奶奶。山旁边这家是贵州移民,他的地每年往我山这边犁一道,已经侵占了好几米了。我家没人说,他们就得寸进尺了,后面我有时间了回来弄水泥筑一道墙隔着。 从上学前班开始,我就记得邻居家后面的这棵树,名字好像叫榨树。那时候也就碗口粗,两三米高吧。我上学放学常常从它旁边走过,四十年过去了,好像没人砍过它。它自由自在的生长,也没长多少,叶生叶落之间,我已经老了不少。 月亮也还是那个月亮,98 年世界杯的时候,我就是在这样的月色下等待,等待比赛开始。我的爷爷奶奶坐在路边上乘凉,有一句没一句的聊着天。

2025/9/15
articleCard.readMore

京都杂记

趁着小棉袄暑假带她去了一趟日本,主要目的地是京都,总共五天。 我们从深圳出发,过关到香港机场,直飞大阪。上次从香港出发还是去台湾,带着小棉袄从台北到台中再到垦丁,可惜的是,18 年之后就不能台湾自由行了。 在日本进关,最好在 Visit Japan Web 预先填好,这样不用走人工,人脸识别就好了,非常方便快捷。 虽然不会日语,英语也不行,过关没任何障碍,看标识就好了,而且有的日本工作人员会说中文。 从大阪关西机场出来,直接买票坐大巴到京都。 大阪的海很黑,应该是太深了吧,跟我去南海的时候一样。 路过大阪的工厂。 大阪的天空。 App 英语也不行,在日本只能通过手机翻译软件交流,Android 上的微软翻译还挺好用的,在日本全靠它了。 手机网络直接用荣耀的环球行,15 块钱一天 1GB,超过了限速不断网,18 块钱一天 5G,当然还有直接买流量的,比如 1GB(7天有效)15 块钱。看需求吧,反正我一天 1GB 就够了,注意最好一天一天的购买,不然中途想改套餐的时候不能停,不能退,只能浪费了。 流量还可以到了目的地买,也可以一个人开了共享一家人用,就是人不能分开了。 导航就只能是 Google Maps 了。 话说之前小棉袄花了上万学日语,现在基本忘光了,英语补习也花了几万,结果在日本不敢张嘴,天天就知道跟我嘚瑟。 酒店 携程提前预订的京都格兰德酒店,三个人一间,和国内比有点小,价格不算贵吧,五六百人民币一晚。 干净整洁,该有的都有,比如智能马桶。有一个小冰箱,只能冷藏,期间买了一盒冰淇淋,全化了。 还有一个房间里有洗衣机等,我们没这个需求,就没进去研究。 纯净水需要自己去拿,晚了就没有了,一般一人一天一小瓶。 比较遗憾的是没看日本的电视节目,每天回来太累了,洗澡就睡觉了。 大家知道窗户上贴的红色三角是什么意思吗?不光酒店有,有些大厦也有贴,我没发现什么规律,开始还以为是没人的楼梯或房间呢。 京都 到京都时天色已暗,入住后逛了逛附近的商场,随便找了些吃的,味道还挺好。 看到了京都塔。 第二天我们就在京都逛了逛,打算去吃一个说很好吃的拉面,结果到了那里没开门,当天休息。最后随便找了一家吃面,味道也不错,我就喜欢日本台湾的面有硬度等级选项。 第一个感觉就是京都好多寺庙啊,到处都是寺,大的小的,收费的免费的。 小棉袄在路上拍了好多照片,说这是日本漫画里的感觉,最后一天她还让她妈带去买了一套日本漫画。 日本的住宅不光干净整洁,很多外面都有放一些花花草草,有趣的摆件等,感觉好有生活情趣啊。 去了趟二条城,里面不让拍照,很多古董画,也看不懂,房子都是木质的。 京都的天空好漂亮。 什么金阁寺清水寺伏见稻荷大社我们都没去,只去了永观堂。 寺里基本上都是中国人,穿日服拍照的特别多,只碰到一对说日语的情侣,但看他们的跪姿,感觉男的是日本人女的不像。 寺里特别清静,非常适合安安静静的待着,啥也不想,发呆。 这里没有功德箱,更别说二维码了,不过我发现里面的水池也是用水泵抽的,感觉像活水。 国人的习惯非常不好,到哪里垃圾就丢哪里。 这是京都最后一天逛街时发现的,北纬 35度: 京都这样的电动车好多,铃木本田三菱各种牌子的都有,但是我没见过特斯拉或者国产的。 京都的路都不宽,但车流量不小,开车都很规范,所以很少像深圳这样堵车的。当然,我也见过有人实线变道超车的,边开车边看手机的。 超市里好多饮料啊,价格有点贵,好想都来一瓶试试。 超市买的桃子,差不多人民币 20 块钱一个,个头大,但味道没有价格那么震撼。 奈良 第三天我们去了一趟奈良,坐的什么车去的我真说不清楚,因为京都站下的地铁,近铁,JR线,电车,特急,我始终没搞清楚怎么坐,看图都看不懂。 最后通过翻译软件让工作人员教我们坐的,至于票价什么的根本不考虑了。 到奈良很快,路上的风景也很好,真想下次去京都附近的乡下走一走啊。 出了奈良站我们就去了一个无人值守的自行车出租店,拍一下护照,支付了现金就可以拿车了,我们租了三辆电动助力的。 先去公园看鹿,到处是鹿,味道很大。 门口的柱子好粗,两个人都不一定合抱的上。 中国人多,外国人也多,还有台湾人,热闹。 这只鹿很聪明,跑到水池里,就它一个,很多人喂它,吃到饱。这几个小朋友都是国内的。 逛了大半天饿得要死,在下山的路上找了一家面馆,等了一会儿,服务员出来说,时间快打烊了,不再接待了。又找了一家,也是营业到两点,还好客人比较少,我们是最后一拨。 家庭式面馆,味道还可以,卫生就不用说,整个店里都非常干净。因为不认识菜单,我随便点了一个,面太清淡了,两口我就干完了。临走时,老板还用中文说再见。 在日本吃饭,你会发现店里特别安静,都是小声说话,包括我们这些外国人。 总结 京都是一个非常适合慢慢游玩的地方,可以来多次,吃住我觉得都很方便,坐地铁,近铁什么的我是搞不懂,所以我们一直都在市内坐的公交车,慢是慢了点,但好认地方啊。 我发现日本的公交车有一个很有意思的地方,它的地盘是可以下降的,我估计能降 20cm 左右。这样比较方便上下车,而且碰到坐轮椅的,司机还要下来帮忙,有点累哈。 日本的商场商店饭馆等地方到点就打烊下班了,不会因为说还有几桌客人可以再接待一下,我觉得这样的生活挺好的,国内就完全不可能。 我在京都没看到一个送外卖的,快递等,电动车也没见过,摩托车有,但很少,自行车倒多了点,但也没有共享单车。下班的时候,好多人都是背个包步行,可能离家近吧,真好。 虽然在日本待了不到五天,但路上边走边看手机的人我遇到的可能都不到五个,这就很神奇了,深圳满大街的都是低头族。不知道日本人刷手机都刷啥,Twitter,YouTube 吗?不抖音? 我还逛了两个卖电子产品的商场,人没有华强北多但也不少,价格比京东贵,所以啥也没买。我本来还想看看日本的钢笔能不能捡个便宜的,结果商场里卖的都好贵,最后在日本基本上是啥也没买。 在日本,外面基本上看不到垃圾桶,也很少有搞卫生的人,最多有的店里有让扔饮料瓶,所以我们每天只能把垃圾带回酒店,酒店的人来分类处理了。国内的城市卫生全靠海量的清洁工人,以后人会越来越少,但大家却没个好习惯,咋办? 还有一个疑惑,京都我也逛了不少地方,就没看到一个卖片的店啊,更别说风月场所了。 这次我护照签的是 3 年多次,花了五百多,估计小棉袄初中毕业了还得再去了。日本也确实值得多次游玩,只不过语言不方便,我打算学习一年日语,看看能不能日常交流。 其实我还是喜欢去台湾,风景宜人,吃住行都非常舒适,价格和深圳差不多,人也特别友好,当然,已经七八年了,不知道现在如何了。比如香港,这十几年变化天翻地覆。

2025/9/6
articleCard.readMore

OpenWrt插件-应用过滤OpenAppFilter如何自定义特征库

之前我对 OpenWrt 的网络控制插件试用总结,最后只留下了插件 应用过滤(OpenAppFilter)。 应用过滤(OpenAppFilter)的特征库虽然开发者有 VIP 服务,提供了更丰富的特征库,但我的需求只针对个别的一些网站过滤,所以研究了一下如何自己添加特征码。 对特征库有刚需的可以购买 VIP 支持一下开发者,也不算贵 39。 特征库文件 首先在这里下载免费的特征库: 网址:https://www.openappfilter.com/#/feature 解压后有三个文件,两个 bin 文件是特征库,可以看升级说明两个文件的不同: 继续解压 bin 文件,可以看到一个 feature.cfg,一个 app_icons,很好理解了。 特征码格式 特征库文件用于存储所有 APP 的特征码,为非加密的文本文件,一般 .cfg 格式,可以通过文本文档编辑。 特征库文件说明:https://github.com/destan19/OpenAppFilter/wiki/self%E2%80%90define-feature-file 特征码用于定义每个 APP 的协议特征,比如可以定义端口号、域名、七层内容字典等: $id $name:[$proto;$sport;$dport;$host url;$request;$dict] $id: 唯一的 APP 编号,不能重复 $name: APP 的名称,比如抖音 $proto: 传输层协议,tcp 或 udp $sport: 源端口,1-65535,不设置表示匹配所有,一般不用设置源端口 $dport: 目的端口,1-65535,不设置表示匹配所有 $host: http或者https请求的域名,比如 www.baidu.com $dict: 七层内容字典,格式 xx:aa|yy:bb,其中 xx,yy 是位置,表示第几个字节,而 aa,bb 表示十六进制内容,示例:00:a0|02:08|03:0a,表示第 0 个位置为 0xa0,第 2 个位置为 0x08,第 3 个位置为 0x0a,注意第一位从 0 开始,如果位置为负数,表示从最后一个开始,一般不要用负数表示。 自定义特征库 打开特征库文件 feature.cfg 后可以看到如下内容: #class video 3 视频 3001 抖音:[tcp;;;-dy-;;,tcp;;;-dy.;;,tcp;;;douyin;;,tcp;;;amemv.com;;,tcp;;;pstatp.com;;,tcp;;;volcsirius.com;;,tcp;;80;;^/pull.*.douyincdn.com;,tcp;;;ecombdapi.com;;,udp;;443;;;09:51|10:30|11:34;amemv.com;0,udp;;16000;;;00:00|01:01,udp;;1000-2000;;;00:00|01:01] 3006 斗鱼:[tcp;;;douyu;;,tcp;;;douyu;;-2:2f|-1:00] 3004 爱奇艺:[tcp;;;iqiyi;;,tcp;;;qy.net;;,tcp;;;inter.71edge.com;;,tcp;;;;^/videos;,tcp;;80;;;00:51|01:48|02:54,tcp;;80;;;09:00|10:00|11:00] 3014 哔哩哔哩:[tcp;;;bilivideo;;,tcp;;;bilibili.com;;,tcp;;;data.bilibili.com;;,tcp;;;biliapi.net;;,tcp;;;;;00:47|05:75|06:70|07:67,tcp;;;;/bfs/emote/;,tcp;;;hdslb.com;;,tcp;;1000-10000;;/v1/resource;,tcp;;8082;;;;00:16|01:03|02:01] 3008 虎牙直播:[tcp;;;huya;;,udp;;;;;01:00|02:00|03:00|04:23,udp;;;;;01:00|02:00|03:00|04:24] 3010 小红书:[tcp;;;xiaohongshu;;,tcp;;;xhscdn;;] 可以在同一个分类中复制某个 APP 特征,追加到该分类的最后一行,这样用于保证 appid 中的分类字段是统一的 appid 的低 3 位表示分类中的编号,高位表示分类 id,比如 3001,其中 3 表示视频分类,而 001 为编号,表示抖音。 复制后首先需要修改 appid,保证组内唯一,最好是组内编号最大值加 1,比如当前最大值为 3012,那新的 appid 就设置成 3013,这样方便统一管理。 比如现在要增加一个 web 游戏网站 poki.com,那新增的特征码定义如下: 2117 宝玩:[tcp;;;*.poki-cdn.com;;,tcp;;;poki.com;;,tcp;;;t.poki.io;;] 多个网址之间可以用 , 分隔,相互之间是或的关系。 添加完成后,记得把文件页首的版本号更新一下。 获取网站的 logo 图片,大小格式为 50x50,PNG,如果不想找,随便用个替代图片也是可以的。图片按格式保存到 app_icons 文件夹内,名称按对应的 appid 命名。 我发现 app_icons 文件夹里的 appid 数量很多,所以 appid 最好先看下文件夹内的最大编号。 浏览器分析域名 在 PC 端使用 Chrome 开发者工具分析网站域名比较方便。 使用 Chrome 打开网站前,先按键盘:F12 再切换到顶部 Network(网络)标签页。 勾选上面的选项 Preserve log,以便页面跳转后保留请求记录。 点击左上角的“🛑”停止按钮或“⨯”图标清除之前的请求。 在浏览器地址栏输入 https://poki.com 并回车,开始加载页面。 在 Network 里,有许多条请求记录,在 Name / Domain 列查看以下域名(如果没有就右键列首,勾选网域): poki.com *.poki.io *.poki-cdn.com 这些都是页面加载过程中涉及的域名,可以按规则加入 feature.cfg。 Wireshark 抓取没有域名的应用 有些没有明显域名但有独特流量特征的应用(如手游、专有加密协议)需要 Wireshark 抓包,获取 $dict 所需的字节特征(也就是七层协议数据中的特定字节内容)。 两种方法: 用笔记本做热点,手机 WiFi 连接笔记本,直接用 Wireshark 抓包分析 在路由器上用 tcpdump 抓取网络数据包,保存下来用 Wireshark 分析 .pcap 文件 我编译的 X86 固件添加了 tcpdump 插件,直接抓取,下载 pcap 文件,然后用 Wireshark 分析。 选择要抓取的端口; 设置抓取时间; 抓包; 等待完成后即可看到 .pcap 文件。但是在插件页面不知道为什么点按钮无法下载,更换浏览器也不行,只能通过文件管理去下载,目录:/tmp/tcpdump/cap/ 当然也可以在 OpenWrt 命令行中安装 tcpdump: opkg update opkg install tcpdump 安装后通过终端命令抓包: 可以参考这里:OpenWrt抓包 Wireshark 打开文件后可使用下列过滤条件,如专门分析 IP:192.168.1.101 的设备数据: ip.addr == 192.168.1.101 && (http.host || tls.handshake.extensions_server_name) 在任意一个 HTTPS 握手包选择后展开 Transport Layer Security → Extension: server_name,右键 → Apply as Column,主界面就会多一列 Server Name,这样所有请求对应的域名一眼就能看出来了。 Wireshark 界面如下: 选中该应用 TCP/UDP 会话,查看数据包内容。如下: 0000 a0 45 13 10 00 1c 00 00 00 03 01 0a 00 00 00 01 0010 4f 12 09 45 01 5d ... 对应 $dict 规则: 00:a0|01:45|02:13|03:10 规则匹配建议: 位置尽量靠前(前几十字节) 尽量使用固定字段(如协议标志) 避免使用 IP /端口变化的数据或会话 ID(不稳定) 可以通过比较多个数据包找出固定不变的字节序列 对于加密通信(如 HTTPS),可从 Client Hello / SNI 获取字节。 对于 WebSocket,可查看握手包中独特字段。 其实我对 Wireshark 抓包分析也不熟,都是现学现卖。 封装 bin 文件 feature3.0_cn_20250316.bin 文件虽然解压就可以自定义特征码了,但如何重新封装成 bin 文件呢?开始我以为直接压缩后将格式改成 bin 就完事了,后来发现根本不行。 于是我先分析了一下 feature3.0_cn_20250316.bin: sudo apt install binwalk # Ubuntu/Debian 安装 binwalk binwalk feature3.0_cn_20250316.bin 接着会看到类似这样的输出: DECIMAL HEXADECIMAL DESCRIPTION -------------------------------------------------------------------------------- 0 0x0 gzip compressed data, from Unix, last modified: 1970-01-01 00:00:00 (null date) 这说明 feature3.0_cn_20250316.bin 文件是纯 gzip 压缩文件。 目录结构如下: feature/ ├── feature.cfg └── app_icons/ ├── ... 先进入 feature 文件夹目录,再打包,封装成 .bin 格式: tar -cf feature.tar feature.cfg app_icons # 先将文件一起生成 tar 包 gzip -c feature.tar > feature3.0_cn_20250822.bin # 压缩成 .bin 格式 这样就生成了一个新的特征库文件:feature3.0_cn_20250822.bin。直接在插件管理页面上传就可以了。 应用过滤 特征库下载 分享一下我的特征库,添加了宝玩游戏和几个网盘。 夸克网盘分享:https://pan.quark.cn/s/e9e26f3f5881 提取码:n1MD 百度网盘分享:https://pan.baidu.com/s/1qcsD1XVwoLjC4J3vAwBh2A?pwd=hm8g 提取码: hm8g OpenWrt X86 固件 我编译的 X86 固件,有应用过滤和网络控制插件,当然还有各种科学上网工具: 夸克网盘分享:https://pan.quark.cn/s/275136450f54 百度网盘分享:https://pan.baidu.com/s/1BTbtZJQvvUXtfwCAknNJdQ?pwd=xg1r 提取码: xg1r 应用过滤 openappfilter 的问题 过滤的网址,有可能还会引起其他的网址无法访问,比如我屏蔽了几个国内视频网站,接着 Google 就无法搜索了。原因不明,我也没找到解决方法。(有时又正常了) 应用过滤这个插件会影像 Docker,如果应用过滤启动了,那么容器会报 500 错误,只能先启动容器,再开启应用过滤插件。 如果同时打开了科学上网插件,那么应用过滤的网站同时也是代理的网站,那过滤无效。比如我开启了所有国外网站都走科学上网,那么应用过滤里的所有国外网站还是都能正常访问的。这就是我为什么没有把国外的社交网站,视频网站加到特征库的原因。

2025/8/27
articleCard.readMore

Arduino烧录hex固件的多种方法

Arduino MCU HEX 文件下载器(烧录软件)我搜了一下,还是有不少的,但很多只支持原生 Arduino 开发板,对于 STM32,ESP32,ESP8266 很少有支持的,目前我找到的仅有 Freematics Builder 支持 ESP32。 ZTFlashWriter ZTFlashWriter 是哲涛工程师基于 Arduino 1.8.9 软件开发的离线 Arduino HEX 文件下载工具。 本工具不需要 Arduino IDE,即可直接把 HEX 文件下载到 Arduino 相关主板上。 本软件支持批量烧录,可以同时给连接在一台主机上的15个主板烧录同样的固件(HEX文件)。 本软件支持常见的所有 Arduino 原生开发板。 本软件不需要安装, 下载后解压即可打开使用。 本软件仅适用Windows系统,建议在Windows10+中使用。 下载链接: https://www.zhetao.com/mcu-download-tools.html OpenJumper™ Serial Assistant 同样的一款 Windows 下的 HEX 下载工具,看文件目录,下载应该是基于 avrdude,仅支持原生的 Arduino 开发板。而且该软件不开源,还停留在十几年前,适合老电脑使用。 下载链接: OpenJumper™ Serial Assistant 1.3.6beta.zip 链接:https://pan.quark.cn/s/b056c8c8bff6 提取码:QsLB 软件介绍: https://openjumper.com/doc/install https://www.cnblogs.com/wind-under-the-wing/p/14686625.html Freematics Builder 这是一个卖 OBD 公司开发的,主要是针对自己的产品,所以只有几种型号的 Arduino 支持,但是可以下载到 ESP32。 下载链接: FreematicsBuilder-1.3.1-win32.zip 链接:https://pan.quark.cn/s/9b9790da046a 提取码:7Rxy 有在 GitHub 提供下载,但似乎没有开放源码:https://github.com/stanleyhuangyc/Freematics/releases 使用介绍:https://blog.csdn.net/LostSpeed/article/details/129730169 avrdude 这个是命令行下载工具,支持 Windows,Linus,Mac,也仅支持 Arduino 原生开发板。 开发者源码: https://github.com/avrdudes/avrdude 使用介绍: https://hackmd.io/@Jub9Bu1BR0qRYeSAA0wUJQ/SkvOGZIE6 Arduloader 也是一款 Windows 下的工具,十年前的软件,仅支持 Arduino 原生开发板。 开发者源码: https://github.com/uname/Arduloader 使用介绍: https://uname.github.io/2015/07/15/arduloader/

2025/8/9
articleCard.readMore

2025最新-Google AdSense税务居住地证明如何申请?中国税收居民身份证明轻松搞定

Google AdSense 后台一直在提醒:“请采取行动:您的AdSense 收款账号中有一些需要核实的信息”。 我搜了一下,发现 Google AdSense 的税务居住地证明就是申请中国税收居民身份证明,看了几个教程都很麻烦,提供很多资料,甚至有的要去税务局提交资料。我的账号反正也没钱,就一直没管,后来看到国家税务局通告说 4 月 1 日起就可以在自然人电子税务局网上申请了。 五月份的时候,又搜索了一下,看到一些新的教程出来了,还要提供不少资料,而且还有和税务局的人沟通。 等到 7 月底,我试了一下,流程应该已经正常了,材料非常简单,已经无须人工沟通了。 首先访问 自然人电子税务局:https://etax.chinatax.gov.cn,登录后选择中国税收居民身份证明开具: 申请开具: 申请年度和国家,一般都是新加坡: 下一步,进入填报: 受雇单位都是默认无法更改的,如果是无业的话那我也不知道是啥了: 特殊要求:否 享受协定待遇 一般都是 Google 新加坡公司的名字: Google Asia Pacific Pte. Ltd. 协定名称:中华人民共和国政府和新加坡共和国政府关于对所得避免双重征税和防止偷漏税的协定 协定条款:独立个人劳务条款 协定待遇收入金额按人民币,起付标准是 100 美元,我也就这么多算不错了,所以 720 和减免 720×20%=144 附件上传 Google AdSense 服务条款,中英文版 PDF Google AdSense Online Terms of Service.pdf 链接:https://pan.quark.cn/s/71da29b4ccbe 提取码:czDE Google AdSense 在线服务条款中文版.pdf 链接:https://pan.quark.cn/s/b03713dba10b 提取码:ZUH3 上传身份证和户口簿,其中证明申请人英文名称的和身份证件都是上传的身份证,户口簿我上传了首页和个人页。 纳税人识别号即身份证号,所有文件我都是扫描成 PDF 格式: 点下一步,检查一下提交: 过了一周多,我忽然想起来了,登录查看,已经确认了: 下载 PDF: 登录 Google AdSense,删除之前提交的记录,重新上传,很快就审核通过了:

2025/8/7
articleCard.readMore

乌龟自动喂食器2.0升级

简介 去年五一之前给三只小龟做了个自动喂食器:赶在五一之前给乌龟做个自动喂食器,刚好一年过去了(我这拖延症),升级到了 2.0 版本,主要是增加了自动水循环系统。 结构设计 在结构上增加了一个循环水箱,一个过滤水箱。水从循环水箱里抽出来,经过过滤水箱后给乌龟们洗澡喝水,再回流到了循环水箱里面。画了一个示意图: 在经过一段时间的循环后,水必然会减少,除了乌龟们用的,还有蒸发的,所以还得往循环水箱里面加水。既然自动化了,当然不能让我每天盯着水少了就加啊。于是我就增加了一个检测水位的装置: 检测到了低水位后,水泵就打开,从水桶里往循环水箱里加水,一直加到高水位后水泵就停止了。 你问桶里没水了怎么办?当然是我手动加了,我可舍不得钱买一个能电动控制的水龙头,一个星期加一桶水,顺便清晰一下几个水箱,更换一下过滤棉。 硬件设计 主控还是 ESP8266 模块,除了自动喂食器的电机驱动,增加了两个水泵的电源控制继电器,再用两个 IO 来检测水位。 一个水泵是循环抽水的,可以通过云端设置开关的时间间隔,另一个水泵是加水的,当检测到低水位时,该水泵就打开,水位到最高点时自动关闭水泵。 监测水位的我用的是干簧管和磁铁,在防水上没什么问题,也不用多余的工作。 中间的白色浮子里面嵌入了一个小磁铁,可以飘浮在水中,随着水位升降。当水面下降时,磁铁会靠近底下的干簧管,干簧管短路,IO 电平由低变高。水位上升的时候磁铁会离开底下的干簧管,干簧管开路,IO 由高变低,当靠近上面的干簧管后,IO由低变高,说明水面到了高水位。 开始本来的想法是用水的导电性来设计水位传感器的,淘宝上卖的也基本都是这类,因为水箱离主控板比较远,线缆一长,ADC 转换的时候容易出错,所以我就改成了用 IO 电平变化来监测水位了。 电路很简单,也没考虑很多,能用就行,仅供 DIY 用。 软件设计 软件设计还是 ESP8266 模块作为 Arduino 板联网控制,通过 Arduino IoT Cloud 连接设备。 Arduino Cloud IoT 使用入门指南 Arduino 代码很简单,注释我也写得很详细,流程图如下: /* Sketch generated by the Arduino IoT Cloud Thing "Autofeed2.0" https://create.arduino.cc/cloud/things/a4043153-6bfb-4dfa-a055-151cba4627a4 Arduino IoT Cloud Variables description The following variables are automatically generated and updated when changes are made to the Thing CloudCounter motorCloudCycleHours; bool motorCloudControl; bool pumpCloudControl; CloudTime pumpCloudOffSecond; CloudTime pumpCloudOnSecond; Variables which are marked as READ/WRITE in the Cloud Thing will also have functions which are called when their values are changed from the Dashboard. These functions are generated with the Thing and added at the end of this sketch. */ #include "thingProperties.h" // 软件版本号 const char* softwareVersion = "2.1"; // 定义引脚 const int pwm1Pin = 12; // GPIO12 (D6) const int pwm2Pin = 14; // GPIO14 (D7) const int pumpPin = 13; // GPIO13 (D5) const int pumpINPin = 16; // GPIO13 (D5) const int pumpLowPin = 5; // GPIO4 (D2) const int pumpHighPin = 4; // GPIO5 (D1) // 系统故障状态 bool systemFault = false; //进水泵状态变量 bool pumpINRunning = false; unsigned long pumpINStartTime = 0; // 记录水泵开启的时间戳 const unsigned long PUMP_TIMEOUT_MS = 2 * 60 * 1000; // 进水泵运行超时2分钟 // --- 用于非阻塞去抖动的变量 --- unsigned long lastLowPinDebounceTime = 0; // 上次低水位引脚状态变化的时间(毫秒) unsigned long lastHighPinDebounceTime = 0; // 上次高水位引脚状态变化的时间(毫秒) const long DEBOUNCE_DELAY_MS = 300; // 去抖动延迟时间 (毫秒) int debouncedLowPinState = LOW; // 经过去抖动后的低水位引脚状态 int debouncedHighPinState = LOW; // 经过去抖动后的高水位引脚状态 int lastLowReading = -1; int lastHighReading = -1; // --- 通用的去抖动函数 --- // pin: 要读取的引脚 // lastStableState: 存储该引脚上次稳定的状态 (需要传入引用&) // lastDebounceTime: 存储该引脚上次去抖动的时间 (需要传入引用&) // lastReading: 存储该引脚上次读取的状态 // 返回值: 经过去抖动后的稳定状态 int debounceRead(int pin, int& lastStableState, unsigned long& lastDebounceTime,int& lastReading) { int reading = digitalRead(pin); // 读取引脚当前原始状态 // 只有当原始读取值与去抖动后的稳定状态不同时,才重置去抖动计时器 if (reading != lastReading) { lastDebounceTime = millis(); } // 如果从上次潜在状态变化到现在的时间超过了去抖动延迟 if ((millis() - lastDebounceTime) > DEBOUNCE_DELAY_MS) { if (reading != lastStableState){ lastStableState = reading; } } lastReading = reading; return lastStableState; // 返回去抖动后的稳定状态 } // 喂食电机状态变量 bool motorRunning = false; unsigned long motorStartTime = 0; // 记录电机本次启动的时间 const unsigned long motorRunDurationMillis = 25 * 1000; // 电机每次运行时间 秒 // 电机自动循环定时变量 unsigned long motorCycleStartTime = 0; // 记录上次自动循环启动的时间 unsigned long motorCycleDurationMillis = 0; // 自动循环间隔(从Cloud获取时间为小时,转换为毫秒) // 循环水泵状态变量 bool pumpRunning = false; // 控制水泵的总开关(受Cloud和遥控按键影响) bool pumpOnPeriod = false; // true表示处于水泵的ON阶段,false表示处于OFF阶段 unsigned long lastPumpToggleTime = 0; // 记录上次水泵ON/OFF切换的时间 unsigned long pumpOnDurationMillis = 0; // 水泵ON时长(从Cloud获取时间为秒,转换为毫秒) unsigned long pumpOffDurationMillis = 0; // 水泵OFF时长(从Cloud获取时间为秒,转换为毫秒) // --- 函数原型声明 --- void startMotor(); void stopMotor(); void setPumpState(bool state); void stopPump(); void setup() { // Initialize serial and wait for port to open: Serial.begin(115200); // This delay gives the chance to wait for a Serial Monitor without blocking if none is found Serial.println("Software Version: " + String(softwareVersion)); delay(100); // Defined in thingProperties.h initProperties(); // Connect to Arduino IoT Cloud ArduinoCloud.begin(ArduinoIoTPreferredConnection); // 设置引脚模式 pinMode(pwm1Pin, OUTPUT); pinMode(pwm2Pin, OUTPUT); pinMode(pumpPin, OUTPUT); pinMode(pumpINPin, OUTPUT); pinMode(pumpHighPin, INPUT); pinMode(pumpLowPin, INPUT); // 初始化输出状态 analogWrite(pwm1Pin, 0); analogWrite(pwm2Pin, 0); digitalWrite(pumpPin, LOW); digitalWrite(pumpINPin, LOW); // 初始化定时器(确保Cloud属性获取到初始值后才计算) // 第一次启动时,假定自动循环从现在开始计时 motorCycleStartTime = millis(); //电机循环开始计时 lastPumpToggleTime = millis(); //水泵的循环也从现在开始计时(如果Cloud开关打开) Serial.println("Arduino Cloud Connected!"); /* The following function allows you to obtain more information related to the state of network and IoT Cloud connection and errors the higher number the more granular information you’ll get. The default is 0 (only errors). Maximum is 4 */ setDebugMessageLevel(2); ArduinoCloud.printDebugInfo(); } void loop() { ArduinoCloud.update(); //--- 处理进水检测和水泵开关逻辑 --- // 读取水位状态并进行去抖动处理 (非阻塞方式) debouncedLowPinState = debounceRead(pumpLowPin, debouncedLowPinState, lastLowPinDebounceTime, lastLowReading); debouncedHighPinState = debounceRead(pumpHighPin, debouncedHighPinState, lastHighPinDebounceTime, lastHighReading); // 打印当前所有相关变量的实时值 Serial.printf("实时状态 -> 低水位: %d, 高水位: %d, 水泵运行中: %d\n", debouncedLowPinState, debouncedHighPinState, pumpINRunning); // 当高位检测到高电平并且进水泵在运行状态,水泵马上停止 if ((debouncedHighPinState == HIGH && debouncedLowPinState == LOW) && pumpINRunning == true) { digitalWrite(pumpINPin, LOW); Serial.printf("水泵状态: 关闭\n"); // 设置电机状态为停止 pumpINRunning = false; } // 当低水位检测到高电平并且进水泵没有运行没有故障,则马上抽水 if ((debouncedLowPinState == HIGH && debouncedHighPinState == LOW) && pumpINRunning == false && !systemFault) { digitalWrite(pumpINPin, HIGH); Serial.printf("水泵状态: 开启\n"); pumpINStartTime = millis(); // 设置电机状态为运行 pumpINRunning = true; } // --- 进水泵超时保护 --- if (pumpINRunning == true) { if (millis() - pumpINStartTime >= PUMP_TIMEOUT_MS) { digitalWrite(pumpINPin, LOW); Serial.printf("进水泵状态: 关闭 (超时 - 系统可能故障!)\n"); pumpINRunning = false; systemFault = true; // 设置系统故障标志 } } // --- 处理喂食电机逻辑 --- // 自动循环定时启动 // 检查Cloud开关是否打开 AND 电机当前未运行 AND 距离上次自动启动已过去设定时间 motorCycleDurationMillis = (unsigned long)motorCloudCycleHours * 3600UL * 1000UL; // 实时更新循环周期,cloud 计数为小时 if (motorCloudControl && !motorRunning && motorCycleDurationMillis > 0 && (millis() - motorCycleStartTime >= motorCycleDurationMillis)) { Serial.println("Motor triggered by automatic cycle."); startMotor(); motorStartTime = millis(); // 记录本次启动时间 motorRunning = true; motorCycleStartTime = millis(); // 重置自动循环计时 } // 电机运行时间到期停止 if (motorRunning && (millis() - motorStartTime >= motorRunDurationMillis)) { Serial.println("Motor run duration finished."); stopMotor(); motorRunning = false; // 如果是通过Cloud开关启动的,当运行时间到期时,Cloud开关状态保持ON // 如果是通过自动循环或外部触发启动的,运行时间到期停止,Cloud开关状态不变 } // --- 处理循环水泵逻辑 --- // 只有当Cloud控制开启并且无故障时,水泵才进入循环模式 if (pumpCloudControl && !systemFault) { // 实时更新泵的ON/OFF时长 pumpOnDurationMillis = (unsigned long)pumpCloudOnSecond * 1000UL; // 从Cloud获取并转换为毫秒 pumpOffDurationMillis = (unsigned long)pumpCloudOffSecond * 1000UL; // 从Cloud获取并转换为毫秒 // 检查当前处于ON还是OFF周期,并判断是否需要切换 if (pumpOnPeriod) { // 当前是ON周期 if (millis() - lastPumpToggleTime >= pumpOnDurationMillis && pumpOnDurationMillis > 0) { Serial.println("Pump ON period finished, switching to OFF."); pumpOnPeriod = false; // 切换到OFF周期 lastPumpToggleTime = millis(); // 记录切换时间 setPumpState(pumpOnPeriod); // 更新水泵引脚状态 (LOW) } } else { // 当前是OFF周期 if (millis() - lastPumpToggleTime >= pumpOffDurationMillis && pumpOffDurationMillis > 0) { Serial.println("Pump OFF period finished, switching to ON."); pumpOnPeriod = true; // 切换到ON周期 lastPumpToggleTime = millis(); // 记录切换时间 setPumpState(pumpOnPeriod); // 更新水泵引脚状态 (HIGH) } } pumpRunning = true; // 只要Cloud开关打开,即使在OFF周期,逻辑上水泵是处于“运行中”循环模式 setPumpState(pumpOnPeriod); // 确保引脚状态与当前周期一致 } else { // 如果Cloud开关关闭,停止水泵循环并关闭水泵 if(pumpRunning) { // 避免重复执行关闭操作 Serial.println("Pump Cloud control turned OFF, stopping pump cycle."); stopPump(); pumpRunning = false; pumpOnPeriod = false; // 确保回到初始状态 } } delay(50); } void startMotor() { digitalWrite(pwm1Pin, HIGH); //逆时针旋转 digitalWrite(pwm2Pin, LOW); Serial.println("Motor started."); } void stopMotor() { digitalWrite(pwm1Pin, LOW); digitalWrite(pwm2Pin, LOW); // 停止电机 Serial.println("Motor stopped."); } void setPumpState(bool state) { digitalWrite(pumpPin, state ? HIGH : LOW); } void stopPump() { setPumpState(false); // 直接关闭水泵 } /* Since PumpCloudControl is READ_WRITE variable, onPumpCloudControlChange() is executed every time a new value is received from IoT Cloud. */ void onPumpCloudControlChange() { Serial.printf("pumpCloudControl changed to: %s\n", pumpCloudControl ? "true" : "false"); if (pumpCloudControl) { // 从Cloud开启水泵,立即开始循环 Serial.println("Starting pump cycle from Cloud."); pumpRunning = true; pumpOnPeriod = true; lastPumpToggleTime = millis(); // 重置泵循环计时 setPumpState(pumpOnPeriod); // 立即打开水泵 } else { // 从Cloud关闭水泵,立即停止水泵和循环 Serial.println("Stopping pump cycle from Cloud."); stopPump(); pumpRunning = false; pumpOnPeriod = false; // 确保回到初始状态 } } /* Since MotorCloudControl is READ_WRITE variable, onMotorCloudControlChange() is executed every time a new value is received from IoT Cloud. */ void onMotorCloudControlChange() { Serial.printf("motorCloudControl changed to: %s\n", motorCloudControl ? "true" : "false"); if (motorCloudControl) { // 从Cloud开启电机,运行25秒 startMotor(); motorStartTime = millis(); motorRunning = true; } else { // 从Cloud关闭电机,立即停止 stopMotor(); motorRunning = false; } } /* Since MotorCloudCycleHours is READ_WRITE variable, onMotorCloudCycleHoursChange() is executed every time a new value is received from IoT Cloud. */ void onMotorCloudCycleHoursChange() { motorCycleStartTime = millis(); } /* Since PumpCloudOffSecond is READ_WRITE variable, onPumpCloudOffSecondChange() is executed every time a new value is received from IoT Cloud. */ void onPumpCloudOffSecondChange() { // Add your code here to act upon PumpCloudOffSecond change } /* Since PumpCloudOnSecond is READ_WRITE variable, onPumpCloudOnSecondChange() is executed every time a new value is received from IoT Cloud. */ void onPumpCloudOnSecondChange() { // Add your code here to act upon PumpCloudOnSecond change } 可以看到上面的代码是 V2.1 版本,因为 V2.0 开始用的第一天,从乌龟槽流到循环水箱的下水管堵住了,导致水没法循环了,所以循环水箱里的水一直减少,加水的泵一直就加,一满桶水很快没了。我赶紧关闭了电源进行清理。 结果没过两天,早上五点多被嗡嗡声吵醒了,我一看,循环水箱没水了,水桶也没水了,导致加水泵一直开着,还不知道干烧了多久。我还在想昨晚桶里水不少,为什么这样,仔细一看,水桶底漏了一个洞。靠,刚烧了固件就连续出现两个意外,促使我完善了代码。 于是我就增加了加水泵保护的代码,持续工作时长超过两分钟自动停止,并报故障,直到系统重启。 下载 Arduino APP,登录,可以看到设备上线了,点击按键控制,因为 Arduino IoT Cloud 对免费版的 Cloud Variables 总数量有限制,所以开关项就这么几个了。 以上所有原始文件在此,仅供参考,有问题自己搜索或问 AI: https://github.com/harry10086/Autofeed

2025/7/24
articleCard.readMore

如何迁移群晖套件到不同的存储空间

前言 群晖之前的套件都安装在一个小硬盘,最近换了个大硬盘,文件可以直接在共享文件夹里修改存储空间就好了。 群晖 DSM 虽然有各种备份,迁移,但套件是没有。怎么才能迁移到新的硬盘,我不想重新安装软件了。 搜了一下,发现有个迁移自动化脚本,使用起来还可以。 下载 项目地址:https://github.com/007revad/Synology_app_mover 实际有用的只有 syno_app_mover.sh 和 syno_app_mover.conf,下载这两个文件就可以了,一个是脚本,一个是配置。 现有备份和恢复模式。 支持 DSM 7。未使用 DSM 6 进行全面测试。 如果备份到 USB 驱动器,分区的文件系统应该是 ext3,ext4,btrfs。 迁移 将下载的两个文件放到群晖的任意文件夹内,syno_app_mover.conf 主要是备份相关的,比如备份目录,剩余空间限制等,我是直接迁移。 启用群晖 SSH,并使用 Xshell 或 PUTTY 连接到 NAS 登录。 # 切换到 root 权限 sudo -i # 进入syno_app_mover.sh所在目录 cd /volume1/scripts # 运行脚本 ./syno_app_mover.sh 选择 1 move,可以看到所有套件和所在分区,按序号选择后迁移到其他盘,按照步骤很容易。 就是有一点不方便,套件得一个一个迁移,没法批量。

2025/7/16
articleCard.readMore

如何用CH32F103做一个Arduino开发板

简介 CH32F103C8T6 和 STM32F103C8T6 基本上是完全兼容的国产版,CH32F103C8T6 开发板淘宝也是一样,就几块钱,于是我买了一块做 Arduino 开发板用。 相关资料不多而且比较古老,我搞了三四天才能用 Arduino IDE 下载。 CH32F103C8T6 规格书:https://www.wch.cn/products/CH32F103.html 其实 ST 原版相关资源更多,开源的支持也更好,毕竟国外用的多。如果没有特别需求还是建议买 ST 开发板。 下载 Bootloader WCH 即沁恒提供了下载工具:https://www.wch.cn/downloads/WCHISPTool_Setup_exe.html,直接下载安装。 CH32F103C8T6 Bootloader 下载地址:https://github.com/rogerclarkmelbourne/STM32duino-bootloader/tree/master/binaries 这里有两个文件夹:bootloader_only_binaries 和 binaries,一定要下载 binaries 文件夹里的 generic_boot20_pc13.bin 文件(pc13 是指开发板上 LED 灯的控制 IO)。 先把开发板上的跳线帽改成 10,即 boot0 连接 1,boot1 连接 0.USB线连接板背面的接口。 打开 WCHISPTool,先选择芯片系列,搜索 USB 设备,添加 Bootloader 文件,然后解除保护,最后点下载。 下载完成后,将跳线帽恢复到 00 位置,连接开发板上面的 USB 接口。 Arduino IDE 下载和驱动安装 打开 Arduino IDE 下载页:https://www.arduino.cc/en/software/,拉到下方下载 Arduino IDE 1.8.19。最好是安装版,绿色版有可能会出问题,并且 1.x 和 2.x 并不冲突。 再下载开发板硬件相关文件:https://github.com/rogerclarkmelbourne/Arduino_STM32,解压后复制到 Arduino IDE 安装目录下 C:\Program Files (x86)\Arduino\hardware\Arduino_STM32, 打开 drivers\win 文件夹,双击 install_drivers.bat 运行,不用管理员身份运行。 这个库介绍写的很清楚,所以我开始用 Arduino IDE 2.3.6 搞了一天是完全错误的: Arduino STM32. Hardware files to support STM32 boards, on Arduino IDE 1.8.x including LeafLabs Maple and other generic STM32F103 boards Arduino IDE 下载 开发板连接 USB 后: Arduino IDE 打开开发板会有 STM32F1 Boards,打开一个 Blink 示例,将 IO 改成 pc13,编译下载测试一下: 总结 WCH 还有一些 RISC-V 内核的 MCU,价格好像贵了一些,也有开源的项目支持:https://github.com/openwch/arduino_core_ch32 Arduino IDE 只支持 1.8.x,别用 2.x。 我用 VS Code + PlatformIO 也没能搞定下载固件,platformio.ini 配置如下: [env:bluepill_f103c8] platform = ststm32 board = bluepill_f103c8 framework = arduino upload_protocol = dfu 设备驱动 Maple drivers 安装会有一些建议使用 zadig:https://github.com/pbatard/libwdi,但我测试不行,会出现名叫 Maple 003 的通用串行设备,并不能被 Arduino IDE 识别。 CH32F103C8T6 开发板资料也不全,淘宝卖家提供的都是牛头不对马嘴,原厂芯片规格书也写的不清不楚,比如 boot0 和 boot1 到底各表示什么,我只能如下猜测: 有说可以使用串口 1 下载程序的,boot 跳线选择 10,我测试是不成功的,无法下载。boot 改成 00 也不行,不知道是不是只有 STM32 才可以。 开发板连个起码的尺寸图也没有,难道只插面包板用?我在国外网站搜到一个: 参考文章:https://www.electroniclinic.com/stm32-bootloader-stm32f103c-programming-using-usb-cable/

2025/6/10
articleCard.readMore

OpenWrt的网络控制插件试用总结

前言 小棉袄每周都有几节网课,一不注意她就在那刷抖音,哔哩哔哩,关键是学校的作业都不完成就去玩,每次都搞到晚上十二点睡觉,早上起点起不来。 没办法,只能针对上课的电脑做下控制,我发现之前 OpenWrt 的上网时间管控是对设备通断网络,并不能特定的网址过滤。 于是我就编译测试了几款插件,发现还是有不少问题。 网址过滤 开源地址:https://github.com/Lienol/openwrt-package/tree/main/luci-app-control-weburl weburl 这个是编译的时候管控里面的一个网址过滤,我打开后发现在关键词里输什么都不好使。 我关闭了软硬件加速,包括卸载了 TurboACC 网络加速的插件,还是无法过滤。 家长控制 开源地址:https://github.com/sirpdboy/luci-app-parentcontrol 后来看到了这个插件:parentcontrol。编译后可以看到家长控制的插件。 第一个页面是时间控制,其实和之前管控里的一样,对某一个设备,在特定的时间关闭或打开网络,这是有效的。 第二个页面是网址过滤,我测试了一下,一样没有效果。 第三个页面是协议过滤,我没这方面的需求,所以没有测了。 应用过滤 后来我搜到了一个收费的插件,当然,基本功能都是免费的,只是针对特征库要求比较多的用户有 VIP 服务:永久会员 39 元。 开源地址:https://github.com/destan19/OpenAppFilter 编译后服务里有个应用过滤插件,用户列表: 家里所有联网设备都有识别,当然不一定准确,比如我的tplink监控,就识别出了经常访问淘宝和抖音。 过滤开关,过滤的网址,包括聊天游戏购物等等,常用的国内网站基本都有,国外的基本没有。 用户配置,如果选择了自动配置那每台设备都会过滤,手动模式就添加需要过滤的设备。 过滤时间设置。 特征库,VIP 收费就收在特征库,免费的库也会更新但比较慢,网址也比较少,目前是三月份更新的,一共过滤 294 个 app。 默认都打开,不关闭加速过滤不了。 我测试后发现可以对单独设备进行过滤一些网址,开发者提供了免费的特征库,如果想要更多更新,可以购买 VIP 服务。 如果想自定义过滤网址,请往下看: 首先在这里下载免费的特征库: 网址:https://www.openappfilter.com/#/feature 解压后有三个文件,两个 bin 文件是特征库,可以看升级说明: 继续解压 bin 文件,可以看到一个 feature.cfg,一个 app_icons,很好理解了。 打开 cfg 文件进行编辑,编辑完成后再打包成 bin 文件,上传: 至于如何添加网址,开发者有说明: https://github.com/destan19/OpenAppFilter/wiki/self%E2%80%90define-feature-file 结论 对于家庭的网络管控,如果是对特定设备进行上网时间的控制,上网时间控制 timecontrol 和家长控制 parentcontrol,都是可用的。 对特定设备进行特定的网址进行过滤,只有应用过滤 openappfilter 好使,当然也不排除还有其他的开关我没设置好,比如防火墙的配置,但作为普通使用者,应用过滤上手即用。 应用过滤 openappfilter 的问题: 过滤的网址,可能还会引起其他的网址无法访问,比如我屏蔽了几个国内视频网站,接着 Google 就无法搜索了。我也没找到解决方法。(有时又正常了) 应用过滤这个插件会影像 Docker,如果应用过滤启动了,那么容器会报 500 错误,只能先启动容器,再开启应用过滤插件。 分享一下我的特征库,添加了宝玩游戏和几个网盘。 夸克网盘分享:https://pan.quark.cn/s/e9e26f3f5881 提取码:n1MD 百度网盘分享:https://pan.baidu.com/s/1qcsD1XVwoLjC4J3vAwBh2A?pwd=hm8g 提取码: hm8g 这里有我编译的 X86 固件,有应用过滤和网络控制插件,当然还有各种科学上网: 夸克网盘分享:https://pan.quark.cn/s/275136450f54 百度网盘分享:https://pan.baidu.com/s/1BTbtZJQvvUXtfwCAknNJdQ?pwd=xg1r 提取码: xg1r

2025/5/27
articleCard.readMore

SONOFF ZBDongle-P(CC2652P) 固件升级方法汇总

看过我之前安装使用 HomeAssistant 文章的都知道,我用的是 SONOFF Zigbee 3.0 USB Dongle Plus,型号 ZBDongle-P(CC2652P) ,固件版本还是 22 年的。现在 Zigbee2MQTT 我看也升级到 2.0 了,coordinator 版本 24 年也更新了一版,那就一起升级了看看。 固件下载地址:https://github.com/Koenkk/Z-Stack-firmware/tree/master/coordinator/Z-Stack_3.x.0/bin 发现 ZBDongle-P 升级方式还挺多的,我一一试了一遍。 SONOFF 在线烧写 首先是 SONOFF 厂家推出的在线升级方式,链接在此: https://dongle.sonoff.tech/sonoff-dongle-quick-flasher/ 插上 ZBDongle-P 后连接设备: 选择设备型号 ZBDongle-P: 选择固件版本: 开始烧写: 设备应该是自动进入了 Bootloader 模式,无需手动按键。 SmartRF Flash Programmer 2 烧写固件 SmartRF Flash Programmer 2 是 Ti 的开发工具,官网下载需要注册,并且要说明是民用产品使用。我分享一个下载链接: SmartRF Flash Programmer 2-1.8.2.zip 下载:https://pan.quark.cn/s/de8cec9b8562 提取码:KDeQ ZBDongle-P 设备进入 Bootloader 模式 首先要使 ZBDongle-P 进入 Bootloader 模式,有两种方法,简单点的就是拆壳后按住 boot 键上电,另一种是通过 Python 脚本自动进入。 Python 脚本 Auto-enter-bootloader.zip 的下载链接:https://pan.quark.cn/s/6ea3924fc4b4 提取码:qJUM 按键进入我就不说了,主要说一下 Python 脚本进入的方法,我用的是 Win 10,首先要安装 Python,然后安装 pyserial,gevent: pip install pyserial pip install gevent 不然会有错误提示: Traceback (most recent call last):   File "E:\ZigBee\zigbee2mqtt\uartlog\uartLog.py", line 10, in <module>     import serial ModuleNotFoundError: No module named 'serial' Traceback (most recent call last):   File "E:\ZigBee\zigbee2mqtt\uartlog\uartLog.py", line 18, in <module>     import gevent ModuleNotFoundError: No module named 'gevent' CMD 运行 uartlog.py 脚本,中间提示要输入 SONOFF Zigbee 3.0 USB Dongle Plus 的串口号: python uartLog.py 运行后自动进入: 再通过串口工具确认 ZBDongle-P 设备已经进入了 Bootloader 模式,发送 HEX 字符 55 55,如果正常会回复:00 CC: 同理,在使用 boot 按键进入的时候,也可以通过此方法确认是否已经进入了 Bootloader 模式。 烧写固件 安装 SmartRF Flash Programmer 2 后打开软件: 点击设备串口处 ①,接着在 ② 处选择 CC2652P,③ 处选要升级的固件,勾选 ④ ⑤ ⑥,点击 ⑦ 开始烧录。 cc2538-bsl 自动烧录固件 cc2538-bsl 是一个开源的 Python 自动烧录固件脚本,支持多款 Ti 芯片,链接: https://github.com/JelmerT/cc2538-bsl 该脚本我仅在 Linux 系统下使用,先安装包和下载脚本: sudo apt update && sudo apt install python3 python3-pip sudo apt install pyserial intelhex mkdir cc2538-bsl cd cc2538-bsl curl -sSL https://github.com/JelmerT/cc2538-bsl/archive/refs/heads/main.tar.gz | tar xz --strip=1 ZBDongle-P 进入 Bootloader 后运行自动升级脚本,固件预先下载到同目录下: cd cc2538_bsl python cc2538_bsl.py -p /dev/ttyUSB0 -f CC1352P2_CC2652P_launchpad_coordinator_20240710.hex -ewv 注意查看 /dev/ttyUSB0 是否是 USB Dongle 的实际端口。根据脚本说明,如果 SONOFF Zigbee 3.0 USB Dongle Plus 需要自动进入 Bootloader 的话,则添加命令行选项 --bootloader-sonoff-usb 来激活引导加载程序。 参考:How to Use SONOFF Dongle Plus on Home Assistant? How to Flash Firmware?

2025/4/10
articleCard.readMore