Hello Hexo /tech/hello-hexo/ 将blog从Typecho迁移到了Hexo。

]]>
tech hexo
认知派生论 /thoughts/cognitive-derived-theory/

拜读了毛主席的实践论和矛盾论,第一次系统地接触了辩证唯物论这一方法论,深感其强大与自然。综合我自己先前的所经所悟,提炼出认知派生这一观点。

从巴甫洛夫的狗铃实验[1],到上世纪50年代费斯汀格的认知失调理论[2],再到1971年津巴多教授主导的斯坦福监狱实验[3],这一系列打破预期的心理学生理学实验,一步一步揭示出,人们心理的作用形式,似乎并非大多数人所认为的那样。实际上,这看似重大的心理学发现,其实早在两个世纪前,便已被马克思,恩格斯等人从社会学角度提出,并完善成为理论。后经列宁,斯大林等人通过实践进行完善。传入国内后,被毛泽东所集大成,结合了中国传统文化的底蕴,发展成为唯物辩证法的毛泽东思想。这一论理的形成,源自于这些人对自己所观察到的社会现象以及自己基于论理所实践的社会运动的归纳总结。而这一论理,又指导了中国共产党建国,扎实地完成国内资本原始积累地奇迹。

辩证唯物论是一套自洽的方法论,它能够有效地指导我们生活实践,从实践中总结论理,再将论理运用于实践的过程。而这一循环的高效运转,正是人类进化出认知的终极意义。

结论

方法论是一种十分有效而重要的工具,它为人们提供了一套范式(习惯),帮助人们更有效地践行“社会实践->认识->论理->社会实践”这一模式。

参考文献

[1] 巴甫洛夫 - 维基百科
[2] 認知失調 - 维基百科
[3] 斯坦福监狱实验 - 维基百科

]]>
thoughts
左宗棠鸡块 /cook/zuozongtang-chiken/ 分享一下改进版炸鸡块做法哦~

材料准备

  • 鸡胸肉
  • 一个鸡蛋
  • 葱末蒜末

预备步骤

  • 鸡肉切小块,加料酒,生抽,淀粉,鸡蛋清,搅匀腌10分钟
  • 鸡块在面粉中打滚

核心步骤

  • 热油炸鸡块至焦黄
  • 植物油蒜末炝锅
  • 加入一勺生抽,一勺多白醋,一把白糖,番茄酱翻一下
  • 加入鸡块,让鸡块上沾上酱汁
  • 撒上葱末

成品图

左宗棠鸡块 2020-02-17

]]>
cook chiken
欧洲旅行支票兑换攻略 /travel/traveler-cheque/

之前去欧洲旅游办签证,由于没有三个月的银行流水,不得已购买了旅行支票作为资金证明。可是到了欧洲才发现旅行支票很难使用,如果不了解行情会被骗收15%-20%的手续费。这篇Blog记录了我们发现的兑换旅行支票的坑和Tips!

[scode type=”info”]经验一: 尽可能不使用旅行支票[/scode]
[scode type=”info”]经验二: 旅支兑换最低手续费在4%左右[/scode]

若不想看经历,可直接调至文末兑换旅行支票的Tips处哦!

我的经历

圣诞假和室友一行四人一起DIY游欧洲,去了意大利和奥地利两个国家,共5个城市。由于英国的银行卡还没有使用到三个月,无法通过打印流水来办签证,我们选择了另一种方法—购买American Express的欧元的旅行支票。殊不知啊,兑换和使用旅行支票真真是一个大坑。

最开始据旅行支票的官网上所说,欧洲很多城市的店铺里都能直接使用旅行支票,照这样来说,旅游时花掉它肯定比回英国后把它换回英镑划算的多(换回英镑的过程需要损失8%)。然鹅,出发前我们通过看他人的游记发现,欧洲现在很多店都无法直接花旅行支票(按我们后来实际旅行情况来看,只在威尼斯的好几家店看到了旅行支票的标识),于是我们决定去了就在机场红色标识的Change那里将它们全数换成欧元。

Change

可到了第一站罗马找到了红色的Change后(如图),却发现700欧元只能给我们590多欧元。这可真的亏的不是一丁半点儿。我对象现场查到了American Express的电话,打过去发现人家现在在意大利没有设点,不过对方建议去银行换,说是可以毫无亏损(注意这也是个坑,,,)。由于有两人已经换了,为了止损,我们决定先不换剩下两人的700欧旅行支票,留着去银行换。

到了第三天,我们去了梵蒂冈那块儿玩,顺便去了附近American Express工作人员推荐的银行,还给中国银行打电话,结果均被告知不接受旅支。这可咋整?

这时刚好发现梵蒂冈周围有一堆change,于是又去问了问报价。其中有一家本来只报590多的,听见我们说另一家给了610多的价,说他们能给我们一个student discount,然后还算了算,报了个640。这下可好,我们开始发现这里面的门道了:其实哪有什么折扣,不过想找个借口吸引你罢了。这些change都是盈利性质的,你把旅支给了他们,他们再通过自己的途径卖给别的地方的American Express,中间可能有一点税收,但只要他们以比扣掉税收低的价格从你这里买下,他就一定能赚(一般还赚不少),不过是多赚点少赚点的区别罢了。而且当地有好几家change,我们主要发现了红色change标识的一家和蓝色的一家。若这家嫌你要求高不接受,那钱就让别家赚了呗。

所以这种时候,我们要想拿到高点的报价,就要掐准人家能接受的度(真的逼太狠了断了人家财路那就没辙了呀),然后通过让他们产生危机意识而提高报价。可以先问个几家,看他们一般会给多少,然后跟他说,别家给我了一个多少的价格。接下来这人可能就会开始打电话给上面的看能给个什么更高的价,叭叭一堆后给你一个略高一点的价格哈哈,你如果不太满意,可以再去找一家问问(不过要注意,如果是同一家的不同店面,要稍微注意点,毕竟他们上面的人可能是一个,说不定就记住你了)。一般来说,大致估估,如果说税可能是百分之二或三,那你起码还是得让人赚个20或30磅(当然你想试试再砍砍也可以,但可能难度会更大)。

于是我们最后两笔分别换的是640欧和645欧(645欧换了一家用类似方法换到的)。

Tips

  • 现在意大利可用旅支消费的地方真不太多,我们去的罗马,佛罗伦萨,威尼斯中,只有威尼斯有几家;
  • 去意大利想兑换欧元旅支,只能在标有change牌子的地方换(当然有的change是不接受旅支的,但很少)。American Express的直接兑换点,至少在意大利应该是没有了,所以没法无损失地换。但意大利的change的确不少,梵蒂冈附近就尤其多;
  • 不要遇见一家,他报个很低的价你就接受了,也不要太信他的话,要知道这很可能是在坑你不清楚内情;
  • 可以先问个两家,了解一下情况。大致估估如果说税可能是百分之二或三,那你起码还是得让人赚个20或30磅,先问问他们的报价,你可以把这个价格说成别家给你的价,去问他们能不能给你高点的价格。当然如果你脸皮薄不好意思胡扯,也可以就只是在这家价格比别家低的情况下把别家价格拿出来激激他们。

总结

以上就是所有关于旅支兑换的一些个人经历和小tips啦,当然这只是结合我们的个人体会总结的一些东西,还是要结合具体情况分析了。出去游玩肯定主要还是想多走走看看感受下,所以在经济条件允许的状况下也不建议大家在这件事上浪费太多时间,只要你自己觉得差不多能接受就行了。最后,还是想说,去意大利玩能不用旅行支票就还是别用了,毕竟真的挺麻烦还处处是坑!

]]>
travel traveler's cheque Europe
一键激活win10 /tech/kms/ 一键激活win10家庭版,专业版,企业版,教育版 φ( ̄∇ ̄o)

方法一(自动安装)

  • 使用此方法请先关闭所有杀毒软件
  • 使用此方法请先关闭所有杀毒软件
  • 使用此方法请先关闭所有杀毒软件

p.s. 如果不放心,请使用 方法二-源码安装



  • 运行刚下载的程序。(请不要修改解压路径)
  • 运行刚下载的程序。(请不要修改解压路径)

  • 点击 更多信息->仍然运行


  • 输入数字进行选择。(可输入数字4获取汉语翻译!!)


  • 耐心等待激活完成~ ::aru:proud::

脚本已发送到桌面kms.bat,如果不需要您可以删除它~

方法二(源码安装)

  • 点击这里下载压缩文件。

  • 解压压缩文件(请务必解压,否则无法运行)
  • 解压压缩文件(请务必解压,否则无法运行)
  • 解压压缩文件(请务必解压,否则无法运行)

  • 双击运行文件夹中的kmskms.bat

压缩文件示例

  • 点击 更多信息->仍然运行


  • 输入数字进行选择。(可输入数字4获取汉语翻译!!)


  • 耐心等待激活完成~ ::aru:proud::

进阶

激活码

您的激活码将保存在C:\Windows\kms.key

运行日志

  • 激活日志 %temp%\kms.log
  • 在本机尝试过的激活码 %temp%\kms.tried_keys
  • kms服务器配置 %temp%\kms.skms
  • ato输出信息 %temp%\kms.ato

恢复未激活状态

  • 进入kms.bat选择3
  • 等待完成卸载!!!

源码

]]>
tech kms win10
部署新型冠状病毒API /tech/coro/ 一分钟快速部署你自己的新型冠状病毒API ୧(๑•̀⌄•́๑)૭

coro-api

新型冠状病毒 实时数据 api
项目Git地址: iotcat/coro-api
项目npm地址: iotcat/coro-api

API示例

获取全部

https://api.yimian.xyz/coro

根据省份

https://api.yimian.xyz/coro?province=山东

根据城市

https://api.yimian.xyz/coro?city=泰安

根据省和城(推荐)

https://api.yimian.xyz/coro?province=山东&city=泰安

快速部署

环境要求

  • nodeJS支持express任意版本
  • git任意版本

下载文件

1
$ git clone https://github.com/iotcat/coro-api.git & cd coro-api

安装依赖

1
$ npm install

启动

1
$ node index.js

访问

1
http://localhost:17676

进阶

GET参数

参数描述示例
province省份(国家)山东
city城市泰安

修改端口

index.js第9行修改默认端口。

禁止跨域

注释掉index.js第13行。

使用pm2守护进程

1
2
$ npm i -g pm2
$ pm2 start index.js --name coro-api -o /var/log/coro/api.out -e /var/log/coro/api.err --watch

Nginx配置

将以下内容加入server{}

1
2
3
location / {
proxy_pass http://127.0.0.1:17676;
}

如果你不是从根目录映射,记得去index.js中第11行app.get('/', f)修改成你的路径。

爬虫配置

爬虫使用coro-py, 请参考其文档。

开源协议

本项目使用MIT协议,允许非署名商业非商业使用。武汉加油!中国加油!!❤

]]>
tech Covid-19 API
香辣牛肉面 /cook/awesome-beef-noodle/ 自研香辣牛肉面做法~

材料准备(两人份)

  • 面条
  • 两个鸡蛋
  • 两根英国大葱切末
  • 两片姜切末
  • 适量牛肉切丁
  • 准备小碗放一个八角,桂皮,白扣,少许白胡椒粒

预备步骤

  • 热锅植物油香油煎鸡蛋
  • 热水焯一下牛肉

核心步骤

  • 热锅植物油香油,放入葱白部分炝锅
  • 加入开水和牛肉粒,加入碗中的调料,焖3分钟
  • 加入一勺生抽,半勺老抽,一勺蚝油
  • 加入适量鸡精和盐调鲜
  • 加适量红油藤椒油调辣
  • 放入面条,煮到熟

后续

  • 面条添至碗中,盖上鸡蛋
  • 加剩下的葱绿末

配图

香辣牛肉面-2020-01-19

]]>
cook beef noodle
英国意大利申根签攻略 /travel/ivisa-checklist/ 在英国留学,圣诞去欧洲旅游,DIY了意大利申根签证。现在游完归来,总结一份申根签攻略。

大致流程

材料类别

常规签证材料

  • Visa申请表
  • 身份证明
  • 居住证明
  • 照片

附加签证材料

  • 工作证明
  • 财产证明
  • 旅行证明
  • 住宿证明
  • 保险证明

材料CheckList

  • visa申请表原件(在线生成后打印)
  • 护照原件+复印件(黑白)
  • BRP原件+复印件(黑白)
  • 一张证件照-与英国签证一致(要求)
  • student letter
  • 旅行支票原件+复印件或三个月银行流水
  • 往返机票(姓名,日期,to&from)
  • 火车票(姓名,日期,to&from)
  • 住宿证明(姓名,日期,地址)
  • 同行者名单
  • 旅行保险证明(姓名,地理范围,保额)
  • 面签预约证明复印件

  • 旅行行程单(方便跟签证官解释)
  • joint travel confirmation letter(如果某个车票或住宿证明上没有你的名字)
  • 买票者的护照签名页复印件(如果某个车票或住宿证明上没有你的名字)

材料说明

visa申请表

  • 在线填写完第一页记得点SAVE, 记下页面右上角的Reference Number ::aru:shy::
  • 下一次登录后点击上方RETRIEVE INCOMPLETE FILLED VAF即可继续填写
  • 填写参考这篇攻略
  • 单面黑白A4打印
  • 打印好不要填写,不要签字,不要贴照片,到现场签证官会告诉你怎么办
  • 不要装订,建议用环形针

Student Letter

  • 去学校FB开
  • 需要有人签名,电子打印的签名不行
  • 抬头需要写Italy Consulate

旅行证明

  • 需要提供付过款的机票和跨城市的火车票
  • 票的底部需要有网站链接
  • 所有票上需要有你的名字
  • 如果某张票没有你的名字,需要票上有名字的人提供签过字的joint travel confirmation letter护照复印件
  • 可参考我们的joint travel confirmation letter
    joint letter

住宿证明

  • Booking Confirmation上需要有paid字样
  • 底部需要有网站链接
  • 所有材料上需要有你的名字
  • 如果没有你的名字,需要有名字的人提供签过字的joint travel confirmation letter护照复印件
  • 建议从Booking等知名网站订购

保险证明

  • 一定要覆盖旅程
  • 保期越长,签证时间越长。。
  • 我们选择的太平保险申根应急签证,供参考

预约证明

  • 到楼下前台拿着预约信挂号
  • 之后预约信就没用了

成果

最后展示一下我拿到的签证 ::aru:cheer::
visa

]]>
travel uk italy visa
今天很开心,在这里留个空 /life/happy/ 先在这里留个空,以后慢慢填~

φ( ̄∇ ̄o)

]]>
life love
Liverpool 学生公寓条件调研 /life/liverpool-accom-inves/ 为了更清晰更直观的选择出明年居住的公寓,本文汇总了网络上对各公寓的评价信息,供决策参考。

[scode type=”green”]大家积极在评论区补充哦,评论推荐使用qq邮箱[/scode]
[scode type=”yellow”]持续更新中…[/scode]
[scode type=”blue”]望大家能够补充更多房源,以便调查[/scode]

所有步行距离以Guild为中心!!

Dover Court (我们的最终选择)

  • 步行距离: 8 min (西北)
  • google地图: Dover Court
  • Official Guide: Dover Court
  • 优点: 距Lidl近,安静,管理好,安全,定期有人清洁,social place好,楼下自习室很安静
  • 缺点: 房间隔音一般,部分房间小,有的地方天花板低
  • 价格: £155.54 pw (Last Year)

Horizon Heights

St Luke’s View

Apollo Court

  • 步行距离: 11 min (西北)
  • 同学反映: 不安静(老雷)

Capital Gate

  • 步行距离: 7 min (西北)

Grand Central

  • 步行距离: 12 min (西)

Philharmonic Court

  • 步行距离: 12 min (南)

The Railyard

  • 步行距离: 9 min (东)

Myrtle Court

  • 步行距离: 9 min (东)

Larch House

  • 步行距离: 7 min (西)

IQ

  • 步行距离: 9 min (西北)
  • 人脉: 老叶,灯泡

The Arch

  • 步行距离: 18 min (西南)

Albert Court

  • 步行距离: 10 min (北)

St Andrews Place

  • 步行距离: 10 min (西南)

The Ascent

  • 步行距离: 13 min (西)

Lee Court

  • 步行距离: 10 min (北)

X1 Liverpool One

  • 步行距离: 18 min (西)

X1 The Edge

  • 步行距离: 12 min (西北)
  • 其它: 快递可以寄到Cambridge Court (梁斌)

Cambridge Court

  • 步行距离: 8 min (南)
  • google地图: Cambridge Court
  • 缺点: 隔音不好,地毯潮湿,条件差

Vita Student Liverpool

  • 步行距离: 21 min (西)

Liberty Park

  • 缺点: 一楼二楼隔音不好
  • 优点: 回字形楼中间有一个小花园(娇娇,欣怡)
]]>
life uk liverpool accomodation investigation
公共开支结算系统 /tech/crown-place-erp/ 在英国留学与4个室友合租,为了更好的控制和监管公共支出,以及维持彼此之间的公共支出平衡,我利用迎新周三天时间设计并开发除了此ERP公共开支计划系统。希望此系统能够便捷接下来一年的生活,减少大家之间的矛盾,促使充满幸福感的公共支出项目持久化OωO

1.功能介绍

  • 统计日均周均流水,让公共支出可视化
  • 用户申报一次公共支出,并提交发票照片留证
  • 监视各成员间支出不均衡程度,计算方差,并可视化显示
  • 对比本周与上周的开支,给出增减比例
  • 当存在一人支出超出均值阈值,并且存在至少一人支出少于均值阈值,则会邮件这两个人产生一次内部交易
  • 当上例中收款人收到款项后,需要到平台确认收到
  • 平台所有历史公共开支及发票可查

2.系统架构

2.1 前端

前端基于一个网上找到的比特币网站平台模板,深度改造实现。值得一提的是,前端使用Ushio-js项目作为安全及日志插件,并得到了Ushio系统做背后支持。

2.2 后端

后端使用php语言编写。提供5个接口,分别提供获取账户事件,获取内部流通信息,获取公共支出信息,获取周报表,操作的功能。

mail系统使用Yimian Mail API快速构建。

2.3 数据库

数据库使用yimian-db/mysql。构建了三个表,分别用于存储流水,公共支出详情,内部流通。

2.4 图片上传

直接引用呓喵酱の图床代码,少量改写。

2.5 用户系统

目前用额外网页简单实现,等待ushio-auth项目完成后统一整合。

3. 外观

没啥可说的,摆图,自己看
imgbed_ed08c497

imgbed_ea04ad82

imgbed_a8b3adb0

]]>
tech uk liverpool crown-place erp system
在家中部署智慧家庭系统 /tech/smart-home/ 基于Home Assisstant搭建综合家庭照明系统,多媒体系统,水流系统的智慧家庭。技术点:天猫精灵交互,LoRa通信,MQTT协议,frp内网穿透,NAS存储,拨动开关电路改造。

结合所学知识,运用前沿技术,造福生活,是我长期以来的不懈追求。为了让家人体验到更加稳定、舒适智能的生活方式,同时也为了巩固憨实先前在学校smartfarm项目和我自己的ushio系统中所积累的技术基础以及架构经验,我决定在出国前,使用20到23整天时间,重构家中老旧的物联网系统。采用分层架构和面向接口、面向测试、面向文档开发原则,以稳定性(Available)可靠性(Reliable)为最优先指标,搭建一个运行目标3年以上的高度模块化的,易于远程操控的,开源的家庭软件硬件智能传感控制系统。

0 架构综述

1 硬件设计

1.1 单片机选材

使用Arduino UNO作为计算单元。一方面,Arduino Uno拥有高可靠性,我之前的智慧窗帘系统使用Arduino Uno作为主控板,平稳运行1年半未出现硬件问题。另一方面,Arduino Uno拥有较大的RAM,无需为了争夺RAM而在单片机编程上煞费苦心。

Arduino UNO的缺陷主要是价格高,但是为保障长期稳定运行,这个成本是必要的。

1.2 WiFi通信模块选材

使用ESP-01作为WiFi的通信模块。主要原因是之前学校课程使用过ESP-01搭建遥控小车,对其工作方式和性能比较了解,降低开发成本。

1.3 LoRa通信模块选材

使用安信可 LORA RA-02 LORA作为LoRa节点和LoRa网关通信模块。原因是surf项目使用的就是这个模块,比较了解它。

1.4 智能音箱选材

智能音箱作为此物联网系统人机交互的最主要界面,发挥着举足轻重的作用。经研究,我使用天猫精灵方糖R作为家用智能音箱。一方面,天猫精灵的性价比摆在那里,非常便宜。第二,与小米开发小爱同学不同,阿里开发天猫精灵的目的是提供平台,它运行开发者以各种形式接入其网络,这一点对我至关重要。

1.5 灯拨动开关

初期设想: 单向控制+复位器。
实际实现:将原有单开改造为双开,一路与继电器串联,另一路与两个pin口相连。

2 通信设计

网络拓扑图

采用WiFi+LoRa两种通信模式。在需要高速高质量通信的场景,如天猫精灵,手机,笔记本,使用WiFi作为通信手段。在WiFi信号不稳定的地方,使用LoRa进行通信。

3 主控系统设计

使用python3开源项目Home Assistant 为基础搭建本项目的主控系统。

4 多媒体系统设计

多媒体主要由天猫精灵提供。此外,通过小米盒子,家庭网盘中的视频,图片,音乐实现了电视与音响上的播放。

5 云端支持系统设计

dns.yimian.xyz提供dns解析服务。

6 NAS存储系统设计

通过挂载从老电脑上拆卸的闲置500G机械硬盘到老IBM服务器,实现存储系统的搭建。
对局域网内,由于家里都是win系统,使用smb作为共享协议实现文件传输,支持局域网内挂载。速度稳定,全网读写10MB/s左右。对外网访问,通过http,frp反代实现,但速度较慢。

]]>
tech Arduino iot smart-home LoRa WiFi ESP8266 MQTT
2019 SURF SmartFarming Proj 架构说明 /tech/smartfarming-surf/ 本文详细介绍了XJTLU大学2019暑期科研SmartFarming Proj物联网架构的设计思路,实施情况以及缺陷反思。

1 背景

1.1 需求

为了探究农业物联网技术的可行性,Alam Mohammed导师希望我们能够提供一个稳定(Available)可靠(Reliable)的物联网系统,以实现对农田的智能监控和管理。这个系统将能够适时地探测土壤以及空气中与植物健康相关的参数,处理并存储这些数据(由Alam提出)。同时,自动化控制的灌溉功能(由Caleb提出)以及一些数据展示方法(由Alam提出的可选需求)也被期待由本系统提供。

1.2 定位

由于是针对农业物联网设计的小型科研项目,项目的目标是对农业物联网的可行性进行探究,愿景是模拟最普遍的小型农业物联网应用场景。因此本架构的定位是适用于大部分具备感知,控制和展示功能的小型农业物联网工程

2 名词解释

  • MQTT: MQTT消息队列遥测传输(Message Queuing Telemetry Transport)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在 TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议[1]。
  • LoRa: LoRa是当前市场上的一种新兴技术,其在1 GHz以下的公共频段中运行,用于远距离低功耗通信[2]。

3 设计目标

3.1 实现功能

本架构功能性需求主要包括土地数据采集,气象数据采集,灌溉系统控制,与无人机小组系统进行交互,网页控制台(可查看实时和历史传感数据,指标数据;能够控制系统)。

3.2 性能指标

  • 通信范围(测试):半径不低于1km
  • 通信范围(生产):半径不低于3km
  • 延时:平均小于1s
  • 超时率:不超过5%
  • 资源占用:节点RAM不超过2k
  • 运行周期:1分 (测试) | 15分 (生产)

4 系统环境

4.1 相关软件及硬件

!!!

节点名称 硬件设施 软件集群
土地节点
Ground Nodes
Arduino Nano Arduino.h
SX1278 LORA模块 SPI.h
LM35DZ 温度传感 LoRa.h
土壤湿度传感 LoRa-Socket.h
四分电磁阀 LoRa-mqtt.h
vector.h
气象站节点
Air Station
Arduino Nano Arduino.h
SX1278 LORA模块 SPI.h
BME280 温度,湿度,大气压强传感 LoRa.h
GY-30 光强传感 LoRa-Socket.h
MQ-135 空气质量传感 LoRa-mqtt.h
MQ-7 一氧化碳传感 vector.h
雨量传感
LoRa 网关
LoRa Gateway
SX1278 Arduino.h
SPI.h
WiFi.h
LoRa.h
LoRa-Socket.h
LoRa-mqtt.h
vector.h
PubSubClient.h
内网控制器/MQTT代理
Controler/MQTT Proxy
树莓派3B - RASPBIAN Python3.7
直流变频水泵 NodeJS
sf-mqtt-proxy@npm
sf-pump@npm
forever@npm
云服务器
Cloud Server
华为云主机 - Centos7.4 Nginx/1.12.2
NodeJS/12.4.0
Redis/3.2.12
sf-mqtt-broker@npm
sf-web-api@npm
forever@npm
数据库
Database
华为云数据库 MySQL 5.7.23
!!!

4.2 数据规模预估

按照生产场景预估,每15分钟产生一组数据集合,一组数据集合约占用253-291字节。按照291计算,每天将新增27.93KB数据。

5 设计思路

5.1 理念

  • 面向文档
  • 面向接口
  • 面向测试

5.2 关键问题

  • 土地节点RAM资源稀缺,只有2K
  • LoRa通信采用433MHz,单信道收发,干扰多
  • 服务器需要采集聚合来自多节点的散列数据
  • 预留与无人机AI小组的交互方法
  • 实时消息向前端浏览器推送

5.3 方案选择

为了优先确保通信以及服务的稳定性可拓展性,我们选取分层模型作为架构的设计模式。整个系统分成多个层级,层级之间具备必要的交互行为。每个层级都独立运行,崩溃时会迅速重启,具备高度的可靠性。

安全上,采取内外网隔离的方法。内网中考虑到部分设备计算资源稀缺,与内网服务器的交互采用不加密的通信模式。内网服务器通过SSL加密的方式与云服务器进行交互。为了确保客户端的资料安全,云服务器API只接受具备SSL加密的HTTP和WebSocket请求。

6 架构设计

6.1 基础介绍

本架构的主要目的是提供一个稳定(Available)可靠(Reliable)的物联网系统,通过采集农田中的实时数据,结合通过无人机采集的图片以及CNN判断的植物健康情况,实现对灌溉系统以及植物健康状况的智能管理。本架构理论上适用于大部分农场环境。测试环境半径2~5km(取决于天线)以内,风力3级以下。本系统通过传感器获取农田数据,通过晶体管电路,继电器等控制灌溉系统,通过网页与API与管理者进行交互。

6.2 系统层级图

Smart Farm 系统分层结构图

此图展示了此架构的抽象层级结构。正如其所指出的,此分层架构可明确为感知层网络层应用层三个横向操作层以及一个纵向错误处理层

其中,感知层又可细化为环境层以及硬件层。环境层中包含植物,土壤,空气,水流等我们要检测和控制的自然物体,硬件层通过传感器、控制器等人造电气设备为系统对自然要素的交互行为(检测,控制)提供了底层技术可行性。当感知层实现对自然信息的交互后,相应的数字信息被传往网络层进行通信。相应的,感知层也会从网络层接受相应的控制信息,并根据这些指令做出相应的控制行为。

网络层分为三层。其中最低一层为预处理层,它的主要任务是对感知层采集的数据进行打包处理,转变成网络流通所适合的形式,如套接字。因此,预处理层需要少量的计算存储资源,比如单片机,EEPROM等。经过预处理层的封装后,数据被传往物理层。基于物理层中的网关、路由器等设备,这些数据包得以被有秩序的分发和传递。通信层中的MQTT协议的应用,使得这些数据包分发的管理更加高效与便利。此外,通信层中QoS服务质量检测体系的实施也使得网络层的性能更加的容错和可靠。

应用层主要负责一些应用层面的服务于业务逻辑,比如数据分析,事件处理等。在应用层的最底端,服务层在长期的运转着。服务层是应用层中最近接网络层的部分,它的主要目的是实时处理从网络层传入的数据,并对相应的请求及错误事件进行快速响应。同时,服务层也负责将传感器采集的数据进行整理分析并传递到数据库层进行存储。为了保证服务的可靠性,服务层的实现程序被注册为系统服务并由专门的守护进程进行守护。与服务层的长期运行不同,业务层则是按需唤起。当界面层有新的请求传入或服务层发生特定的事件时,业务层将会被调用并处理它们。除了一些基础的数据分析外,业务层也有权限向AI层进行分析请求。AI层通过分析从无人机传回的图像数据后,会传回一个判断结果给业务层。根据请求的具体内容,业务层会将图像识别结果,历史传感器数据等进行整理,并传递到界面层。界面层则主要用来提供不同形式的接口,比如HTTP接口和WebSocket接口,以方便客户端调用。

6.3 系统拓扑图

Smart Farm 系统拓扑图

从拓扑结构来看,如上图所示,整个系统物理上可划分为土地节点,气象节点,LoRa网关,内网服务器,云服务器,数据库和用户终端。

从功能机制上看,整个系统包含:传感器模块,LoRa通信模块,LoRa网关模块,MQTT-Proxy代理模块,水泵控制模块,MQTT+数据处理模块,web接口模块,守护进程模块和数据库模块。

土地节点
土地节点部署于不同区域的农田中,用于探测土壤温度,湿度参数,并能够提供对相应位置水流电磁阀的控制。土地节点使用Arduino Nano作为计算单元,使用LoRa作为通信方式连接LoRa网关(和其它节点),使用电池供电。其数量较多,工作环境恶劣,无线通信不稳定,是系统中最大的不确定性来源。

气象节点
气象节点部署于农田特定位置,用于探测空气温度,湿度,大气压,降雨量,光照,NH3浓度,CO浓度等气象参数。气象节点使用Arduino Nano作为计算单元,使用LoRa作为通信方式连接LoRa网关(和土地节点),使用电池或有线供电。其工作环境较为恶劣,无线通信质量一般。

LoRa网关
LoRa网关部署于室内,为扩大有效通信半径,其天线可延伸至室外。LoRa网关通过LoRa连接各土地节点和气象节点,通过WiFi连接内网服务器。LoRa网关能够将通过LoRa传入的socket包转换为mqtt消息并传递给内网服务器,以及将内网服务器传来的mqtt消息转换为socket包通过LoRa发送至指定节点。

内网服务器
内网服务器是一个树莓派3B,它包含三个功能模块:MQTT-Proxy代理模块,水泵控制模块以及守护进程模块。

MQTT-Proxy代理模块能够接收由LoRa网关通过WiFi发送的mqtt消息,对其进行SSL加密并转发至云服务器。同时,MQTT-Proxy代理模块也将接受指定的来自云服务器的mqtt消息,将其解密并转发至LoRa网关。

水泵控制模块通过树莓派的GPIO通过继电器控制水泵的状态。与水泵控制模块直接与云服务器进行mqtt通信,不经过MQTT-Proxy代理。

守护进程模块运行在Linux上,用于监视MQTT-Proxy代理模块和水泵控制模块。当探测到模块停止运行时,守护进程模块会及时重启这些模块,以确保服务的稳定性和连续性。

云服务器
云服务器运行在位于北京的华为云上,包含MQTT+数据处理模块,web接口模块和守护进程模块。

MQTT+数据处理模块包含了层级结构中的Service层和Business层。这个模块通过mqtt与内网进行通信,通过mqtt, redis与web接口模块(和AI模块)进行交互。当收到来自内网的各种散列的数据后,本模块会自动对它们进行聚合,整理成一条一条的数据,存入数据库,并通过redis推送给web接口模块。此外,本模块会定时向各节点发送请求以获取它们的数据,这些请求将被追踪以计算延时。

web接口模块提供一系列的HTTP和WebSocket接口。这些接口可用于获取数据,发送指令,刷新数据以及获取推送消息。

守护进程模块运行在Linux上,用于监视MQTT+数据处理模块和web接口模块。当探测到模块停止运行时,守护进程模块会及时重启这些模块,以确保服务的稳定性和连续性。

7 模块说明

7.1 LoRa通信模块

LoRa通信模块用于在单信道情况下实现稳定可靠的socket通信。本模块包含LoRa-socket和LoRa-mqtt。

LoRa-socket是在LoRa-Arduino的基础上进行了数据包的封装,实现了简单的udp和tcp通信,让传统的LoRa通信更加可靠。通过在数据包的head添加收发ip地址,以及在数据包的最后添加hash校验值,LoRa-socket支持点对点通信和广播通信,并且具有强大的噪音处理能力和数据防篡改能力。
项目地址iotcat/LoRa-socket

LoRa-mqtt是在LoRa-socket基础上对mqtt协议进行的一个简单再现。基于udp和tcp,LoRa-mqtt支持qos为0和1的mqtt通信。
项目地址iotcat/LoRa-mqtt

7.2 MQTT-Proxy代理模块

本模块运行在内网服务器,实现了对内网mqtt的加密转发。
项目地址iotcat/sf-mqtt-proxy

7.3 水泵控制模块

本模块运行在内网服务器,实现了通过GPIO对继电器水泵的控制。
项目地址iotcat/sf-pump

7.4 mqtt+数据处理模块

本模块运行在云服务器,实现了对来自底层mqtt消息的数据聚合,处理和存储。
项目地址iotcat/sf-mqtt-broker

7.5 web接口模块

本模块运行在云服务器,实现了功能性接口的提供。
项目地址iotcat/sf-web-api

8 开发文档

8.1 mqtt主题

8.2 http接口

8.3 websocket接口

9 运行状态

9.1 系统延时

qos

上图展示了土地节点(左),气象节点(右),水泵(下)的延时统计折线图。由图可以看出,土地节点的平均延时在730ms左右,气象节点延时在900ms左右,水泵的延时较低,在45ms左右。

9.2 传感器数据

点击这里查看2019-7-31的气象传感器数据


-------------------------------**Reference List:**

[1] OASIS, (2015,12.10). MQTT Version 3.1.1 Plus Errata 01 [Online]. Available: https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html

[2] Sinha, R.S., Wei, Y. and Hwang, S.H., “A survey on LPWA technology: LoRa and NB-IoT”, in Ict Express, 3(1), pp.14-21, 2017.

]]>
tech Arduino iot LoRa MQTT smart-farming
Arduino中[]=重载导致的String调用问题 /tech/arduino-operator-string-issue/ 最近在物联网开发中使用Arduino搭建LoRa网关和节点,发现在调用String时总遇到一些奇奇怪怪的现象。经过排查,发现是由于其它地方[]=运算符的重载所导致。

为了方便,在开发节点时,我们使用了LoRa-SocketArduinoJSON作为依赖。我们发现这两个依赖分别使用时表现良好,但如果在同一个项目文件中使用,则会导致一些怪异的问题。

情况一

通过指针调用函数时String参数传递异常。代码如下:

1
2
3
inline static void _onReceived(const String& msg, const String& from, const String& to, const String& type){
(*_f)(msg, from, to, type);
};

在这个案例中,我们发现msg等String在此函数中的数值是一切正常的,可是却没有能够成功传递到_f中。经过一系列骚操作,我们得出如下结论:

  • 发现如果将String换成int或其它类型,则参数传递至_f一切正常。有问题的只有String和char类型。
  • 我们尝试过将String转换为其它类型,再转回,但是没有效果。
  • String或char类型全局变量的声明会使单片机崩溃。
  • 当我们将ArduinoJSON依赖删去,String参数的传递则一切正常。

我们从而可以得出,这种怪异现象是由于与ArduinoJSON包的冲突所致。

情况二

在使用ArduinoVector制作String类型Vector时,我们也发现了String类型的不稳定现象。神奇的是,这种现象只出现在String的使用中,其它如int类型运作良好。

这些不稳定现象可以总结如下:

  • 赋值时被截断
  • String值局部乱序
  • String值部分乱码
  • 作为参数传给函数时会失败,读取出来是空(与案例一类似)

综述

通过上述两个案例,我们可以初步总结出,这是由于[]=赋值运算符的重载与String有冲突。只要使用[]=重新定义String,即有可能出现String怪异的问题。

]]>
tech Arduino cpp
随机图片API /tech/rand-pic-api/ 本API基于华为云对象存储,使用华为CDN云加速,全球平均下载速度达10MB/s。API中已收录1100+张二次元图片,20+张Bing壁纸(每日自动抓取),150+张二次元头像,10+张图床上传图片。

[scode type=”red”]本API不承诺永久维护,使用前请务必斟酌使用风险!![/scode]

1 API地址

  • https://api.yimian.xyz/img

2 快速入门

随机二次元图片

随机Bing壁纸

随机二次元头像

随机图床图片

随机1920x1080尺寸二次元图片

3 参数列表

名称描述格式示例
type图片种类moe/wallpaper/head/imgbedtype=moe
size根据图片大小筛选??x??;
*x??;
*x*;
??-??x??;
??-??x??-??;
??-??x*
display=1920x1080;
display=1920x*;
display=1920-1950x230-500;
display=1920-1950x*;
range尺寸误差范围numberrange=100
id根据图片id筛选numberid=15
path根据路径提取图片abs pathpath=wallpaper/img_··mal.jpg
display是否以网页格式展示true/false(default)display=true
R18是否显示18禁图片true/false(default)R18=true

4 参数详解

4.1 type

二次元(默认)

bing每日壁纸

二次元头像

呓喵酱图床

こいぬちゃん

EasyVer人机验证

4.2 display

如果本参数置为true,则会禁用302跳转,直接返回完整图片编码。本方法效率极低,速度很慢,请慎用。

false(默认)

true

4.3 size

使用本参数限制图片尺寸。本参数支持以下格式:

??x??

??x*

\x??*

\x**

??-??x??

??x??-??

??-??x??-??

??-??x*

\x??-??*

4.4 range

本参数规定允许的size的误差,需搭配size使用,默认为0。

对于??型size参数

对于??-??型size参数

对于*型size参数

  • GET/POST /img?size=*x*&range=100
  • 描述: range无效

4.5 id

每一个种类都有自己的id系统,同一种类下不同图片id唯一。

二次元

bing每日壁纸

二次元头像

呓喵酱图床

4.6 path

使用绝对路径直接提取图片,优先级高于type,效率最高

4.7 R18

是否显示18禁图片,默认为false。

5 报错格式

5.1 找不到指定type类型

若找不到指定的type类型,将会自动返回一个moe类型的图片。

5.2 找不到符合条件的图片

返回JSON

1
2
3
{
"err": "错误信息"
}

[scode type=”yellow”]每台设备每天全局调用上限500次!![/scode]

]]>
tech api img random moe
wIoT - 轻松物联 /tech/wiot/ 基于NodeJS搭建的物联网系统,配合D1 MINI单片机,帮助你灰常快速实现物联~

[scode type=”green”]正式开发文档见这里[/scode]

wIoT for NodeJS

适用于NodeJS的wIoT服务器控制组件,轻松物联

先觉条件

  • 拥有烧录好wIoT固件D1 MINI单片机
  • 一台或多台无线WiFi路由器2.4G/5G
  • 局域网内拥有一台装有NodeJS的服务器或电脑 (NodeJS装法非常简单, 请自行Google或百度)
  • 配置好npm

快速开始

单片机接入

  1. 使用MicroUSB, 5V, 或3V pin脚给单片机供电
  2. 用一根导线连接D0脚与3V3脚,持续一秒以上拔出,以重置单片机
  3. 用手机或电脑搜索它的WiFi热点,名称格式wiot-xx:xx:xx:xx:xx:xx
  4. 连接上此热点,密码为1234567890
  5. 用浏览器打开网址http://192.168.0.1,记录网页中的MAC地址,这将用于识别此单片机
  6. 配置你无线路由器的ssid(即wifi名称,注意不能有非ASCII字符,比如汉字)和密码
  7. 配置完成后热点将自动断开,单片机将连接到你的无线路由器

依赖安装

在你的项目文件夹下打开命令行,输入以下指令安装wiot:

1
$ npm install wiot

使用方法

在你的项目文件夹中新建一个app.js文件,输入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var wiot = require('wiot'); //引入wiot依赖包

// 新建一个单片机对象
// 这里使用了两个参数,MAC是单片机的MAC地址,pin中指定需要OUTPUT输出的端口
// 请自行修改MAC地址的值
var MyMCU = new wiot.client({MAC: "xx:xx:xx:xx:xx:xx", pin: {D4: wiot.OUTPUT}});


// 以下代码将实现,板载led亮1秒,灭1秒的循环

// 等待所有单品即准备就绪
wiot.begin([MyMCU], ()=>{ // 第一个参数为要等待的单片机对象数组,第二个参数为要执行的函数
// 设置计时器,每隔2000毫秒, MyMCU的3号pin口将拉高一次电平
setInterval(()=>{
MyMCU.write(wiot.D4, wiot.HIGH);
}, 2000);

// 设置计时器,延时1000毫秒后开始执行大括号中指令
setTimeout(()=>{
// 设置计时器,每隔2000毫秒,MyMCU的3号pin口将拉低一次电平
setInterval(()=>{
MyMCU.write(wiot.D4, wiot.LOW);
}, 2000);
}, 1000);
});

开始执行

在项目文件夹中打开命令行,输入以下指令:

1
node app.js

预期结果

如果一切顺利,你现在应该会发现你的板载led在闪烁了

社区支持

也许你会觉得上述代码难以理解,这是正常的,由于delay功能在JS中难以实现。但是不用担心,这些问题将会由社区中的其它开发者帮你解决。

wIoT在实现基本的单片机控制同时,也提供了丰富的扩展功能。更神奇的是,任何人都可以在wIoT中编写自己的扩展并与全世界共享它们。在这里我们可以使用wIoT官方提供的led扩展轻松实现上例功能!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var wiot = require('wiot'); //引入wiot依赖包

// 新建一个单片机对象
var MyMCU = new wiot.client({MAC: "xx:xx:xx:xx:xx:xx", pin: {D4: wiot.OUTPUT}});

// 新建一个led模块
var led = new wiot.led(MyMCU, wiot.D4);

// 以下代码将实现,板载led亮1秒,灭1秒的循环

// 等待所有单品即准备就绪
wiot.begin([MyMCU], ()=>{

// 调用led模块构建亮1秒灭1秒的动作
led.set([wiot.HIGH, wiot.LOW], [1000, 1000]);
});

进阶设置

wiot.client

参数说明

名称默认值描述
MAC“”单片机的MAC地址
pin{D1: 0, D2: 0, D3: 0, D4: 0, D5: 0, D6: 0, D7: 0, D8: 0}pin脚的模式, 0为INPUT, 1为OUTPUT, 2为INPUT_PULLUP
hinttrue是否显示状态提示
debugfalse是否开启debug模式
ip“default”指定单片机IP, 请在长时间搜索不到IP时尝试此选项
port8848Client的TCP Socket通信端口,默认8848
ip_range“192.168.0”IP搜索字段,请在长时间搜索不到IP时尝试此选项
localIP“127.0.0.1”本机IP
OnlyHTTPfalse是否仅使用HTTP模式连接单片机
errDelayTime2000遇到网络错误时重试间隔时间(毫秒)
okDelayTime30收到网络请求后延时等待时间(毫秒)
resetDelayTime4500向单片机发送重置指令后多久不再发送新消息(毫秒)
noTryMaxTime15000经过此时间单片机仍未响应则重新发送消息(毫秒)
IntervalTime2000监听行为心跳间隔
MaxToReScanTime180000经过此事件单片机无响应则从新扫描IP地址(毫秒)
MinResearchTime5000搜索IP经过一此轮询后间隔时间(毫秒)
IpScanTimeout1IP扫描时的Ping检测超时时间(秒)
pingTimeout2心跳Ping检测的超时时间(秒)
MaxTraceBackTimes8判断连接状态所向前追溯的历史心跳个数

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var MyMCU = new wiot.client({
MAC: "xx:xx:xx:xx:xx:xx",
pin: {
D1: 0,
D2: 0,
D3: 1,
D4: 1,
D5: 0,
D6: 1,
D7: 0,
D8: 0
},
hint: true,
debug: false,
ip: "192.168.0.55",
port: 6666,
ip_range: "192.168.0",
localIP: "127.0.0.1",
errDelayTime: 2000,
okDelayTime: 30,
resetDelayTime: 4500,
noTryMaxTime: 15000,
IntervalTime: 2000,
MaxToReScanTime: 180000,
MinResearchTime: 5000,
IpScanTimeOut: 1,
pingTimeout: 2,
MaxTraceBackTimes: 8
});

方法列表

  • .write(pin: wiot.pin/number, state: iot.state/number): 向指定pin口输出状态指令,状态可以是wiot.HIGH/wiot.LOW或PWM调制(0-255数字)
  • wiot.read(pin: wiot.pin/number): 读取指定pin口状态,数字pin返回wiot.HIGH/wiot.LOW,模拟pin返回0-1024数值

事件绑定

.on(event, handler)

client事件列表

  • begin 开始于单片机正常交互
  • disConnected 与单片机断开连接
  • reConnected 与单片机恢复连接
1
2
3
4
5
6
var MCU = new wiot.client({"MAC": "xx:xx:xx:xx:xx:xx"});

MCU.on('disConnected', function () {
// 当与MCU失联时会执行此处指令
console.log('Disconnected with MCU!!');
});

.pinOn(pin, event, handler)

pin事件列表

  • on pin口电位从低到高
  • off pin口电位从高到低
  • change pin口电位变化
1
2
3
4
5
6
var MCU = new wiot.client({"MAC": "xx:xx:xx:xx:xx:xx"});

MCU.pinOn(wiot.D2, 'on', function () {
// 当MCU的D2电位由低到高时会执行
console.log('D2 from LOW to HIGH!!');
});

API

  • wiot.begin(): 单片机准备完成后开始执行
1
2
3
4
5
6
7
MCU0 = new wiot.client({MAC: "xx:xx:xx:xx:xx:xx", pin: {D4: wiot.OUTPUT}});
MCU1 = new wiot.client({MAC: "xx:xx:xx:xx:xx:ww"});

wiot.begin([MCU0, MCU1], ()=>{
//这里放你要执行的指令
//这些指令将会在MCU0和MCU1准备就绪后开始执行
});
  • wiot.loop(): 循环执行的指令,适合于条件控制语句
1
2
3
4
5
6
7
8
9
10
11
12
13
MCU0 = new wiot.client({MAC: "xx:xx:xx:xx:xx:xx", pin: {D4: wiot.OUTPUT}});
MCU1 = new wiot.client({MAC: "xx:xx:xx:xx:xx:ww"});

// 以下代码将实现: 当MCU0的D5接收到HIGH,MCU1的D4将会输出HIGH
// 当MCU0的D5接收到LOW, MCU1的D4将会输出LOW
// 本函数接受两个参数: 第一个是MCU对象数组, 第二个是参数为MCU对象数组的函数
wiot.loop([MCU0, MCU1], () => {
if(MCU1.read(wiot.D5) == wiot.HIGH){
MCU0.write(wiot.D4, wiot.HIGH);
}else{
MCU0.write(wiot.D4, wiot.LOW);
}
});

注册表

  • wiot.register.set(status1, status2, function): 向注册表中添加一条规则, status可以是值或函数,当status1==status2时会触发function。
    注册表的设计是为了方便协调各扩展模块的使用,详见下文扩展模块
  • wiot.register.set(status, function): 你也可以传入两个函数,其中status的返回值是bool型,变为true时触发function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var myLED = wiot.led(MyMCU, wiot.D4);
var pir = wiot.pir(MyMCU, wiot.D2);

//注册一条规则,当pir探测到人时,myLED亮
wiot.register.set(pir.getStatus, wiot.HIGH, ()=>{
myLED.set(wiot.HIGH);
});

//注册一条规则,当人离开时,myLED灭
wiot.register.set(()=>{
return (wiot.LOW == pir.getStatus);
}, ()=>{
myLED.clear();
});

传感器扩展模块

LED

  • wiot.led(MCU, pin): 声明一个led模块
  • wiot.led.getStatus(): 获取led状态
  • wiot.led.set(status, time = 0, isSmooth = false): 设置led状态,起始状态,中间状态,最终状态,周期
  • wiot.led.breath(period): 设置一个呼吸灯
  • wiot.led.clear(): 重置led
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MCU0 = new wiot.client({MAC: "xx:xx:xx:xx:xx:xx", pin: {D4: wiot.OUTPUT}});

var myLED = wiot.led(MCU0, wiot.D4); //新建一个led对象,使用MCU0上的D4口

/* 如果myLED不亮,则点亮它 */
if(!myLED.getStatus()){
myLED.set(wiot.HIGH);
}

/* 设置一个周期为2秒的呼吸灯 */
myLED.breath(2000);

/* 设置一个亮三秒,灭四秒的led */
myLED.set([wiot.HIGH, wiot.LOW], [3000, 4000]);

/* 设置一个呼1秒吸3秒的呼吸渐变灯 */
myLED.set([wiot.LOW, wiot.HIGH], [1000, 3000], true);

/* 自定义一个先半亮2秒再全亮3秒再熄灭2秒的led灯 */
myLED.set([100, wiot.HIGH, wiot.LOW], [2000, 3000, 2000]);

/* 熄灭led */
myLED.clear();

PIR 红外人体传感器

  • wiot.pir(MCU, pin): 声明一个PIR模块
  • wiot.pir.getStatus(): 获取PIR状态,返回值wiot.HIGH(有人),wiot.LOW(无人)

事件触发器

  • wiot.pir.on(event, handler)

事件列表

  • detected 探测到人
  • undetected 人体移动出探测范围
  • change 状态改变,包括有人到无人和无人到有人
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
MCU0 = new wiot.client({MAC: "xx:xx:xx:xx:xx:xx"});

var myPIR = wiot.pir(MCU0, wiot.D2); //新建一个pir对象,使用MCU0上的D2口

/* 输出pir状态到控制台 */
console.log(myPIR.getStatus());

/* 当探测到人,打印 "Detected People!" 到控制台 */
myPIR.on("detected", ()=>{
console.log("Detected People!");
});

/* 人移动出探测范围,打印 "No People!!" 到控制台 */
myPIR.on("undetected", ()=>{
console.log("No People!!");
});

/* 当状态改变,执行指令 */
myPIR.on("change", ()=>{
/* 你的指令 */
});

IR 红外循迹/障碍传感器

  • wiot.ir(MCU, pin): 声明一个IR模块,pin可以是模拟或数字端口
  • wiot.ir.getStatus(): 获取IR状态,返回值wiot.HIGH(有障碍),wiot.LOW(无障碍),或者0-1024数值(限模拟端口)

事件触发器

  • wiot.ir.on(event, handler)

事件列表

  • detected 探测到障碍
  • undetected 障碍消失
  • change 状态改变
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
MCU0 = new wiot.client({MAC: "xx:xx:xx:xx:xx:xx"});

var myIR = wiot.ir(MCU0, wiot.D2); //新建一个ir对象,使用MCU0上的D2口

/* 输出ir状态到控制台 */
console.log(myIR.getStatus());

/* 当探测到物体,打印 "Detected Object!" 到控制台 */
myIR.on("detected", ()=>{
console.log("Detected Object!");
});

/* 物体移动出探测范围,打印 "No Object!!" 到控制台 */
myIR.on("undetected", ()=>{
console.log("No Object!!");
});

/* 当状态改变,执行指令 */
myIR.on("change", ()=>{
/* 你的指令 */
});

lightSensor 光敏传感器

  • wiot.lightSensor(MCU, pin): 声明一个lightSensor模块, pin可以是模拟或数字端口
  • wiot.lightSensor.getStatus(): 获取lightSensor状态,返回值wiot.HIGH(有光),wiot.LOW(无光),或者0-1024数值(限模拟端口)

事件触发器

  • wiot.light.on(event, handler)

事件列表

  • light 由暗到明
  • dark 由明到暗
  • change 状态改变
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
MCU0 = new wiot.client({MAC: "xx:xx:xx:xx:xx:xx"});

var myLightSensor = wiot.lightSensor(MCU0, wiot.D1); //新建一个pir对象,使用MCU0上的D2口

/* 输出LightSensor状态到控制台 */
console.log(mylightSensor.getStatus());

/* 当由暗到明,打印 "Light!!!" 到控制台 */
myLightSensor.on("light", ()=>{
console.log("Light!");
});

/* 由明到暗,打印 "Dark!!" 到控制台 */
myLightSensor.on("dark", ()=>{
console.log("Dark!!");
});

/* 当状态改变,执行指令 */
myLightSensor.on("change", ()=>{
/* 你的指令 */
});

网络扩展模块

mail 邮件模块

使用本模块向指定邮箱发送邮件。自豪地引用Yimian API构建!

  • wiot.mail(to, from = "wIoT"): 声明一个mail模块,参数收件地址,发件人名称
  • wiot.mail.send(subject, body): 发送邮件,需传入主题,邮件内容
1
2
3
var mail = wiot.mail("i@iotcat.me", "wIoT Test");

mail.send("Test", "Test from wiot!!");

guguji 咕咕机模块

使用本模块向指定咕咕机发送消息。咕咕机是一款便携式私人打印机,详见官网。使用本模块需要在官网提前申请好自己的开发者ak, 详见这里。自豪地引用Yimian API构建!

  • wiot.guguji(ak, userID, memobirdID): 声明一个guguji模块,参数: 开发者ak, 用户id, 咕咕机id
  • wiot.guguji.send(msg): 发送消息,需传入待发送的消息
1
2
3
var gugu = wiot.guguji("9e55121803474371bfa25d20e554b31f", "832598", "b3ee06a8bd9b49e1");

gugu.print("This is from wIoT!!");
]]>
tech nodeJS iot WiFi
中美贸易战-解 /thoughts/trade-war/ 中美贸易战的解不在美国,而是在我们自己身上。

关于谈判,党内争议比较大,但最终很有可能会拒绝做出让步。
当美关税抬升,国内相关产业链将大批转移至台湾及东南亚国家,累计将造成1亿人口的就业问题。与前几次的危机不同,这一次我们不但要提防房市泡沫的激化,也没有那麽多的基建可提供就业。从另一方面看,近几年来,中国的产能过剩问题主要通过出口得以解决,拿着贸易顺差来发展国内经济,以实现不可思议的经济增长。如今特朗普政府征加关税,将使得这一策略不再行得通。

如果在谈判中妥协,中方将丧失好不容易占来的第四次工业革命先机,并经济将会想日本,韩国一样任人摆布。

我认为,在不妥协的前提下,中共有三个破局之法。

  1. 武统台湾
    这个需要看明年台湾大选,是否能找到正当的武统理由。但的确有助于缓解国内社会焦点问题。
  2. 房市改革
    可能性极大,把泡沫危机转变成创造就业机会的资本。
  3. 游戏
    将社会上的过剩劳动力转移进游戏产业空转,以缓解社会矛盾的形成。

为了缓解失业冲击的强度,央行将通过印人民币使人民币贬值来增进出口,吸引他国来补充美资撤离的空缺。

以上。。

]]>
thoughts war
自动发邮件API /tech/mail-api/ 重整自己先前的mail模块,顺便封装了一个API出来,欢迎大家调用~

方法

参数(接受GET和POST)

  • to收信人邮箱地址
  • subject邮件主题
  • body邮件内容(建议使用html格式)
  • from发件人名称

请求地址

1
https://api.yimian.xyz/mail

示例

1
https://api.yimian.xyz/mail/?to=收信邮箱&subject=邮件主题&body=邮件内容&from=发件人名称

[scode type=”yellow”]如遇到GET传递邮件内容错误,请尝试使用POST[/scode]

返回值(json格式)

  • 参数state::true(成功)或false(失败)

[scode type=”dangerous”]每个IP每天请求上限50个[/scode]

]]>
tech api mail
JS中那些惊艳的操作 /tech/js-notes/ 教你如何一步步迷上JS.. ╮(╯▽╰)╭

好嘀~只是一些总结

JS中的那些萌点