553 Commits

Author SHA1 Message Date
kerwincui
bdbfb187ab 大屏展示绑定设备相关数据 2022-08-17 22:21:58 +08:00
kerwincui
e9f0175286 Revert "!41 大屏设备地图实现"
This reverts commit b007f4889c, reversing
changes made to 6bdb2a2b37.
2022-08-15 19:13:53 +08:00
随遇而安
b007f4889c !41 大屏设备地图实现
Merge pull request !41 from 孙阿龙/master
2022-08-15 06:12:04 +00:00
孙阿龙
5c3558f43a 大屏展示地图实现 2022-08-15 11:21:09 +08:00
孙阿龙
5c873b7178 大屏展示设备地图实现 2022-08-15 11:19:24 +08:00
随遇而安
6bdb2a2b37 update README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2022-08-14 17:04:13 +00:00
kerwincui
7f16b3f99c 删除测试数据 2022-08-15 00:22:01 +08:00
随遇而安
7342928e69 update README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2022-08-14 16:18:59 +00:00
kerwincui
15d3a8c049 细节调整 2022-08-14 01:16:48 +08:00
随遇而安
ab24a46604 update README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2022-08-13 05:31:34 +00:00
随遇而安
fbc41863d6 update README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2022-08-13 03:57:45 +00:00
随遇而安
588eeb0101 update README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2022-08-13 03:48:24 +00:00
kerwincui
84aa98595e 首页调整 2022-08-13 00:38:45 +08:00
随遇而安
1c4cc3c9b9 update README.md.
Signed-off-by: 随遇而安 <164770707@qq.com>
2022-08-12 14:54:00 +00:00
kerwincui
6c31985a19 删除工作流 2022-08-12 16:53:04 +08:00
随遇而安
796123fdfd update pipeline-java.yml 2022-08-12 06:42:51 +00:00
孙阿龙
7d4396695f Merge branch 'master' of https://gitee.com/sunalong/wumei-smart 2022-08-12 11:07:12 +08:00
孙阿龙
0934096254 大屏设备总览实现 2022-08-12 11:06:53 +08:00
随遇而安
73e64ed0e0 !40 大屏与主样式冲突问题
Merge pull request !40 from 孙阿龙/master
2022-08-11 07:30:16 +00:00
孙阿龙
ce7bbf8c46 解决大屏样式与主样式冲突问题 2022-08-11 15:18:54 +08:00
随遇而安
b2d94772a6 !39 新增大屏展示
Merge pull request !39 from 孙阿龙/master
2022-08-11 06:22:54 +00:00
孙阿龙
909b874a2c 大屏展示 2022-08-11 14:10:35 +08:00
随遇而安
42fd321016 update README.md. 2022-08-07 15:23:27 +00:00
随遇而安
e3bde6a0b0 update README.md. 2022-08-07 11:56:30 +00:00
随遇而安
e4f2b9c221 !38 调整目录结构 增加使用说明
Merge pull request !38 from CQAdu/master
2022-08-07 11:53:33 +00:00
DuXingJie
e731a9472b 1.调整目录结构
2.增加README
2022-08-07 19:40:35 +08:00
随遇而安
61d5a6cca6 update README.md. 2022-08-07 06:05:23 +00:00
随遇而安
bdd7600262 重命名 sdk/RaspberryPi/更多参考教程.txt 为 sdk/RaspberryPi/参考资料.txt 2022-08-07 03:48:44 +00:00
随遇而安
be39afcba4 update sdk/RaspberryPi/README.md. 2022-08-07 03:45:33 +00:00
随遇而安
697ecacd43 update sdk/RaspberryPi/README.md. 2022-08-07 03:45:19 +00:00
随遇而安
7fd35fc2e6 !37 增加合宙air724 mqtt对接
Merge pull request !37 from CQAdu/master
2022-08-07 02:32:39 +00:00
DuXingJie
7c32115ab7 1.air724上测试可以 2022-08-07 10:08:39 +08:00
DuXingJie
d8aad8c175 Merge branch 'master' of https://gitee.com/iot.adu/wumei-smart 2022-08-07 10:07:53 +08:00
随遇而安
0289a53278 update README.md. 2022-08-06 17:54:12 +00:00
随遇而安
497bfaecf1 update README.md. 2022-08-06 17:39:35 +00:00
随遇而安
4f0474bcc1 update README.md. 2022-08-06 17:32:47 +00:00
随遇而安
1e7293a819 update README.md. 2022-08-06 17:07:16 +00:00
随遇而安
338927673d update README.md. 2022-08-06 17:04:36 +00:00
随遇而安
3b72e1bbc1 update README.md. 2022-08-06 17:03:23 +00:00
随遇而安
a05a7fe5d5 update README.md. 2022-08-06 17:01:49 +00:00
DuXingJie
50d548ec9a 第一次提交合宙mqtt对接物美
代码结构:
WeiMeiComAuth.lua 用于认证
WeiMeiComInteraction.lua 用户交互
WeiMeiApp.lua 应用采集
WuMeiTest.lua 结合合宙mqtt 调用上面函数 完成功能
开发调试环境:vscode 仿真代码
功能:
1.简单认证,加密认证
2.设备信息上传
3.监控主题订阅 监控数据回应
4.属性定时上传
验证完成
1.简单加密
2.设备信息上传
3.监控上传
4.属性定时上传
2022-08-07 00:55:20 +08:00
随遇而安
5879b00f31 update README.md. 2022-08-06 14:38:48 +00:00
随遇而安
a160fc9514 update README.md. 2022-08-06 14:31:06 +00:00
随遇而安
e3316fcd61 update README.md. 2022-08-06 14:24:52 +00:00
随遇而安
f9256a397a update README.md. 2022-08-06 14:23:15 +00:00
kerwincui
a3a3f56d90 设备名称长度限制2-32个字符 2022-08-06 01:37:27 +08:00
kerwincui
6924802b1f 设备编号校验,只能为字母和数字 2022-08-06 01:23:48 +08:00
kerwincui
1947a67827 修复新增设备报错 2022-08-06 00:30:36 +08:00
kerwincui
fb51c2a205 上报设备信息可更新设备关联的用户 2022-08-04 22:24:20 +08:00
kerwincui
f93d95e5cc 配网后增加延时,等待设备返回状态码 2022-08-04 22:23:54 +08:00
kerwincui
129953092e 固件优化 2022-08-04 01:53:25 +08:00
kerwincui
145e02c7ad mqtt报错处理 2022-08-03 22:35:25 +08:00
kerwincui
339e065031 sdk完善 2022-08-03 15:47:44 +08:00
kerwincui
fc753c2898 新版固件改进 2022-08-01 23:28:20 +08:00
kerwincui
5171094988 新增Arduino固件-待完善 2022-08-01 01:31:37 +08:00
kerwincui
90badd1eaf 数据同步完成后,切换选项卡 2022-07-31 13:17:40 +08:00
kerwincui
67f8f66254 首页图表 2022-07-30 14:03:24 +08:00
随遇而安
86e4ce4191 update README.md. 2022-07-30 03:59:58 +00:00
kerwincui
62b14ca053 设备详情页的实时监测 2022-07-30 11:38:43 +08:00
kerwincui
e94a770425 mqtt优化 2022-07-30 00:19:02 +08:00
kerwincui
fd7f186ccc 设备状态、信号、属性、功能实时订阅 2022-07-29 18:34:52 +08:00
kerwincui
c887c9b011 首页改进 2022-07-29 15:32:23 +08:00
kerwincui
d9da66db28 首页调整 2022-07-29 00:31:55 +08:00
kerwincui
844ebaa295 设备信号实时显示 2022-07-28 21:18:05 +08:00
kerwincui
d7cc5bb278 修改标志颜色 2022-07-27 21:29:44 +08:00
kerwincui
7e4e7292ce 自动添加设备默认名称改为产品名称加随机数 2022-07-27 19:48:22 +08:00
kerwincui
51ea00fbfd 名称和图标修改 2022-07-27 17:47:44 +08:00
kerwincui
d3a8bba37a 添加设备二维码 2022-07-27 01:37:03 +08:00
kerwincui
2cd73153d9 修改侧边栏名称 2022-07-27 01:36:31 +08:00
kerwincui
c0a9f1ec80 添加扫码添加设备接口 2022-07-27 01:35:10 +08:00
随遇而安
7ba47dc100 update README.md. 2022-07-26 00:26:33 +00:00
kerwincui
033bb16e24 配网的WIFI名称随机 2022-07-24 08:21:33 +08:00
kerwincui
1ee43b0a87 配网功能简化 2022-07-22 23:26:50 +08:00
kerwincui
a7b9b1e0c4 设备配网改进 2022-07-20 00:19:05 +08:00
kerwincui
bd9beba488 增加配网sdk 2022-07-15 23:20:37 +08:00
kerwincui
58231abdd6 首页增加H5端演示 2022-07-13 01:05:47 +08:00
kerwincui
d7feda4eb3 名称修改 2022-07-12 01:21:58 +08:00
kerwincui
f42d1541fa 添加全选事件处理 2022-07-09 19:14:10 +08:00
kerwincui
52fa0aceaa 数据同步功能延迟到数据加载完成 2022-07-08 23:59:34 +08:00
kerwincui
89595fbf84 分组中添加设备支持分页 2022-07-08 23:49:49 +08:00
随遇而安
faaf0e387a update README.md. 2022-07-08 11:21:19 +00:00
随遇而安
ad036ff911 update README.md. 2022-07-07 06:18:48 +00:00
随遇而安
3a47422f12 update README.md. 2022-07-06 07:19:57 +00:00
kerwincui
f685093eca 更新设备时,发布设备状态,解决设备取消禁用的状态同步问题 2022-07-05 01:42:29 +08:00
kerwincui
37630007c2 设备禁用bug处理 2022-07-05 01:41:29 +08:00
kerwincui
00240fa258 地图添加在线设备输 2022-07-04 18:32:14 +08:00
kerwincui
b3ed268175 设备状态同步改进 2022-07-04 18:23:03 +08:00
kerwincui
c629033690 固件添加设备信息订阅,解决设备状态同步问题 2022-07-04 17:54:36 +08:00
随遇而安
66d5edb668 update README.md. 2022-07-04 07:33:03 +00:00
kerwincui
88dc744d3d 数据同步功能完善 2022-07-04 15:03:43 +08:00
kerwincui
dd0b0942be 设备数据同步和设备的默认定位 2022-07-04 14:49:20 +08:00
kerwincui
ebea98ca99 设备监测统计适配移动端筛选 2022-07-01 22:36:09 +08:00
kerwincui
d33c66d49c 设备监测统计适配移动端筛选 2022-07-01 22:36:09 +08:00
随遇而安
813d3c0254 update LICENSE. 2022-06-30 17:44:58 +00:00
随遇而安
802150e815 update README.md. 2022-06-29 12:23:25 +00:00
kerwincui
df27c1aace 注册时的手机号码保存 2022-06-28 16:36:47 +08:00
kerwincui
9dfc874d6f 注释 2022-06-27 20:45:15 +08:00
随遇而安
267b45581f update vue/.env.staging. 2022-06-27 12:44:37 +00:00
随遇而安
5ef51b9609 update vue/.env.production. 2022-06-27 12:44:15 +00:00
随遇而安
7af1b6711e update vue/.env.development. 2022-06-27 12:43:51 +00:00
kerwincui
a1c9ef99ad 首页地图显示定位方式,设备定时的时间排序 2022-06-27 00:57:50 +08:00
kerwincui
796468d123 前端配置文件的简化和统一 2022-06-23 02:27:06 +08:00
kerwincui
f88bc5fdf3 前端配置文件的简化和统一 2022-06-23 01:42:09 +08:00
随遇而安
966318e5cf update README.md. 2022-06-22 13:33:00 +00:00
随遇而安
305bd9c303 update README.md. 2022-06-22 13:01:23 +00:00
随遇而安
7c93778b94 update README.md. 2022-06-22 13:00:55 +00:00
kerwincui
6275eb4aa5 修复移动端设备列表报错问题 2022-06-22 14:48:08 +08:00
kerwincui
2c617701d4 移动端接口新闻分类列表bug处理 2022-06-22 01:45:09 +08:00
随遇而安
208b230ce0 update README.md. 2022-06-20 08:30:24 +00:00
随遇而安
9a4613eb74 update app/README.md. 2022-06-20 06:12:47 +00:00
随遇而安
d46ef4ad51 update README.md. 2022-06-20 04:55:07 +00:00
随遇而安
780e5477d8 update README.md. 2022-06-20 04:46:15 +00:00
kerwincui
f302f8c8bc 配置文件改善 2022-06-18 23:46:35 +08:00
kerwincui
468ec83bfe 设备名称的bug处理 2022-06-18 23:23:48 +08:00
kerwincui
c2d884e910 设备日志界面优化 2022-06-18 23:15:04 +08:00
kerwincui
381ff00ea4 TDengine测试和优化 2022-06-18 23:14:43 +08:00
kerwincui
452c5a5903 界面优化 2022-06-18 12:28:42 +08:00
kerwincui
3795bc067b 固件版本类型调整为float 2022-06-17 01:45:20 +08:00
kerwincui
5b8f1f39f3 改进esp8266的OTA升级 2022-06-17 01:43:55 +08:00
kerwincui
0e2dd62f9c 树莓派改进ota升级 2022-06-17 01:42:19 +08:00
kerwincui
5fca93c76a esp32固件改进ota升级 2022-06-17 01:42:01 +08:00
kerwincui
1b11ffc4c8 Merge remote-tracking branch 'origin/master' into version1.2 2022-06-17 00:32:43 +08:00
kerwincui
cb338037d2 bug修复 2022-06-17 00:31:48 +08:00
kerwincui
19a6b28cb8 更新sql,增加固件状态 2022-06-16 23:44:22 +08:00
kerwincui
b9f56459d4 固件升级完善 2022-06-16 23:41:30 +08:00
kerwincui
a574bcc5aa 固件升级完善 2022-06-16 23:41:15 +08:00
kerwincui
b2fb001618 设备认证改为认证方式 2022-06-16 16:18:26 +08:00
kerwincui
5ebdb8d05e 设备摘要bug修复 2022-06-16 16:18:09 +08:00
kerwincui
13663aad63 授权界面优化 2022-06-16 01:10:50 +08:00
kerwincui
4f9ac0dca5 设备删除优化 2022-06-16 00:56:42 +08:00
kerwincui
6562746f1e 界面优化 2022-06-16 00:56:29 +08:00
kerwincui
fb75e72a43 细节调整 2022-06-15 23:09:21 +08:00
kerwincui
5cef61cc04 界面优化 2022-06-15 20:50:18 +08:00
kerwincui
e70385bd26 界面优化 2022-06-15 20:36:23 +08:00
kerwincui
f7b6883dff 图片显示优化 2022-06-15 20:30:17 +08:00
kerwincui
82d3f73eeb 分组更新问题 2022-06-15 19:12:23 +08:00
kerwincui
c9434d4be7 授权码改进 2022-06-15 17:08:15 +08:00
kerwincui
422ebf51d8 设备授权码改进 2022-06-15 16:59:42 +08:00
kerwincui
a908ca60a9 设备授权码改进 2022-06-15 16:59:27 +08:00
kerwincui
c883ec828f 后端支持我的分组筛选 2022-06-15 15:27:47 +08:00
kerwincui
b87a1dc6f0 设备分组筛选和细节优化 2022-06-15 15:27:24 +08:00
kerwincui
146d84dcab 设备认证bug处理 2022-06-14 23:45:25 +08:00
kerwincui
e32153c222 细节调整 2022-06-14 21:07:09 +08:00
随遇而安
1c56c7709b update README.md. 2022-06-14 13:03:22 +00:00
随遇而安
d0f48cfd77 update README.md. 2022-06-14 13:01:07 +00:00
随遇而安
fc34514bb3 update README.md. 2022-06-14 12:57:56 +00:00
kerwincui
a640f3f17e 解决设备列表分页问题 2022-06-14 16:48:01 +08:00
kerwincui
d8990643f4 更新日志配置 2022-06-14 16:46:51 +08:00
kerwincui
98cb6da924 更新sql文件 2022-06-14 16:46:28 +08:00
kerwincui
54ca3ab0d2 设备编辑详情报错处理 2022-06-14 16:36:46 +08:00
kerwincui
2b79c5df16 修改配置文件 2022-06-14 15:06:36 +08:00
kerwincui
31867085ea bug处理 2022-06-12 14:59:43 +08:00
kerwincui
6df3279909 Merge remote-tracking branch 'origin/master' into version1.2 2022-06-12 12:50:56 +08:00
kerwincui
550a390703 更新SDK 2022-06-12 12:50:33 +08:00
kerwincui
8b42e52db0 界面调整 2022-06-12 12:13:23 +08:00
kerwincui
2b1b73abff 细节优化 2022-06-12 02:30:02 +08:00
kerwincui
9cd08b74d1 bug处理 2022-06-12 02:06:03 +08:00
随遇而安
8355faf39e update README.md. 2022-06-11 16:14:02 +00:00
随遇而安
228b741ba5 update README.md. 2022-06-11 16:12:24 +00:00
随遇而安
e286465946 update README.md. 2022-06-11 16:12:03 +00:00
随遇而安
2904f0b43d update README.md. 2022-06-11 16:11:37 +00:00
kerwincui
5f675aa796 用户中心调整 2022-06-11 23:26:22 +08:00
kerwincui
eeac05745f 设备日志改进 2022-06-11 16:41:19 +08:00
kerwincui
33a7ba9645 多租户测试调整 2022-06-11 02:32:48 +08:00
kerwincui
8571f899da 设备列表重复问题处理 2022-06-10 21:29:46 +08:00
kerwincui
34b0cd53ea 界面细节调整 2022-06-10 17:42:15 +08:00
kerwincui
fdb2d71d2e 首页地图单击跳转 2022-06-10 16:10:29 +08:00
kerwincui
a8f6dcf882 日志添加租户和用户信息 2022-06-10 15:10:58 +08:00
kerwincui
6f2800cdb8 设备筛选bug处理 2022-06-10 13:52:44 +08:00
kerwincui
72cd1e95fd 多租户的测试调整 2022-06-10 01:34:31 +08:00
kerwincui
b6af649c30 固件添加链接 2022-06-09 17:52:21 +08:00
kerwincui
44ed5a27b3 设备解绑功能完善 2022-06-09 17:09:07 +08:00
kerwincui
0052178b5a 设备界面优化 2022-06-09 14:10:55 +08:00
kerwincui
87f7a6eb86 设备列表bug修复 2022-06-09 13:28:29 +08:00
kerwincui
5660a399b8 授权码导出功能 2022-06-09 00:04:38 +08:00
kerwincui
9dd368c883 完善设备授权 2022-06-08 23:57:40 +08:00
kerwincui
f2b80eaf2f 物模型界面细节调整 2022-06-08 15:10:22 +08:00
kerwincui
f2af26998a 解决物模型修改枚举和数组界面不更新问题 2022-06-08 14:18:21 +08:00
kerwincui
952c2e09c0 细节优化 2022-06-08 12:41:34 +08:00
kerwincui
40d6a49bfc 界面和细节优化 2022-06-08 01:58:26 +08:00
kerwincui
267d60fb1a 设备授权界面调整 2022-06-07 17:56:23 +08:00
kerwincui
70098975d5 设备授权添加状态和筛选 2022-06-07 17:56:08 +08:00
kerwincui
54dc335b02 前端bug处理 2022-06-07 14:23:57 +08:00
kerwincui
d8e35ebfc3 后端TDengine统计分类数量 2022-06-07 14:23:42 +08:00
kerwincui
653eee4e76 设备统计接口 2022-06-06 17:45:36 +08:00
kerwincui
1aa94d3e50 设备统计界面 2022-06-06 17:45:16 +08:00
kerwincui
e6ccf6ee58 分组中添加设备前端 2022-06-06 15:52:48 +08:00
kerwincui
1f7a127499 分组中添加设备 2022-06-06 15:52:32 +08:00
kerwincui
24f2e65f2b 设备修改定位字段名称,添加设备摘要 2022-06-06 13:11:06 +08:00
kerwincui
c9a036043e 完成多租户测试 2022-06-05 17:41:12 +08:00
kerwincui
edf36d3dd1 bug修复 2022-06-05 17:40:54 +08:00
kerwincui
39e7e78b3a 通知公告和新闻咨询完善 2022-06-05 15:57:06 +08:00
kerwincui
12b88d2a93 图片和文件上传优化 2022-06-05 14:51:10 +08:00
kerwincui
ba128edd40 设备添加初始化信息 2022-06-05 13:17:46 +08:00
kerwincui
ed1401ccb8 认证匹配加密认证和简单认证 2022-06-05 13:07:32 +08:00
kerwincui
4632e69def 界面调整 2022-06-05 01:18:23 +08:00
kerwincui
b7b693b6d6 界面优化 2022-06-05 00:18:42 +08:00
kerwincui
6e0becee7c 多租户调整 2022-06-05 00:18:29 +08:00
kerwincui
3fea5132ce 新闻和通知的多租户修改 2022-06-04 19:40:12 +08:00
kerwincui
c3d3d524de 添加信息栏 2022-06-04 17:00:42 +08:00
kerwincui
5423f2fb7f 界面调整 2022-06-04 13:27:49 +08:00
kerwincui
d6c69594b9 登录界面调整 2022-06-04 13:27:02 +08:00
kerwincui
f8eb314bd0 租户只能查看自己的产品、固件、分组和产品下设备以及系统定义的物模型和分类 2022-06-04 13:19:15 +08:00
kerwincui
dad1d22d69 接口 2022-06-04 00:55:52 +08:00
kerwincui
cb2aa585c4 多租户前端调整 2022-06-04 00:52:24 +08:00
kerwincui
46aa17f320 多租户接口调整 2022-06-04 00:51:14 +08:00
kerwincui
4999c2abcb 后端多租户调整 2022-06-03 17:21:51 +08:00
kerwincui
168d987779 前端多租户调整 2022-06-03 17:21:31 +08:00
kerwincui
c9623a5ec6 权限调整 2022-06-03 14:29:50 +08:00
kerwincui
f281ccc1da 界面和权限调整 2022-06-03 12:39:28 +08:00
kerwincui
e36c9849a8 界面调整 2022-06-01 14:37:33 +08:00
kerwincui
b78bf54e21 界面响应式调整 2022-05-31 22:51:59 +08:00
kerwincui
c226922f07 产品和设备编辑界面调整 2022-05-31 17:21:38 +08:00
kerwincui
1cf1a60583 登录和注册界面调整 2022-05-31 16:55:33 +08:00
kerwincui
1f9636ac96 代码优化 2022-05-30 23:07:18 +08:00
kerwincui
c768af6cf9 Arduino开发的SDK更新 2022-05-30 21:39:11 +08:00
kerwincui
1a5c9b8c39 树莓派sdk更新 2022-05-30 21:33:48 +08:00
kerwincui
96715753b0 登录注册界面调整 2022-05-30 17:47:19 +08:00
kerwincui
b6cd6975f8 设备定位优化 2022-05-30 17:01:23 +08:00
kerwincui
aab50e5a78 产品模块完善 2022-05-30 16:08:39 +08:00
kerwincui
ed5b747844 Merge remote-tracking branch 'origin/master' into version1.2 2022-05-30 14:14:49 +08:00
kerwincui
8fb9d5dba9 代码优化 2022-05-30 14:13:52 +08:00
kerwincui
6a3fab6198 docker构建测试失败,emqx安装不了 2022-05-30 03:38:09 +08:00
kerwincui
9b23b5e712 emqx安装失败 2022-05-30 03:31:19 +08:00
kerwincui
ad0cd5dd11 测试dockerfile 2022-05-30 03:27:20 +08:00
kerwincui
d057601c72 测试dockerfile 2022-05-30 03:24:04 +08:00
kerwincui
68fbd6caa0 测试镜像构建 2022-05-30 03:05:02 +08:00
kerwincui
a8f0c72a3f 测试构建 2022-05-30 02:46:24 +08:00
kerwincui
bc4686e598 测试构建 2022-05-30 02:41:35 +08:00
kerwincui
b7a5b69619 测试 2022-05-30 02:33:35 +08:00
kerwincui
4a251eccc4 测试 2022-05-30 02:29:27 +08:00
kerwincui
e944b695b1 构建镜像测试 2022-05-30 02:27:49 +08:00
kerwincui
24a0d67a33 构建镜像测试 2022-05-30 02:25:41 +08:00
随遇而安
89a85a295e update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 18:24:37 2022-05-29 18:24:37 +00:00
kerwincui
9790bff15c 测试构建docker镜像 2022-05-30 02:24:00 +08:00
kerwincui
dd8747f66b 测试镜像构建 2022-05-30 02:10:23 +08:00
随遇而安
e1b0231490 update pipeline-vue.yml for Gitee Go updated_at:2022-05-29 17:37:26 2022-05-29 17:37:27 +00:00
随遇而安
17dbdcb66a update pipeline-java.yml for Gitee Go updated_at:2022-05-29 17:36:56 2022-05-29 17:36:56 +00:00
随遇而安
badd1e414f update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 17:36:29 2022-05-29 17:36:29 +00:00
kerwincui
b6d02938fd 更新流水线配置 2022-05-30 01:34:31 +08:00
随遇而安
8e2e910b5f update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 17:25:50 2022-05-29 17:25:50 +00:00
kerwincui
1337db3dff 测试流水线docker构建镜像 2022-05-30 01:21:05 +08:00
随遇而安
36dab8cd5a update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 17:17:26 2022-05-29 17:17:27 +00:00
随遇而安
cf1fa1a0f1 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 17:13:31 2022-05-29 17:13:31 +00:00
kerwincui
a116e4d44b 测试流水线docker构建镜像 2022-05-30 01:12:17 +08:00
随遇而安
fe122ce31a update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 16:33:22 2022-05-29 16:33:22 +00:00
随遇而安
dc59b81841 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 16:30:44 2022-05-29 16:30:44 +00:00
kerwincui
34571698ee 删除输出目录 2022-05-29 23:54:23 +08:00
随遇而安
ed1a940238 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 15:20:36 2022-05-29 15:20:36 +00:00
随遇而安
51b9389128 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 15:09:50 2022-05-29 15:09:50 +00:00
随遇而安
84573a7283 update pipeline-vue.yml for Gitee Go updated_at:2022-05-29 14:51:32 2022-05-29 14:51:33 +00:00
随遇而安
2883c0c553 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 14:31:24 2022-05-29 14:31:24 +00:00
随遇而安
497f480cad update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 14:17:34 2022-05-29 14:17:35 +00:00
随遇而安
aa9efa0121 update pipeline-vue.yml for Gitee Go updated_at:2022-05-29 14:15:13 2022-05-29 14:15:13 +00:00
随遇而安
d8010fce1e update pipeline-java.yml for Gitee Go updated_at:2022-05-29 14:14:03 2022-05-29 14:14:03 +00:00
随遇而安
076a5c2905 update pipeline-docker.yml for Gitee Go updated_at:2022-05-29 14:01:03 2022-05-29 14:01:03 +00:00
随遇而安
5866624317 add pipeline-docker.yml for Gitee Go created_at:2022-05-29 14:00:25 2022-05-29 14:00:25 +00:00
随遇而安
c9bc4ba0e2 update pipeline-vue.yml for Gitee Go updated_at:2022-05-29 13:47:32 2022-05-29 13:47:32 +00:00
随遇而安
be2fcad8dc update pipeline-java.yml for Gitee Go updated_at:2022-05-29 13:44:57 2022-05-29 13:44:57 +00:00
随遇而安
f06383e46b update .workflow/pipeline-java.yml. 2022-05-29 13:34:25 +00:00
随遇而安
16d3d26a31 重命名 .workflow/pipeline-deploy.yml 为 .workflow/pipeline-java.yml 2022-05-29 13:34:08 +00:00
随遇而安
2e0fd23695 add pipeline-vue.yml for Gitee Go created_at:2022-05-29 13:33:16 2022-05-29 13:33:16 +00:00
随遇而安
0bec7efd5c update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 13:22:32 2022-05-29 13:22:33 +00:00
随遇而安
f3a80259eb update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 13:07:06 2022-05-29 13:07:06 +00:00
随遇而安
d25592232b update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 13:01:53 2022-05-29 13:01:53 +00:00
随遇而安
042761259e update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:50:08 2022-05-29 12:50:08 +00:00
随遇而安
7f524eb48b update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:44:07 2022-05-29 12:44:07 +00:00
随遇而安
bcca79dfc1 update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:39:09 2022-05-29 12:39:09 +00:00
随遇而安
5c40f81e3d update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:34:15 2022-05-29 12:34:15 +00:00
kerwincui
1f54ec3a85 添加构建目录 2022-05-29 20:33:18 +08:00
kerwincui
4429882b60 测试持续集成 2022-05-29 20:15:28 +08:00
随遇而安
00e11e7cb6 update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 12:00:30 2022-05-29 12:00:31 +00:00
随遇而安
2714fc076f update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 11:55:44 2022-05-29 11:55:44 +00:00
随遇而安
d7fc72e45d update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 10:36:29 2022-05-29 10:36:29 +00:00
随遇而安
214a55898c update pipeline-deploy.yml for Gitee Go updated_at:2022-05-29 10:33:26 2022-05-29 10:33:26 +00:00
随遇而安
90b1eb2da0 add pipeline-deploy.yml for Gitee Go created_at:2022-05-29 10:10:48 2022-05-29 10:10:48 +00:00
随遇而安
391a5310e0 update app/README.md. 2022-05-28 18:02:39 +00:00
随遇而安
b339724a25 update README.md. 2022-05-28 15:12:49 +00:00
kerwincui
ea403c0be5 Merge remote-tracking branch 'origin/master' into version1.2 2022-05-25 16:22:39 +08:00
随遇而安
6ed91b856a update README.md. 2022-05-25 02:27:10 +00:00
kerwincui
17ef0b28ef yml文件还原 2022-05-24 19:41:14 +08:00
随遇而安
f793b62627 !36 修复查询日志和监控数据报错问题
Merge pull request !36 from xxmfl/master
2022-05-24 11:39:47 +00:00
wxy001
2788764430 2022年5月24日19:20:31 修复查询设备日志和检测数据报错问题 2022-05-24 19:20:54 +08:00
随遇而安
d31fae1077 !35 增加启动时创建TDengine数据库和日志表
Merge pull request !35 from xxmfl/master
2022-05-24 07:33:31 +00:00
wxy001
14197e7436 2022年5月24日14:34:18 增加初始化时创建数据库功能 2022-05-24 15:28:39 +08:00
wxy001
4dde2bd121 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/init/ApplicationStarted.java
2022-05-24 15:15:52 +08:00
wxy001
6c58e34bec 2022年5月24日14:34:18 增加初始化时创建数据库功能 2022-05-24 14:34:39 +08:00
kerwincui
f07b05eaa1 Merge remote-tracking branch 'origin/master' into version1.2 2022-05-24 13:58:57 +08:00
随遇而安
315f9f8d18 update springboot/wumei-admin/src/main/resources/application-druid.yml. 2022-05-24 05:23:24 +00:00
kerwincui
ca688aa975 备注信息 2022-05-24 13:21:59 +08:00
随遇而安
d25d81967d update README.md. 2022-05-24 04:28:07 +00:00
kerwincui
8a1db44119 提示信息调整 2022-05-24 12:21:00 +08:00
随遇而安
1970b9f007 update README.md. 2022-05-24 04:16:43 +00:00
随遇而安
416935e530 update README.md. 2022-05-24 04:14:00 +00:00
kerwincui
6fc2a47527 还原配置 2022-05-24 10:29:06 +08:00
随遇而安
ba91433bb1 !33 将TDEngine相关配置移到同一个包中
Merge pull request !33 from xxmfl/master
2022-05-24 02:25:27 +00:00
wxy001
f783503b51 2022年5月24日01:05:38 还原ApplicationStart,讲TDengine相关类型和配置归于同一个包 2022-05-24 01:53:27 +08:00
wxy001
5219a0c766 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	springboot/wumei-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java
#	springboot/wumei-iot/src/main/java/com/ruoyi/iot/mqtt/EmqxService.java
#	springboot/wumei-iot/src/main/java/com/ruoyi/iot/tdengine/config/TDengineConfig.java
#	springboot/wumei-iot/src/main/resources/mapper/tdengine/DatabaseMapper.xml
#	springboot/wumei-iot/src/main/resources/mapper/tdengine/TDDeviceLogMapper.xml
2022-05-24 01:18:18 +08:00
wxy001
d032413a56 2022年5月24日01:05:38 还原ApplicationStart,讲TDengine相关类型和配置归于同一个包 2022-05-24 01:06:40 +08:00
随遇而安
8fb4f017e5 !32 增加时序数据库TDengine支持
Merge pull request !32 from xxmfl/master
2022-05-23 03:40:19 +00:00
wxy001
c43459e987 增加时序数据库TDengine存储设备日志和设备监测数据 2022-05-23 00:48:30 +08:00
wxy001
81232fbb04 2022年5月22日23:48:54 增加TDengine存储日志功能,
提供基础的新增和查询功能
2022-05-22 23:50:01 +08:00
kerwincui
34d6a676ea 设备定位方式界面 2022-05-22 01:33:38 +08:00
kerwincui
eb755f7e6f 图表样式调整 2022-05-21 10:45:01 +08:00
kerwincui
177a8fbba8 更新统计的最大数量 2022-05-20 23:54:42 +08:00
kerwincui
28ead10408 监测统计进行日期范围查询 2022-05-20 21:54:42 +08:00
wxy001
44f682c3ba 2022年5月20日19:30:44
1.集成TDengine作为日志和监测数据存储库使用
2.实现简单的新增和查询功能接口
2022-05-20 19:32:14 +08:00
kerwincui
1113ed0c50 统计 2022-05-20 17:55:02 +08:00
kerwincui
6e052c64ab 统计添加时间筛选 2022-05-20 17:54:44 +08:00
kerwincui
a2bbaeb15a 产品和设备图片同步问题处理 2022-05-20 15:54:14 +08:00
kerwincui
317c728f37 解决设备激活时间查询报错问题 2022-05-20 15:20:18 +08:00
kerwincui
767fdebe2c 解决新增、编辑产品和设备的缓存问题 2022-05-20 15:19:46 +08:00
kerwincui
475cb507cf 设备认证bug处理 2022-05-19 17:51:22 +08:00
kerwincui
eaf2eac028 字符串比较错误处理 2022-05-19 17:08:07 +08:00
kerwincui
9412466747 解决加密认证解密失败bug 2022-05-19 16:50:44 +08:00
kerwincui
b98b326674 解决分类新闻列表查询报错 2022-05-19 16:50:13 +08:00
kerwincui
dbc229b1b7 登录页修改文字 2022-05-19 16:49:02 +08:00
kerwincui
8ea10bb813 设备认证统一 2022-05-19 10:56:02 +08:00
kerwincui
7e00d8c0d6 解决多租户导致设备不显示问题 2022-05-18 20:57:05 +08:00
随遇而安
86940906ca update app/README.md. 2022-05-18 12:55:16 +00:00
随遇而安
568e4fbb25 update README.md. 2022-05-17 13:13:16 +00:00
随遇而安
2094e117c1 update README.md. 2022-05-17 07:28:10 +00:00
kerwincui
ccb0da2779 实时监测的bug修复 2022-05-16 18:55:55 +08:00
kerwincui
32f284b3c4 后端启动bug处理 2022-05-16 16:15:31 +08:00
kerwincui
3172f37090 暂时注释授权码的判断 2022-05-15 17:40:22 +08:00
kerwincui
85e3f1f6c8 还原设备实时监测代码,取消注释。 2022-05-15 17:38:35 +08:00
随遇而安
c82e65eea4 update sdk/RaspberryPi/README.md. 2022-05-14 02:58:44 +00:00
随遇而安
a0e8628e8a update sdk/RaspberryPi/README.md. 2022-05-14 02:56:57 +00:00
kerwincui
1b6f4ae53c 文档更新 2022-05-14 10:55:21 +08:00
随遇而安
7f91d1cbaa update sdk/RaspberryPi/README.md. 2022-05-14 02:50:59 +00:00
随遇而安
4018b2b02b update sdk/RaspberryPi/更多参考教程.txt. 2022-05-14 02:50:08 +00:00
kerwincui
ddd3b77182 修改文档 2022-05-14 10:49:08 +08:00
随遇而安
59cc0ad683 update sdk/RaspberryPi/README.md. 2022-05-14 02:46:27 +00:00
kerwincui
6511c32b02 更新markdown 2022-05-14 10:44:45 +08:00
kerwincui
d523a1bf1f 更新markdown文件 2022-05-14 10:39:55 +08:00
随遇而安
b65a19ad7f !31 增加对树莓派SDK的说明文件
Merge pull request !31 from YBZX/master
2022-05-14 02:31:35 +00:00
YBZX
3b75b121c4 增加对树莓派sdk说明文件 2022-05-13 15:59:09 +08:00
kerwincui
747eac3879 emq管理的权限控制调整 2022-05-13 13:43:50 +08:00
随遇而安
881bc88f5c update README.md. 2022-05-13 04:52:09 +00:00
随遇而安
23fe83f85c !30 开发完成的树莓派sdk
Merge pull request !30 from YBZX/master
2022-05-13 03:55:27 +00:00
kerwincui
0a59ea9478 规则引擎界面调整 2022-05-13 00:48:19 +08:00
YBZX
091782d000 添加树莓派sdk 2022-05-13 00:09:05 +08:00
kerwincui
bc147649c7 调整客户端界面 2022-05-12 18:07:39 +08:00
kerwincui
1b345cbbdd 第三方登录页面调整 2022-05-12 17:48:34 +08:00
kerwincui
70173b9b82 首页修改 2022-05-12 17:05:41 +08:00
kerwincui
bd4dd405d2 首页修改 2022-05-12 16:39:38 +08:00
kerwincui
bc694b8a6f 设备列表取消订阅 2022-05-12 14:25:42 +08:00
kerwincui
cd63e1eba4 注册和登录页面修改 2022-05-12 14:25:18 +08:00
kerwincui
303d6dc6b0 添加ios包文件 2022-05-10 14:10:21 +08:00
kerwincui
50e478317c apk更新 2022-05-09 20:14:16 +08:00
随遇而安
72467de6b9 update app/README.md. 2022-05-09 12:13:08 +00:00
随遇而安
0997fb4eed update app/README.md. 2022-05-09 12:12:23 +00:00
随遇而安
a6b2bed0f8 update app/README.md. 2022-05-09 12:11:25 +00:00
随遇而安
118c4814fb update app/README.md. 2022-05-09 12:10:24 +00:00
随遇而安
14f49580b9 update README.md. 2022-05-09 11:47:09 +00:00
kerwincui
1625cd0628 修改图片目录 2022-05-09 16:34:21 +08:00
随遇而安
e18d1de429 update README.md. 2022-05-09 06:35:27 +00:00
随遇而安
24b1fa84e5 update README.md. 2022-05-06 17:58:39 +00:00
随遇而安
7b715ea6e3 update app/README.md. 2022-05-06 17:58:20 +00:00
随遇而安
64c5834901 update README.md. 2022-05-06 17:57:22 +00:00
随遇而安
4217347366 update app/README.md. 2022-05-01 06:43:12 +00:00
随遇而安
cbc180ac9f update app/README.md. 2022-05-01 06:42:50 +00:00
随遇而安
2fad6d3213 重命名 sdk/arduino 为 sdk/Arduino 2022-05-01 06:29:57 +00:00
kerwincui
992e6503fd 删除无用文件 2022-05-01 14:29:25 +08:00
kerwincui
be51ff7e4d 添加目录 2022-05-01 14:27:47 +08:00
kerwincui
025c127707 添加新闻的分类Id查询 2022-04-28 15:23:11 +08:00
随遇而安
b016b32154 update README.md. 2022-04-28 06:37:44 +00:00
随遇而安
c26a7183ae update README.md. 2022-04-27 14:50:56 +00:00
随遇而安
a9e2013138 update README.md. 2022-04-27 14:47:49 +00:00
随遇而安
69e527416c !29 分享设备列表
Merge pull request !29 from woaibjb/master
2022-04-27 14:45:25 +00:00
hp
224d4e1f7e 分享设备列表接口以及sql修改 2022-04-27 18:56:51 +08:00
随遇而安
4a5d29e87e !28 设备分享
Merge pull request !28 from woaibjb/master
2022-04-27 06:16:55 +00:00
hp
cabc91f3bc 分享单个或全部设备功能实现,用户设备列表接口调整,新增别人分享给自己的设备 2022-04-27 13:05:36 +08:00
随遇而安
f5c4042f58 update README.md. 2022-04-27 04:46:27 +00:00
随遇而安
b020aa4561 update README.md. 2022-04-27 04:13:28 +00:00
随遇而安
9236004a26 update README.md. 2022-04-27 04:12:50 +00:00
随遇而安
c5b544771b update README.md. 2022-04-27 04:10:01 +00:00
随遇而安
909bc54249 update README.md. 2022-04-24 15:29:18 +00:00
随遇而安
5d49f84949 update README.md. 2022-04-24 15:27:50 +00:00
随遇而安
08b3607123 !27 qq解绑和重新绑定+ 优化登录管理界面UI
Merge pull request !27 from LemonTree/json_social_login
2022-04-24 15:23:36 +00:00
kerwincui
e86407130c 更新esp8266的SDK 2022-04-24 21:20:27 +08:00
LemonTree
afa550986a [功能]:1、跳转url 放到配置文件里面 2、优化登录管理界面 3、添加qq登录解绑和重新绑定功能 4、个人中心增加 qq绑定信息 展示view 2022-04-24 19:10:35 +08:00
LemonTree
6a5d0169a7 Merge branch 'master' into json_social_login 2022-04-24 18:26:30 +08:00
随遇而安
b6ccc1531e !26 规则引擎页面 ,错误修复
Merge pull request !26 from sxh/master
2022-04-22 08:36:20 +00:00
sxh
17438df5da 规则引擎前端错误修改 2022-04-22 16:33:33 +08:00
随遇而安
08a9aad8ab !25 EMQX模块前端优化
Merge pull request !25 from sxh/master
2022-04-22 06:29:11 +00:00
sxh
7a83ba8984 EMQX模块前端优化 2022-04-22 14:25:04 +08:00
kerwincui
83d3e58bb3 更新sql文件 2022-04-22 01:36:20 +08:00
kerwincui
e9f94c4344 配置文件修改 2022-04-22 01:31:23 +08:00
kerwincui
412bc8e5d0 界面调整 2022-04-22 01:27:20 +08:00
随遇而安
d443ebe790 update README.md. 2022-04-21 05:27:39 +00:00
随遇而安
480d82e422 update README.md. 2022-04-21 05:20:04 +00:00
随遇而安
c3185f324f update README.md. 2022-04-21 05:00:32 +00:00
随遇而安
3015b7d576 update README.md. 2022-04-21 04:58:58 +00:00
随遇而安
5a0b0ae6e2 update README.md. 2022-04-21 04:54:28 +00:00
随遇而安
6a5dc2a6c5 !24 Emqx管理功能完善
Merge pull request !24 from sxh/master
2022-04-21 04:47:03 +00:00
sxh
a236687ecd 新增以下内容1.客户端查看详情和断开连接,2.规则引擎的增删改查,3.资源的增删改查, 2022-04-21 12:43:59 +08:00
sxh
d8435da52c 细节完善 2022-04-21 09:14:21 +08:00
sxh
b0c2ed9b13 增加客户端查看详情和断开连接;规则引擎的增删改查;资源的增删改查 2022-04-21 09:01:01 +08:00
随遇而安
45a497af97 update README.md. 2022-04-20 12:11:55 +00:00
LemonTree
6510c04154 [功能]:1、只在iot使用 去除外层依赖 2022-04-20 19:58:11 +08:00
随遇而安
d8650dcaa1 !21 qq第三方登录开发
Merge pull request !21 from LemonTree/json_social_login
2022-04-20 11:54:32 +00:00
LemonTree
9bdcf7a60d [功能]:1、添加http通用接口forest 2、引入justoauth 处理第三方登录 3、大致完成qq登录代码 4、前端界面修改适配第三方登录逻辑 2022-04-20 18:31:04 +08:00
LemonTree
bb2cdebac3 [功能]:1、添加http通用接口forest 2、引入justoauth 处理第三方登录 3、大致完成qq登录代码 4、前端界面修改适配第三方登录逻辑 2022-04-20 18:30:27 +08:00
随遇而安
28bfe461dc update app/README.md. 2022-04-20 06:40:52 +00:00
kerwincui
5326e8543e bug修复 2022-04-18 14:21:36 +08:00
kerwincui
513b10d939 修改响应式界面 2022-04-17 00:44:48 +08:00
kerwincui
47d702ee76 更新sql 2022-04-17 00:44:10 +08:00
随遇而安
e44a2fe9fd update vue/src/views/iot/device/mqtt-client.vue. 2022-04-16 15:56:32 +00:00
随遇而安
9d2f87496b update vue/vue.config.js. 2022-04-16 15:55:40 +00:00
kerwincui
e2a1b673d6 添加设备重置接口 2022-04-16 23:46:39 +08:00
kerwincui
5152eb5239 登录界面修改 2022-04-16 23:45:53 +08:00
kerwincui
5b277fa130 mqtt完善 2022-04-16 21:31:09 +08:00
kerwincui
a8ab4bf2e2 修复bug 2022-04-16 20:38:37 +08:00
kerwincui
2abaae21b0 界面颜色调整 2022-04-16 16:56:52 +08:00
kerwincui
1a8d39f92d 响应式布局 2022-04-16 16:51:23 +08:00
kerwincui
a0a3987209 修改为响应式布局 2022-04-16 16:42:56 +08:00
随遇而安
63c3f0b6a2 !20 代码规范化
Merge pull request !20 from redamancy_zxp/master
2022-04-16 06:15:26 +00:00
redamancy-qian
36afa809c4 代码规范化 2022-04-16 13:57:26 +08:00
随遇而安
00d9340825 !19 update vue/src/views/iot/group/device-list.vue.
Merge pull request !19 from redamancy_zxp/N/A
2022-04-16 05:29:37 +00:00
redamancy_zxp
4de11c5f96 update vue/src/views/iot/group/device-list.vue.
修改分组添加设备可以看见其他的设备
2022-04-16 05:10:52 +00:00
随遇而安
d95e625297 update README.md. 2022-04-16 04:53:03 +00:00
随遇而安
31a64b6638 !18 多租户修改3
Merge pull request !18 from redamancy_zxp/master
2022-04-16 04:11:34 +00:00
redamancy-qian
f052bda831 zhaothird 2022-04-16 00:48:53 +08:00
随遇而安
4bc2b41a38 !17 update springboot/wumei-iot/src/main/resources/mapper/iot/FirmwareMapper.xml.
Merge pull request !17 from redamancy_zxp/N/A
2022-04-15 03:43:50 +00:00
redamancy_zxp
843492ccba update springboot/wumei-iot/src/main/resources/mapper/iot/FirmwareMapper.xml.
对于租户固件查询处做出修改,保证租户只能查看系统定义的固件和自己创建的固件
2022-04-15 03:39:53 +00:00
随遇而安
81e9ef6373 update sdk/arduino/Arduino-ESP8266/Helper.cpp. 2022-04-14 17:52:32 +00:00
随遇而安
9b1ecf7bf3 update sdk/arduino/Arduino-ESP32/Helper.h. 2022-04-14 17:51:54 +00:00
随遇而安
2651004e1c update sdk/arduino/Arduino-ESP32/Arduino-ESP32.ino. 2022-04-14 17:51:33 +00:00
随遇而安
eb2e3b911f update sdk/arduino/Arduino-ESP32/Helper.cpp. 2022-04-14 17:51:15 +00:00
随遇而安
1d4361b2cf update sdk/arduino/Arduino-ESP32/Helper.cpp. 2022-04-14 17:50:43 +00:00
kerwincui
3ac00be115 添加esp32的支持 2022-04-15 01:38:27 +08:00
随遇而安
2009fe796c !16 多租户修改2
Merge pull request !16 from redamancy_zxp/master
2022-04-14 15:48:02 +00:00
redamancy-qian
1a5df34c4f zhaoSecond 2022-04-14 23:38:46 +08:00
kerwincui
217f2d2773 界面修改 2022-04-14 20:32:44 +08:00
kerwincui
81f1ca8a23 新增App资讯相关接口 2022-04-14 20:32:28 +08:00
kerwincui
6b759faeb9 更新前端配置 2022-04-14 00:49:19 +08:00
kerwincui
3163364da3 后端新增新闻模块 2022-04-14 00:49:19 +08:00
kerwincui
69c4111f02 完善前端 2022-04-14 00:49:19 +08:00
随遇而安
8c50fe34a0 update app/README.md. 2022-04-12 04:04:09 +00:00
随遇而安
cd067db4a7 update app/README.md. 2022-04-12 04:03:19 +00:00
随遇而安
e9790da1a2 !10 授权码页面微调
Merge pull request !10 from kami0314/master
2022-04-11 09:53:42 +00:00
kami
3e65de2837 授权码页面微调 2022-04-11 17:17:20 +08:00
kerwincui
fe2ab6da14 界面调整 2022-04-11 15:10:53 +08:00
随遇而安
7a89e5646f update README.md. 2022-04-11 06:25:26 +00:00
随遇而安
1cddbd94bc !9 新增授权码功能
Merge pull request !9 from kami0314/master
2022-04-11 05:57:33 +00:00
kami
95da9027e6 +f;新增授权码功能
1、产品表添加 is_authorize 是否启用授权码字段;
2、产品授权码功能:基础增删改查、批量生成授权码、绑定设备。
2022-04-11 13:45:27 +08:00
随遇而安
0afd5fab02 update README.md. 2022-04-10 16:27:09 +00:00
随遇而安
68ed6c1c24 update README.md. 2022-04-10 15:52:22 +00:00
随遇而安
8ec1311675 update README.md. 2022-04-10 05:10:58 +00:00
随遇而安
27882d8f23 update README.md. 2022-04-10 05:08:20 +00:00
随遇而安
5623a6dd64 update README.md. 2022-04-10 05:05:19 +00:00
随遇而安
736d269c3b update app/README.md. 2022-04-10 04:41:35 +00:00
随遇而安
5bb5fbf334 update app/README.md. 2022-04-10 04:07:48 +00:00
随遇而安
3bdaeb0c29 update README.md. 2022-04-10 04:06:16 +00:00
随遇而安
4f383d9d77 update README.md. 2022-04-10 04:05:19 +00:00
随遇而安
4e0d01d5ea update app/README.md. 2022-04-09 19:41:33 +00:00
随遇而安
7f4a87722b update README.md. 2022-04-09 19:39:09 +00:00
随遇而安
1e6d392a24 update README.md. 2022-04-09 19:38:05 +00:00
随遇而安
0998dae5d4 update README.md. 2022-04-09 19:36:54 +00:00
随遇而安
446119aa5e update README.md. 2022-04-09 19:35:51 +00:00
随遇而安
182689204d update app/README.md. 2022-04-09 19:32:55 +00:00
随遇而安
8fdfcf1251 update app/README.md. 2022-04-09 19:30:54 +00:00
随遇而安
873fe19f9e update README.md. 2022-04-09 17:54:02 +00:00
kerwincui
462d5d38f8 Revert "!8 APP显示新闻模块"
This reverts commit e28c829613, reversing
changes made to 734f3e7f9d.
2022-04-09 18:53:14 +08:00
随遇而安
e28c829613 !8 APP显示新闻模块
Merge pull request !8 from sxh/master
2022-04-09 07:17:33 +00:00
sxh
af30a8d2cd 新增新闻模块(新闻分类和新闻资讯),采取多对一的模式,前端富文本新增三个依赖(支持图片拖放与缩放) 2022-04-09 14:59:05 +08:00
随遇而安
734f3e7f9d update app/README.md. 2022-04-09 05:52:59 +00:00
随遇而安
e2df0340cf update app/README.md. 2022-04-09 05:48:14 +00:00
随遇而安
e80e04351e update README.md. 2022-04-09 04:55:24 +00:00
kerwincui
cffa1ec5e8 添加apk 2022-04-09 12:49:58 +08:00
随遇而安
e6d67faaf9 update README.md. 2022-04-08 06:46:29 +00:00
kerwincui
8dde2fea92 修复bug 2022-04-08 13:23:30 +08:00
kerwincui
77178e05e8 更新图片上传组件 2022-04-08 11:24:37 +08:00
kerwincui
0521511dfd 暂时注释oauth配置 2022-04-08 11:24:09 +08:00
kerwincui
f646a360ad 添加配置 2022-04-07 01:36:43 +08:00
kerwincui
187e0e2244 修复前端bug 2022-04-07 01:35:59 +08:00
随遇而安
ee56d4ab64 update README.md. 2022-04-06 05:47:39 +00:00
随遇而安
c8207a007b update README.md. 2022-04-06 05:41:37 +00:00
随遇而安
c8a2c752c4 update README.md. 2022-04-04 07:55:11 +00:00
随遇而安
d3a8ec0a1e update README.md. 2022-04-04 07:53:55 +00:00
随遇而安
abf4229bae update README.md. 2022-04-04 07:52:41 +00:00
随遇而安
775da3c22b update README.md. 2022-04-04 07:30:16 +00:00
随遇而安
c1891dc005 update README.md. 2022-04-04 07:04:46 +00:00
随遇而安
9ab21a2d8d update README.md. 2022-04-02 05:24:40 +00:00
随遇而安
0d31f3aef9 update README.md. 2022-03-27 14:20:27 +00:00
随遇而安
02f7bd8969 update README.md. 2022-03-27 05:35:10 +00:00
随遇而安
ba0ee06f63 update README.md. 2022-03-27 05:29:02 +00:00
随遇而安
f649065d6c update README.md. 2022-03-25 12:21:01 +00:00
随遇而安
b91a823c95 update README.md. 2022-03-25 12:06:08 +00:00
随遇而安
00d5bd9bb5 update README.md. 2022-03-25 12:04:58 +00:00
随遇而安
28aa2f32bc update README.md. 2022-03-25 11:59:36 +00:00
随遇而安
5170305537 update vue/src/views/monitor/cache/index.vue. 2022-03-24 09:13:30 +00:00
随遇而安
9d923b3a08 update README.md. 2022-03-23 07:44:57 +00:00
随遇而安
41a6fdb6cd update README.md. 2022-03-23 07:42:41 +00:00
kerwincui
e3c0946553 更新yml配置 2022-03-23 14:42:02 +08:00
kerwincui
977261156b 更新配置 2022-03-23 14:27:22 +08:00
kerwincui
ff37b79f4d 忽略配置 2022-03-23 14:25:56 +08:00
kerwincui
06e7186e13 删除无用的配置 2022-03-23 14:24:19 +08:00
kerwincui
6b5ae7d2f6 更新忽略文件 2022-03-23 14:23:38 +08:00
kerwincui
5852c2ae20 更新配置 2022-03-23 14:18:44 +08:00
kerwincui
5c79a1d839 删除无用的配置文件 2022-03-23 14:17:09 +08:00
随遇而安
ad1a7a0c4c update springboot/wumei-admin/src/main/resources/application.yml. 2022-03-23 05:42:45 +00:00
随遇而安
4bbcb17f9f update springboot/wumei-admin/src/main/resources/application.yml. 2022-03-23 05:05:44 +00:00
随遇而安
be5b940a9f !7 线程池配置
Merge pull request !7 from guanshubiao/master
2022-03-23 04:56:57 +00:00
guanshubiao
600c3a4f0e 线程池的配置 2022-03-23 12:53:46 +08:00
kerwincui
503c0dddd6 update spring boot yml config 2022-03-23 00:20:43 +08:00
随遇而安
f118ab4cc7 !6 mqtt异步客户端+接收主题的业务在线程池处理
Merge pull request !6 from guanshubiao/master
2022-03-22 16:16:40 +00:00
guanshubiao
c3a991cf9c Merge remote-tracking branch 'origin/master'
# Conflicts:
#	springboot/wumei-admin/src/main/resources/application.yml
2022-03-22 23:53:35 +08:00
随遇而安
9793885107 update README.md. 2022-03-22 13:46:29 +00:00
随遇而安
401cb9846d update README.md. 2022-03-22 13:43:52 +00:00
随遇而安
8d8b2d2bb0 update README.md. 2022-03-22 13:43:02 +00:00
随遇而安
4cb4d209cf update README.md. 2022-03-22 13:41:40 +00:00
kerwincui
f34697803f 更新图片 2022-03-22 20:24:19 +08:00
kerwincui
b205f9a922 更新配置文件 2022-03-22 17:32:50 +08:00
随遇而安
bb94b3f003 update springboot/wumei-admin/src/main/resources/application.yml. 2022-03-22 09:28:21 +00:00
kerwincui
3253ef9ab4 docker配置文件更新 2022-03-22 17:03:10 +08:00
kerwincui
7a7e9827ca 更新sql 2022-03-22 17:02:56 +08:00
kerwincui
d5367fc414 修复实时监测报错问题 2022-03-22 17:02:46 +08:00
guanshubiao
940a9eda63 1.添加异步客户端MqttAsyncClient,创建client加锁,确保client唯一
2.添加线程池处理接收主题的业务事件
2022-03-22 16:06:36 +08:00
kerwincui
36f98dc3cb 更新图片 2022-03-22 10:54:04 +08:00
kerwincui
47c94df5cf 更新配置文件 2022-03-21 17:59:15 +08:00
kerwincui
389fb975c3 更新图片 2022-03-21 00:05:47 +08:00
kerwincui
cdb13035ea 添加docker相关文件 2022-03-20 23:57:07 +08:00
kerwincui
d05dd8fc62 添加Docker相关文件 2022-03-20 12:59:49 +08:00
随遇而安
6c7b3549ce update README.md. 2022-03-20 02:14:42 +00:00
随遇而安
7eb45e1590 update vue/.env.staging. 2022-03-19 14:23:56 +00:00
随遇而安
24049b5e54 update vue/.env.production. 2022-03-19 14:23:39 +00:00
随遇而安
8ed517e181 update vue/.env.development. 2022-03-19 14:23:24 +00:00
随遇而安
1f3326f16f update README.md. 2022-03-18 17:58:24 +00:00
随遇而安
9b38ba2fce update README.md. 2022-03-18 17:56:25 +00:00
随遇而安
6a35304341 update README.md. 2022-03-18 17:53:41 +00:00
随遇而安
5a39be4df6 update README.md. 2022-03-18 17:53:10 +00:00
随遇而安
e47b417f4e update README.md. 2022-03-18 17:50:12 +00:00
kerwincui
23edf7e794 接收设备消息的异常处理 2022-03-18 22:02:20 +08:00
kerwincui
1bc1fbb354 修复设备显示和Webhook时间戳问题 2022-03-18 20:28:15 +08:00
随遇而安
d81d612b1c !4 修复mqtt相关bug
Merge pull request !4 from guanshubiao/master
2022-03-18 12:14:31 +00:00
guanshubiao
3cd360e429 修复bug1-mqtt断开重连时,topic没有订阅。
修复bug2-上报property数据,如果数据解析异常,客户端将断开。
2022-03-18 14:45:07 +08:00
随遇而安
9b2c23f51a !3 修改bug
Merge pull request !3 from guanshubiao/master
2022-03-17 16:02:07 +00:00
guanshubiao
7d06b42ea6 修改bug-添加认证失败处理类 导致启用自定义认证会导致oauth授权地址不能访问 2022-03-17 23:33:48 +08:00
随遇而安
ef8e262d08 update README.md. 2022-03-17 06:36:50 +00:00
随遇而安
4eb4b43673 update README.md. 2022-03-17 06:35:13 +00:00
kerwincui
cb2bb065f9 添加图片 2022-03-17 13:26:09 +08:00
kerwincui
78fe543e5b 更新图片 2022-03-17 13:20:59 +08:00
随遇而安
759323313b update README.md. 2022-03-17 05:19:21 +00:00
kerwincui
89ecf1f29a 更新图片 2022-03-17 13:16:36 +08:00
随遇而安
5122c3f932 update README.md. 2022-03-17 05:05:15 +00:00
kerwincui
c28dc9c663 添加图片 2022-03-17 13:04:05 +08:00
随遇而安
012b373289 update README.md. 2022-03-17 04:55:44 +00:00
随遇而安
9c10303c47 update README.md. 2022-03-17 04:52:34 +00:00
随遇而安
50399c2271 update README.md. 2022-03-17 04:47:18 +00:00
随遇而安
1adcfae81d update README.md. 2022-03-17 04:45:14 +00:00
kerwincui
3486bff376 更新图片 2022-03-17 12:29:55 +08:00
422 changed files with 31000 additions and 4059 deletions

View File

@@ -1,13 +0,0 @@
### 该问题是怎么引起的?
### 重现步骤
### 报错信息

View File

@@ -1,14 +0,0 @@
### 相关的Issue
### 原因(目的、解决的问题等)
### 描述(做了什么,变更了什么)
### 测试用例(新增、改动、可能影响的功能)

798
LICENSE
View File

@@ -1,201 +1,661 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
1. Definitions.
Preamble
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
The precise terms and conditions for copying, distribution and
modification follow.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
TERMS AND CONDITIONS
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
0. Definitions.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
"This License" refers to version 3 of the GNU Affero General Public License.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
A "covered work" means either the unmodified Program or a work based
on the Program.
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
1. Source Code.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
END OF TERMS AND CONDITIONS
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
APPENDIX: How to apply the Apache License to your work.
The Corresponding Source for a work in source code form is that
same work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
2. Basic Permissions.
Copyright [yyyy] [name of copyright owner]
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
http://www.apache.org/licenses/LICENSE-2.0
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

120
README.md
View File

@@ -1,88 +1,92 @@
### 一、项目
### 一、项目介
1. 物美智能 [wumei-smart](http://wumei.live/) 是一个简单易用的生活物联网平台。可用于搭建物联网平台以及二次开发和学习。
1. WumeiSmart是一个简单易用的生活物联网平台。可用于搭建物联网平台以及二次开发和学习。适用于智能家居、智慧办公、智慧社区、农业监测、工业控制等领域。[演示地址>>](https://iot.wumei.live/)
2. 设备接入使用EMQX消息服务器认证采用EMQX内置的Http插件对称加密认证。后端采用Spring boot前端采用Vue移动端采用Uniapp数据库采用Mysql、Redis和TDengine设备端支持硬件SDK生成例如ESP32、ESP8266、树莓派等设备模拟器采用Android和WPF框架不仅能模拟硬件设备还可以控制和监测电脑、手机。
2. 项目采用AGPL3协议可用于个人学习和使用商业用途需要赞助项目获得授权。[查看详情 >>](https://wumei.live/doc/pages/sponsor/)
3. 系统架构图
![系统架构图](https://github.com/kerwincui/wumei-smart/blob/master/document/sys.png?raw=true)
4. 使用流程
![使用流程图](https://raw.githubusercontent.com/kerwincui/wumei-smart/master/document/process.png)
3. 项目使用EMQX消息服务器后端采用Spring boot前端采用Vue移动端采用Uniapp数据库采用Mysql、TDengine和Redis设备端支持ESP32、ESP8266、树莓派、合宙等系统架构图如下:
<img src="https://oscimg.oschina.net/oscnet/up-98eefff896394066a60d664b875a3d05d1d.png" max-width="800" />
4. 相关硬件
|[空气检测仪](https://wumei.live/doc/pages/hardware/) | [物联网开发板](https://wumei.live/doc/pages/hardware/) | [Air724开发板](https://wumei.live/doc/pages/hardware/) | [智能开关](https://wumei.live/doc/pages/hardware/) | [查看更多>>](https://wumei.live/doc/pages/hardware/) |
| :----: | :----------: |:----------: |:----------: |:----------: |
| ![](https://oscimg.oschina.net/oscnet/up-ad98a81677e5e68d660866770e3266ca4cf.png) | ![](https://oscimg.oschina.net/oscnet/up-68caf860d0659444e73f42717a03d2fdf72.png) | ![](https://oscimg.oschina.net/oscnet/up-cf690f6058042dccb567ff382ea9432ebab.png) |![](https://oscimg.oschina.net/oscnet/up-c4a7971510127324d6566dd6ea95d571483.jpg) | ![](https://oscimg.oschina.net/oscnet/up-4ce09be3599e3ff7ed91fe182572abd258b.jpg) |
### 二、功能
### 二、系统功能
- 权限管理: 用户管理、部门管理、岗位管理、菜单管理、角色管理、字典和参数管理等
- 系统监控: 操作日志、登录日志、系统日志、在线用户、服务监控、连接池监控、缓存监控等
- 产品管理: 产品、产品物模型、产品分类、产品固件等
- 设备管理: 控制、分组、定时、日志、统计、定位、OTA升级、影子模式、实时监测、加密认证等
- EMQ管理 Mqtt客户端、监听器、消息主题、消息订阅、插件管理
- 硬件 SDK 支持WIFI和MQTT连接、物模型响应、实时监测、定时上报监测数据、AES加密、NTP时间等
- 产品管理: 产品、产品物模型、产品分类、产品固件、设备授权码
- 设备管理: 设备控制、设备分组、设备定时、设备日志、监测统计、设备定位、设备分享、设备禁用、OTA升级、实时状态、影子模式、实时监测、加密认证等
- EMQ管理 Mqtt客户端、监听器、消息主题、消息订阅、插件管理、规则引擎、资源
- 硬件 SDK 支持WIFI和MQTT连接、物模型响应、实时监测、定时上报数据、AES加密、NTP时间、AP配网
- 物模型管理: 属性(设备状态和监测数据),功能(执行特定任务),事件(设备主动上报给云端)
- 其他功能多租户、统计、新闻资讯、通知公告、支持TDengine时序数据库
- 开发中功能设备告警、场景联动、云云对接智能音箱、第三方登录、短信登录、APP界面自定义、视频流处理等
### 三、开发中功能
- 设备分享、设备告警、场景联动进度50%
- 智能音箱、多租户、APP界面自定义进度40%
- 时序数据库、分布式集群部署、Granfa监控进度30%
- 视频流处理进度0%
- 桌面端模拟器/监控进度5%
- 安卓端模拟器/监控进度0%
- App和小程序正在开发中......
### 、技术栈
### 、技术栈
* 服务端
- 相关技术Spring boot、MyBatis、Spring Security、Jwt、Mysql、Redis、TDengine、EMQX、Mqtt等
- 开发工具IDEA
* Web端
- 相关技术ES6、Vue、Vuex、Vue-router、Vue-cli、Axios、Element-ui等
- 开发工具Visual Studio Code
* 移动端(android / ios / 微信小程序)
- 相关技术uniapp、smartconfig
* 移动端(Android / Ios / 微信小程序 / H5
- 相关技术uniapp、[uView](https://www.uviewui.com/)、[uChart](https://www.ucharts.cn/)
- 开发工具HBuilder
* 硬件端
- 相关技术: ESP-IDF、Arduino、FreeRTOS等
- 开发工具Visual Studio Code 和 Arduino
* 安卓端模拟器/监控
- 相关技术android
- 开发工具Android Studio
* 电脑端模拟器/监控
- 相关技术WPF
- 开发工具Visual Studio
### 五、硬件接入具体参考文档项目提供了示例SDK使用ESP8266芯片基于Arduino开发
1. 设备认证
* 加密认证(推荐)
* 简单认证
* EMQX支持的其他认证方式
2. 设备交互
* 发布物模型、设备信息、时钟同步相关Mqtt主题
* 订阅物模型、设备升级、时钟同步相关Mqtt主题
### 六、项目目录
&nbsp;&nbsp;&nbsp;&nbsp; spring-boot ---------------------------------------------------- 后端<br/>
&nbsp;&nbsp;&nbsp;&nbsp; vue ------------------------------------------------------------- 前端<br />
&nbsp;&nbsp;&nbsp;&nbsp; docker ---------------------------------------------------------- docker部署文件<br />
&nbsp;&nbsp;&nbsp;&nbsp; sdk ------------------------------------------------------------- 硬件SDK<br />
&nbsp;&nbsp;&nbsp;&nbsp; download ------------------------------------------------------- 工具下载<br />
- 相关技术: ESP-IDF、Arduino、FreeRTOS、Python、Lua
- 开发工具Visual Studio Code 和 Arduino
### 七、相关文档
##### 权限管理基于ruoyi-vue系统Mqtt消息服务器基于EMQX4.0开源版SDK示例使用ESP8266 Core For Arduino开发
* [项目文档(编写中...)](http://wumei.live/kerwincui/document/wiki/)
### 四、项目目录
&nbsp;&nbsp;&nbsp;&nbsp; spring-boot --------------- 后端<br/>
&nbsp;&nbsp;&nbsp;&nbsp; vue ----------------------- 前端<br />
&nbsp;&nbsp;&nbsp;&nbsp; docker -------------------- docker部署文件<br />
&nbsp;&nbsp;&nbsp;&nbsp; sdk ----------------------- 硬件SDK,已集成多种设备<br />
&nbsp;&nbsp;&nbsp;&nbsp; app ----------------------- 移动端打包文件
### 五、相关文档
##### 权限管理基于ruoyi-vue系统Mqtt消息服务器基于EMQX4.0开源版
* [项目文档](https://wumei.live/doc/)
* [物美智能官网](http://wumei.live/)
* [权限管理系统ruoyi-vue](https://gitee.com/y_project/RuoYi-Vue)
* [若依权限管理系统ruoyi-vue](https://gitee.com/y_project/RuoYi-Vue)
* [Mqtt消息服务器EMQX4.0](https://github.com/emqx/emqx)
* [ESP8266 Core For Arduino](https://github.com/esp8266/Arduino)
* [uCharts高性能跨平台图表库](https://www.ucharts.cn)
* [TDengine时序数据库](https://www.taosdata.com/?zh)
### 、其他
* 互助交流群:1073236354
* [演示地址>>](https://iot.wumei.live/)
### 、其他
1. QQ交流群&#x1F680;946029159 &#x1F680;1073236354
2. 项目贡献者
- [小驿物联](https://gitee.com/iot-xiaoyi)、 [Guanshubiao](https://gitee.com/guanshubiao)、[CrazyDull](https://gitee.com/crazyDull)、 [Kami0314](https://github.com/kami0314)、 [YBZX](https://github.com/YBZX)、 [CQAdu](https://gitee.com/iot.adu)、[孙阿龙](https://gitee.com/sunalong)
- [SXH](https://gitee.com/sixiaohu)、 [Redamancy_zxp](https://gitee.com/redamancy-zxp)、 [LEE](https://gitee.com/yueming188)、 [LemonTree](https://gitee.com/fishhunterplus)、 [Tang](https://gitee.com/mexiaotang)、 [Tang](https://gitee.com/mexiaotang)、 [xxmfl](https://gitee.com/xxmfl)
### 九、界面图片
* web端
### 七、部分图片
![](https://oscimg.oschina.net/oscnet/up-972dea7b54eca705dcc8bf2fe0680b12c09.png)
![](https://oscimg.oschina.net/oscnet/up-6d89f1558797a9becf07c20f92c1407a13a.png)
<table>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-a0c864679be6c4f9bb5547244aeb19657b4.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-9cc3bc5abe8dd95cb3924e5f7b6864a0342.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-ec8c6251884d81f234487d3e25d459ce302.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-e5e7ef5027723051e97d6861d4296c08da5.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-3ae8cef86db794ff37d9186e83b12b88958.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-e20900a12e3781467d05163665ca04645fa.png"/></td>
</tr>
</table>

47
app/README.md Normal file
View File

@@ -0,0 +1,47 @@
<br />
* 项目可用于个人学习;商业使用请赞助该项目,获得授权;
* 赞助后还提供了小程序、APP源码。[详情](https://wumei.live/doc/pages/sponsor/)
#### 移动端介绍
|安卓/Android|苹果/IOS|微信小程序| 网页/H5|Vue2.0
| :---: | :---: | :---: | :---: |:---: |
| √ | √| √ | √ | √ |
1. 项目使用uniapp开发适配小程序、安卓、苹果和H5其他平台未测试。
2. UI框架使用uView2.0
3. 组件使用easycom模式只要组件安装在项目的components目录下或uni_modules目录下并符合components/组件名称/组件名称.vue目录结构。就可以不用引用、注册直接在页面中使用。
4. 开发工具为Hbuilder3.3版本,版本不易过低。
###### 项目结构
```
├─apis // 接口管理
│ ├─modules // api模块化目录
│ │ └─device.js // 设备接口地址
│ ├─http.api.js // 接口定义文件
│ └─http.interceptor // 拦截器
├─common // 公共文件
│ ├─config // 环境配置 (设置baseurl等)
│ ├─extend // 扩展原型方法
│ ├─filters // 全局过滤器
│ └─tools // 全局公共方法
├─components // 项目组件库,组件放置这里,其他页面可直接使用
│ ├─cl-test // easycom测试组件
│ └─cl-icon // iconfont图标组件
├─pages // 页面目录
│ ├─public // 公共页面
│ └─tarbar // 底部导航栏页面
├─static // 图片目录
├─store // vuex
│ ├─$u.mixin // store全局混入方法
│ └─index // vuex 组件全局状态管理
├─uni_modules // 插件市场插件目录
│ └─uview-ui // uview-ui
```
<br /><br />

BIN
app/wumei.apk Normal file

Binary file not shown.

BIN
app/wumei.ipa Normal file

Binary file not shown.

61
docker/Dockerfile Normal file
View File

@@ -0,0 +1,61 @@
FROM openjdk:8u322-jre-slim-buster
ENV VERSION 1.1
ENV AUTHOR kerwincui
ENV INFO wumei smart open source living iot platform
ENV SERVERS nginx:1.14.2, redis-server:5.0.14, emqx:4.0, openjdk:8u322-jre-slim-buster
# mysql环境变量
ENV DB_HOST localhost
ENV DB_NAME wumei
ENV DB_USER root
ENV DB_PASSWORD admin
RUN apt-get update && \
# 安装网络工具和设置时区
apt-get install wget -y --no-install-recommends && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
# 更换国内源
wget http://qiniu.xiwen.online/Debian10.list && \
mv Debian10.list /etc/apt/sources.list && \
apt update && apt upgrade -y && \
# 安装压缩工具
apt install zip -y && \
# 安装nginx和redis
apt-get install nginx -y --no-install-recommends && \
apt-get install redis-server -y --no-install-recommends && \
# 安装 emqx
apt update && apt install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common && \
curl -fsSL https://repos.emqx.io/gpg.pub | apt-key add - && \
add-apt-repository \
"deb [arch=amd64] https://repos.emqx.io/emqx-ce/deb/ubuntu/ \
./bionic \
stable" && \
apt update && \
apt install emqx=4.0.0 -y --no-install-recommends && \
# 修改redis配置
sed -i "s/# requirepass foobared/requirepass wumei-smart/g" /etc/redis/redis.conf && \
sed -i "s/bind 127.0.0.1/# bind 127.0.0.1/g" /etc/redis/redis.conf
# 复制emqx和Nginx的配置文件
COPY ./emqx4.0/emqx.conf /etc/emqx/emqx.conf
COPY ./emqx4.0/emqx_auth_http.conf /etc/emqx/plugins/emqx_auth_http.conf
COPY ./emqx4.0/emqx_web_hook.conf /etc/emqx/plugins/emqx_web_hook.conf
COPY ./emqx4.0/loaded_plugins /var/lib/emqx/loaded_plugins
COPY ./nginx.conf /etc/nginx/nginx.conf
# 拷贝前后端压缩文件到容器,容器内解压后删除
COPY ./wumei-smart.tar /var/
RUN cd /var && tar -xvf wumei-smart.tar && rm wumei-smart.tar
# 启动脚本
COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
# 映射端口
EXPOSE 80 1883 8083

48
docker/description.txt Normal file
View File

@@ -0,0 +1,48 @@
# 服务启动
service nginx start
service redis-server start
service mysql start
emqx start
java -jar /var/wumei-smart/app.jar
# 镜像构建
docker build -t wumei-smart:1.0 .
# 复制文件到容器
docker cp wumei-smart/* container:/var/wumei-smart/
# 镜像导出导入
docker export container| docker import - kerwincui/wumei-smart:1.0
# 镜像推送
阿里云镜像registry.cn-chengdu.aliyuncs.com/kerwincui/wumei-smart:1.0
docker tag wumei-smart kerwincui/wumei-smart:1.0
docker push kerwinci/wumei-smart:1.0
# 容器运行
docker run \
--name wumei-smart \
--env DB_HOST=wumei.live:3306 \
--env DB_NAME=wumei-smart \
--env DB_USER=root \
--env DB_PASSWORD=wumei-smart \
--publish 80:80 \
--publish 1883:1883 \
--publish 8083:8083 \
--volume /var/wumei-smart/java/uploadPath:/var/wumei-smart/java/uploadPath \
--restart unless-stopped \
--detach \
kerwincui/wumei-smart:1.1
--publish 18083:18083 \
--publish 8084:8084 \
--publish 8883:8883 \
--publish 8081:8081 \
--publish 6379:6379 \
--publish 8080:8080 \
--volume /var/wumei-smart/java/logs:/var/wumei-smart/java/logs \
--volume /var/wumei-smart/nginx/nginx.conf:/etc/nginx/nginx.conf \
--volume /var/wumei-smart/nginx/error.log:/var/log/nginx/error.log \
--volume /var/wumei-smart/redis/redis.conf:/etc/redis/redis.conf \
--volume /var/wumei-smart/redis/redis-server.log:/var/log/redis/redis-server.log \
--volume /var/wumei-smart/emqx/emqx.conf:/etc/emqx/emqx.conf \
--volume /var/wumei-smart/emqx/log:/var/log/emqx \

View File

@@ -0,0 +1,32 @@
#!/bin/bash
# start service
startTime=$(date "+%Y-%m-%d %H:%M:%S")
echo $startTime : wumei-smart is starting, please waiting ...
# 提取jar包配置文件
cd /var/wumei-smart/java
unzip app.jar BOOT-INF/classes/application-druid.yml
# 修改mysql配置
sed -i "s/{DB_HOST}/$DB_HOST/g" BOOT-INF/classes/application-druid.yml
sed -i "s/{DB_NAME}/$DB_NAME/g" BOOT-INF/classes/application-druid.yml
sed -i "s/{DB_USER}/$DB_USER/g" BOOT-INF/classes/application-druid.yml
sed -i "s/{DB_PASSWORD}/$DB_PASSWORD/g" BOOT-INF/classes/application-druid.yml
# 配置文件写入jar包并删除提取的配置
zip app.jar BOOT-INF/classes/application-druid.yml
rm -rf BOOT-INF
service nginx start
service redis-server start
emqx start
java -jar /var/wumei-smart/java/app.jar
while true
do
time=$(date "+%Y-%m-%d %H:%M:%S")
echo $time : wumei-smart is running...
sleep 3600
done

2061
docker/emqx4.0/emqx.conf Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
##--------------------------------------------------------------------
## HTTP Auth/ACL Plugin
##--------------------------------------------------------------------
##------------------------------------------------------------------------------
## SSL options
## Path to the file containing PEM-encoded CA certificates. The CA certificates
## are used during server authentication and when building the client certificate chain.
##
## Value: File
## auth.http.ssl.cacertfile = /etc/emqx/certs/ca.pem
## The path to a file containing the client's certificate.
##
## Value: File
## auth.http.ssl.certfile = /etc/emqx/certs/client-cert.pem
## Path to a file containing the client's private PEM-encoded key.
##
## Value: File
## auth.http.ssl.keyfile = /etc/emqx/certs/client-key.pem
##--------------------------------------------------------------------
## HTTP Request Headers
##
## Example: auth.http.header.Accept-Encoding = *
##
## Value: String
## auth.http.header.Accept = */*
##--------------------------------------------------------------------
## Authentication request.
##
## Variables:
## - %u: username
## - %c: clientid
## - %a: ipaddress
## - %r: protocol
## - %P: password
## - %p: sockport of server accepted
## - %C: common name of client TLS cert
## - %d: subject of client TLS cert
##
## Value: URL
auth.http.auth_req = http://localhost:8080/iot/tool/mqtt/auth
## Value: post | get | put
auth.http.auth_req.method = post
## Value: Params
auth.http.auth_req.params = clientid=%c,username=%u,password=%P
##--------------------------------------------------------------------
## Superuser request.
##
## Variables:
## - %u: username
## - %c: clientid
## - %a: ipaddress
## - %r: protocol
## - %P: password
## - %p: sockport of server accepted
## - %C: common name of client TLS cert
## - %d: subject of client TLS cert
##
## Value: URL
# auth.http.super_req = http://127.0.0.1:8991/mqtt/superuser
## Value: post | get | put
# auth.http.super_req.method = post
## Value: Params
# auth.http.super_req.params = clientid=%c,username=%u
##--------------------------------------------------------------------
## ACL request.
##
## Variables:
## - %A: 1 | 2, 1 = sub, 2 = pub
## - %u: username
## - %c: clientid
## - %a: ipaddress
## - %r: protocol
## - %m: mountpoint
## - %t: topic
##
## Value: URL
# auth.http.acl_req = http://127.0.0.1:8991/mqtt/acl
## Value: post | get | put
# auth.http.acl_req.method = get
## Value: Params
# auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t,mountpoint=%m
##------------------------------------------------------------------------------
## Http Reqeust options
## Time-out time for the http request, 0 is never timeout.
##
## Value: Duration
## -h: hour, e.g. '2h' for 2 hours
## -m: minute, e.g. '5m' for 5 minutes
## -s: second, e.g. '30s' for 30 seconds
##
## Default: 0
## auth.http.request.timeout = 0
## Connection time-out time, used during the initial request
## when the client is connecting to the server
##
## Value: Duration
##
## Default is same with the timeout option
## auth.http.request.connect_timout = 0
## Re-send http reuqest times
##
## Value: integer
##
## Default: 3
auth.http.request.retry_times = 3
## The interval for re-sending the http request
##
## Value: Duration
##
## Default: 1s
auth.http.request.retry_interval = 1s
## The 'Exponential Backoff' mechanism for re-sending request. The actually
## re-send time interval is `interval * backoff ^ times`
##
## Value: float
##
## Default: 2.0
auth.http.request.retry_backoff = 2.0

View File

@@ -0,0 +1,22 @@
web.hook.api.url = http://localhost:8080/iot/tool/mqtt/webhook
## Encode message payload field
##
## Value: base64 | base62
##
## Default: undefined
## web.hook.encode_payload = base64
# web.hook.rule.client.connect.1 = {"action": "on_client_connect"}
# web.hook.rule.client.connack.1 = {"action": "on_client_connack"}
web.hook.rule.client.connected.1 = {"action": "on_client_connected"}
web.hook.rule.client.disconnected.1 = {"action": "on_client_disconnected"}
# web.hook.rule.client.subscribe.1 = {"action": "on_client_subscribe"}
# web.hook.rule.client.unsubscribe.1 = {"action": "on_client_unsubscribe"}
# web.hook.rule.session.subscribed.1 = {"action": "on_session_subscribed"}
# web.hook.rule.session.unsubscribed.1 = {"action": "on_session_unsubscribed"}
# web.hook.rule.session.terminated.1 = {"action": "on_session_terminated"}
# web.hook.rule.message.publish.1 = {"action": "on_message_publish"}
# web.hook.rule.message.delivered.1 = {"action": "on_message_delivered"}
# web.hook.rule.message.acked.1 = {"action": "on_message_acked"}

View File

@@ -0,0 +1,8 @@
{emqx_management,true}.
{emqx_recon,true}.
{emqx_retainer,true}.
{emqx_dashboard,true}.
{emqx_rule_engine,true}.
{emqx_bridge_mqtt,false}.
{emqx_auth_http,true}.
{emqx_web_hook,true}.

97
docker/nginx-ssl.conf Normal file
View File

@@ -0,0 +1,97 @@
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1k;
gzip_buffers 16 64K;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
server {
listen 80;
server_name localhost;
location / {
rewrite ^(.*) https://$server_name$1 permanent;
}
}
server {
# 侦听443端口
listen 443 ssl;
# 定义访问域名
server_name localhost;
#证书文件名称
ssl_certificate domain_bundle.crt;
#私钥文件名称
ssl_certificate_key domain.key;
#SSL-START SSL相关配置请勿删除或修改下一行带注释的404规则
#error_page 404/404.html;
#HTTP_TO_HTTPS_START
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
}
ssl_session_timeout 10m;
#请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
# web端
location / {
root /var/wumei-smart/vue;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
# 服务端接口
location /prod-api/{
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:8080/;
}
# emqx接口
location /api/v4/{
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:8081/api/v4/;
}
# wss连接
location /mqtt {
proxy_pass http://localhost:8083/mqtt;
proxy_read_timeout 90s;
proxy_set_header Host $host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-for $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

55
docker/nginx.conf Normal file
View File

@@ -0,0 +1,55 @@
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1k;
gzip_buffers 16 64K;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
server {
listen 80;
server_name localhost;
charset utf-8;
location / {
root /var/wumei-smart/vue;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
location /prod-api/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:8080/;
}
location /api/v4/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:8081/api/v4/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

BIN
document/images/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

BIN
document/images/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
document/images/device.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
document/images/flash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
document/images/group.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
document/images/index.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
document/images/message.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
document/images/model.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
document/images/monitor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
document/images/process.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
document/images/product.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

BIN
document/images/sys.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

View File

@@ -0,0 +1,157 @@
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
String randomName="wumei-device"+(String)random(1000);
const char *ap_ssid =randomName.c_str();
const char *ap_password = ""; //开放式网络
char sta_ssid[32] = {0};
char sta_password[64] = {0};
char sta_user_id[32] = {0};
IPAddress local_IP(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);
void initApConfig();
void initWebServer();
void handleConfig();
void handleStatus();
void handleNotFound();
ESP8266WebServer server(80);
void setup(void)
{
//打开串行端口:
Serial.begin(115200);
// AP模式
initApConfig();
// web服务
initWebServer();
}
void loop(void)
{
// Web服务端
server.handleClient();
}
/**
* AP模式
*/
void initApConfig()
{
WiFi.mode(WIFI_AP_STA);
WiFi.softAPConfig(local_IP, gateway, subnet);
WiFi.softAP(ap_ssid, ap_password);
printMsg("已启动AP配网IP地址" + WiFi.softAPIP().toString()+" 热点名称:"+(String)ap_ssid);
}
/**
* 初始化webserver配置
*/
void initWebServer()
{
server.on("/status", HTTP_GET, handleStatus);
server.on("/config", HTTP_POST, handleConfig);
server.onNotFound(handleNotFound);
server.enableCORS(true);
server.begin();
printMsg("HTTP服务已启动");
}
/**
* 连接WIFI
*/
void connectWifi()
{
printMsg("连接WIFI");
WiFi.begin(sta_ssid, sta_password);
int cnt = 0;
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
cnt++;
Serial.print(".");
if (cnt >= 30)
{
printMsg("设备连接WIFI超时请重新配网");
return;
}
}
server.close();
WiFi.softAPdisconnect(false);
printMsg("Http服务和热点已关闭设备已连接WIFI");
}
/**
* 检测设备状态
*/
void handleStatus(){
server.send(200, "text/plain;charset=utf-8", "AP配网已准备就绪");
}
/**
* 配网:下发配置信息
*/
void handleConfig()
{
printMsg("进入配网......");
// wifi名称、wifi密码、用户编号
if (server.hasArg("SSID") && server.hasArg("password") && server.hasArg("userId"))
{
strcpy(sta_ssid, server.arg("SSID").c_str());
strcpy(sta_password, server.arg("password").c_str());
strcpy(sta_user_id, server.arg("userId").c_str());
printMsg("收到WIFI名称" + (String)sta_ssid);
printMsg("收到WIFI密码" + (String)sta_password);
printMsg("收到用户编号:" + (String)sta_user_id);
}
else
{
printMsg("配网必须传递用户编号、WIFI名称和WIFI密码,配网失败");
server.send(500, "text/plain;charset=utf-8", "配网必须传递用户编号、WIFI名称和WIFI密码配网失败");
return;
}
// 可选字段
if (server.hasArg("deviceNum"))
{
printMsg("收到设备编号:" + server.arg("deviceNum"));
}
if (server.hasArg("extra"))
{
printMsg("收到补充信息:" + server.arg("extra"));
}
// TODO 可增加设备连接WIFI测试
server.send(200, "text/plain;charset=utf-8", "设备已更新WIFI配置开始连接WIFI...");
connectWifi();
}
void handleNotFound()
{
printMsg("进入预检请求或请求地址找不到");
if (server.method() == HTTP_OPTIONS)
{
// 处理浏览器跨域问题
server.sendHeader("Access-Control-Max-Age", "10000");
server.sendHeader("Access-Control-Allow-Methods", "PUT,POST,GET,OPTIONS");
server.sendHeader("Access-Control-Allow-Headers", "*");
server.send(204);
}
else
{
server.send(404, "text/plain;charset=utf-8", "请求的地址找不到或无法访问");
}
}
//打印提示信息
void printMsg(String msg)
{
Serial.print("\r\n[");
Serial.print(millis());
Serial.print("ms]");
Serial.print(msg);
}

View File

@@ -0,0 +1,7 @@
{
"port": "COM3",
"configuration": "FlashFreq=80,UploadSpeed=921600",
"board": "esp32:esp32:nano32",
"output": "./build",
"sketch": "Arduino-Esp32.ino"
}

View File

@@ -0,0 +1,85 @@
/***********************************************************
* author: LaoHuang
* create: 2022-04-14
* emailrememberyousaid@163.com
* source:https://github.com/kerwincui/wumei-smart
* board:esp32 版本 1.0.6
***********************************************************/
#include "Helper.h"
long lastMqttConn; // 上次mqtt连接时间
long lastPublishMonitor; // 上次发布监测数据时间
long lastTimerMonitor; // 上次定时发布监测数据
/**
* 启动
*/
void setup()
{
//打开串行端口:
Serial.begin(115200);
printMsg("wumei smart device starting...");
connectWifi();
connectMqtt();
}
/**
* 循环执行
*/
void loop()
{
// Wifi掉线重连
if (WiFi.status() != WL_CONNECTED)
{
connectWifi();
}
// 非阻塞Mqtt重连间隔30秒
if (WiFi.status() == WL_CONNECTED)
{
long now = millis();
if (!mqttClient.connected())
{
if (now - lastMqttConn > 30000)
{
lastMqttConn = now;
connectMqtt();
}
}
else
{
mqttClient.loop();
}
}
// 非阻塞发布实时监测数据,间隔默认1秒
if(WiFi.status() == WL_CONNECTED && monitorCount>0){
long now = millis();
if (now - lastPublishMonitor > monitorInterval)
{
lastPublishMonitor = now;
monitorCount--;
publishMonitor();
}
}
// 非阻塞定时上报测试用60秒发布一次
if(WiFi.status() == WL_CONNECTED){
long now = millis();
if (now - lastTimerMonitor > 60000)
{
lastTimerMonitor = now;
printMsg("执行定时上报");
// 发布事件
publishEvent();
// 发布时钟同步
publishNtp();
// 发布属性(监测值)
String msg=randomPropertyData();
publishProperty(msg);
}
}
}

View File

@@ -0,0 +1,554 @@
/***********************************************************
* author: LaoHuang
* create: 2022-04-14
* emailrememberyousaid@163.com
* source:https://github.com/kerwincui/wumei-smart
* board:esp32 版本1.0.6
***********************************************************/
#include "Helper.h"
String g_time;
WiFiClient wifiClient;
PubSubClient mqttClient;
float rssi = 0;
char wumei_iv[17] = "wumei-smart-open";
int monitorCount = 0;
long monitorInterval = 1000;
//==================================== 这是需要配置的项 ===============================
// Wifi配置
char *wifiSsid = "wifi-ssid";
char *wifiPwd = "wifi-password";
// 设备信息配置
String deviceNum = "D6329VL54419L1Y0";
String userId = "1";
String productId = "2";
float firmwareVersion = 1.0;
// 经度和纬度可选,如果产品使用设备定位,则必须传
float latitude=0;
float longitude=0;
// Mqtt配置
char *mqttHost = "wumei.live";
int mqttPort = 1883;
char *mqttUserName = "wumei-smart";
char *mqttPwd = "P5FJKZJHIR82GNB2";
char mqttSecret[17] = "K63C4EA3AI5TER97";
// 产品启用授权码,则授权码不能为空
String authCode="";
// NTP地址用于获取时间,可选的修改为自己部署项目的地址)
String ntpServer = "http://wumei.live:8080/iot/tool/ntp?deviceSendTime=";
//====================================================================================
// 订阅的主题
String prefix = "/" + productId + "/" + deviceNum;
String sInfoTopic = prefix + "/info/get";
String sOtaTopic = prefix + "/ota/get";
String sNtpTopic = prefix + "/ntp/get";
String sPropertyTopic = prefix + "/property/get";
String sFunctionTopic = prefix + "/function/get";
String sPropertyOnline = prefix + "/property-online/get";
String sFunctionOnline = prefix + "/function-online/get";
String sMonitorTopic = prefix + "/monitor/get";
// 发布的主题
String pInfoTopic = prefix + "/info/post";
String pNtpTopic = prefix + "/ntp/post";
String pPropertyTopic = prefix + "/property/post";
String pFunctionTopic = prefix + "/function/post";
String pMonitorTopic = prefix + "/monitor/post";
String pEventTopic = prefix + "/event/post";
// 物模型-属性处理
void processProperty(String payload)
{
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
for (JsonObject object : doc.as<JsonArray>())
{
// 匹配云端定义的属性(不包含属性中的监测数据)
const char *id = object["id"];
const char *value = object["value"];
printMsg((String)id + "" + (String)value);
}
// 最后发布属性,服务端订阅存储(重要)
publishProperty(payload);
}
// 物模型-功能处理
void processFunction(String payload)
{
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
for (JsonObject object : doc.as<JsonArray>())
{
// 匹配云端定义的功能
const char *id = object["id"];
const char *value = object["value"];
if (strcmp(id, "switch") == 0)
{
printMsg("开关 switch" + (String)value);
}
else if (strcmp(id, "gear") == 0)
{
printMsg("档位 gear" + (String)value);
}
else if (strcmp(id, "light_color") == 0)
{
printMsg("灯光颜色 light_color" + (String)value);
}
else if (strcmp(id, "message") == 0)
{
printMsg("屏显消息 message" + (String)value);
}
else if (strcmp(id, "report_monitor") == 0)
{
String msg = randomPropertyData();
printMsg("订阅到上报监测数据指令,上报数据:");
printMsg(msg);
publishProperty(msg);
}
}
// 最后发布功能,服务端订阅存储(重要)
publishFunction(payload);
}
// Mqtt回调
void callback(char *topic, byte *payload, unsigned int length)
{
blink();
printMsg("接收数据:");
String data = "";
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
data += (char)payload[i];
}
if (strcmp(topic, sOtaTopic.c_str()) == 0)
{
printMsg("订阅到设备升级指令...");
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
String newVersion = doc["version"];
String downloadUrl = doc["downloadUrl"];
printMsg("固件版本:"+newVersion);
printMsg("下载地址:"+downloadUrl);
}
else if (strcmp(topic, sInfoTopic.c_str()) == 0)
{
printMsg("订阅到设备信息...");
// 发布设备信息
publishInfo();
}
else if (strcmp(topic, sNtpTopic.c_str()) == 0)
{
printMsg("订阅到NTP时间...");
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
float deviceSendTime = doc["deviceSendTime"];
float serverSendTime = doc["serverSendTime"];
float serverRecvTime = doc["serverRecvTime"];
float deviceRecvTime = millis();
float now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2;
printMsg("当前时间:" + String(now, 0));
}
else if (strcmp(topic, sPropertyTopic.c_str()) == 0 || strcmp(topic, sPropertyOnline.c_str()) == 0)
{
printMsg("订阅到属性指令...");
processProperty(data);
}
else if (strcmp(topic, sFunctionTopic.c_str()) == 0 || strcmp(topic, sFunctionOnline.c_str()) == 0)
{
printMsg("订阅到功能指令...");
processFunction(data);
}
else if (strcmp(topic, sMonitorTopic.c_str()) == 0)
{
printMsg("订阅到实时监测指令...");
StaticJsonDocument<128> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
monitorCount = doc["count"];
monitorInterval = doc["interval"];
}
}
// 连接wifi
void connectWifi()
{
printMsg("连接 ");
Serial.print(wifiSsid);
WiFi.mode(WIFI_STA);
WiFi.begin(wifiSsid, wifiPwd);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
printMsg("WiFi连接成功");
printMsg("IP地址: ");
Serial.print(WiFi.localIP());
}
// 连接mqtt
void connectMqtt()
{
printMsg("连接Mqtt服务器...");
// 生成mqtt认证密码(设备加密认证密码加密格式为mqtt密码 & 过期时间 & 授权码,其中授权码为可选)
String password = generationPwd();
String encryptPassword = encrypt(password, mqttSecret, wumei_iv);
printMsg("密码(已加密)" + encryptPassword);
mqttClient.setClient(wifiClient);
mqttClient.setServer(mqttHost, mqttPort);
mqttClient.setCallback(callback);
mqttClient.setBufferSize(1024);
mqttClient.setKeepAlive(10);
//连接 设备mqtt客户端Id格式为认证类型(E=加密、S=简单) & 设备编号 & 产品ID & 用户ID
String clientId = "E&" + deviceNum + "&" + productId +"&" + userId;
bool connectResult = mqttClient.connect(clientId.c_str(), mqttUserName, encryptPassword.c_str());
if (connectResult)
{
printMsg("连接成功");
// 订阅(OTA、NTP、属性、功能、实时监测、信息)
mqttClient.subscribe(sInfoTopic.c_str(), 1);
mqttClient.subscribe(sOtaTopic.c_str(), 1);
mqttClient.subscribe(sNtpTopic.c_str(), 1);
mqttClient.subscribe(sPropertyTopic.c_str(), 1);
mqttClient.subscribe(sFunctionTopic.c_str(), 1);
mqttClient.subscribe(sPropertyOnline.c_str(), 1);
mqttClient.subscribe(sFunctionOnline.c_str(), 1);
mqttClient.subscribe(sMonitorTopic.c_str(), 1);
printMsg("订阅主题:" + sInfoTopic);
printMsg("订阅主题:" + sOtaTopic);
printMsg("订阅主题:" + sNtpTopic);
printMsg("订阅主题:" + sPropertyTopic);
printMsg("订阅主题:" + sFunctionTopic);
printMsg("订阅主题:" + sPropertyOnline);
printMsg("订阅主题:" + sFunctionOnline);
printMsg("订阅主题:" + sMonitorTopic);
// 发布设备信息
publishInfo();
}
else
{
printMsg("连接失败, rc=");
Serial.print(mqttClient.state());
}
}
// 1.发布设备信息
void publishInfo()
{
StaticJsonDocument<256> doc;
doc["rssi"] = WiFi.RSSI();
doc["firmwareVersion"] = firmwareVersion;
doc["status"] = 3; // 1-未激活2-禁用3-在线4-离线)
doc["userId"] = (String)userId;
doc["longitude"] = longitude; //经度 可选
doc["latitude"] = latitude; // 纬度 可选
// 设备摘要,可选(自定义配置信息,不限数量)
JsonObject summary = doc.createNestedObject("summary");
summary["name"]="wumei-smart";
summary["chip"]="esp8266";
summary["author"]="kerwincui";
summary["version"]=1.6;
summary["create"]="2022-06-06";
printMsg("发布设备信息:");
serializeJson(doc, Serial);
String output;
serializeJson(doc, output);
mqttClient.publish(pInfoTopic.c_str(), output.c_str());
}
// 2.发布时钟同步信,用于获取当前时间(可选)
void publishNtp()
{
StaticJsonDocument<128> doc;
doc["deviceSendTime"] = millis();
printMsg("发布NTP信息:");
serializeJson(doc, Serial);
String output;
serializeJson(doc, output);
mqttClient.publish(pNtpTopic.c_str(), output.c_str());
}
// 3.发布属性
void publishProperty(String msg)
{
printMsg("发布属性:" + msg);
mqttClient.publish(pPropertyTopic.c_str(), msg.c_str());
}
// 4.发布功能
void publishFunction(String msg)
{
printMsg("发布功能:" + msg);
mqttClient.publish(pFunctionTopic.c_str(), msg.c_str());
}
// 5.发布事件
void publishEvent()
{
// 匹配云端的事件
StaticJsonDocument<512> doc;
JsonObject objTmeperature = doc.createNestedObject();
objTmeperature["id"] = "height_temperature";
objTmeperature["value"] = "40";
objTmeperature["remark"] = "温度过高警告";
JsonObject objException = doc.createNestedObject();
objException["id"] = "exception";
objException["value"] = "异常消息消息内容XXXXXXXX";
objException["remark"] = "设备发生错误";
printMsg("发布事件:");
serializeJson(doc, Serial);
String output;
serializeJson(doc, output);
mqttClient.publish(pEventTopic.c_str(), output.c_str());
}
// 6.发布实时监测数据
void publishMonitor()
{
String msg = randomPropertyData();
// 发布为实时监测数据,不会存储
printMsg("发布实时监测数据:" + msg);
mqttClient.publish(pMonitorTopic.c_str(), msg.c_str());
}
// 随机生成监测值
String randomPropertyData()
{
// 匹配云端定义的监测数据,随机数代替监测结果
float randFloat = 0;
int randInt = 0;
StaticJsonDocument<1024> doc;
JsonObject objTmeperature = doc.createNestedObject();
objTmeperature["id"] = "temperature";
randFloat = random(1000, 3000);
objTmeperature["value"] = (String)(randFloat / 100);
objTmeperature["remark"] = (String)millis();
JsonObject objHumidity = doc.createNestedObject();
objHumidity["id"] = "humidity";
randFloat = random(3000, 6000);
objHumidity["value"] = (String)(randFloat / 100);
objHumidity["remark"] = (String)millis();
JsonObject objCo2 = doc.createNestedObject();
objCo2["id"] = "co2";
randInt = random(400, 1000);
objCo2["value"] = (String)(randInt);
objCo2["remark"] = (String)millis();
JsonObject objBrightness = doc.createNestedObject();
objBrightness["id"] = "brightness";
randInt = random(1000, 10000);
objBrightness["value"] = (String)(randInt);
objBrightness["remark"] = (String)millis();
printMsg("随机生成监测数据值:");
serializeJson(doc, Serial);
String output;
serializeJson(doc, output);
return output;
}
// 生成密码
String generationPwd()
{
String jsonTime = getTime();
printMsg("getTime()= " + jsonTime);
// 128字节内存池容量
StaticJsonDocument<128> doc;
// 解析JSON
DeserializationError error = deserializeJson(doc, jsonTime);
if (error)
{
printMsg("Json解析失败");
Serial.print(error.f_str());
return "";
}
// 获取当前时间
float deviceSendTime = doc["deviceSendTime"];
float serverSendTime = doc["serverSendTime"];
float serverRecvTime = doc["serverRecvTime"];
float deviceRecvTime = millis();
float now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2;
// 过期时间 = 当前时间 + 1小时
float expireTime = now + 1 * 60 * 60 * 1000;
// 密码加密格式为mqtt密码 & 过期时间 & 授权码(可选),如果产品启用了授权码就必须加上
String password="";
if(authCode == ""){
password = (String)mqttPwd + "&" + String(expireTime, 0);
}else{
password = (String)mqttPwd + "&" + String(expireTime, 0) + "&" + authCode;
}
printMsg("密码(未加密):" + password);
return password;
}
// HTTP获取时间
String getTime()
{
while (WiFi.status() == WL_CONNECTED)
{
HTTPClient http;
printMsg("获取时间...");
if (http.begin(wifiClient, (ntpServer + (String)millis()).c_str()))
{
// 发送请求
int httpCode = http.GET();
if (httpCode > 0)
{
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY)
{
g_time = http.getString();
printMsg("获取时间成功data:");
Serial.print(g_time);
return g_time;
}
}
else
{
printMsg("获取时间失败error:");
Serial.printf(http.errorToString(httpCode).c_str());
}
http.end();
}
else
{
printMsg("连接Http失败");
}
delay(500);
}
}
//打印提示信息
void printMsg(String msg)
{
Serial.print("\r\n[");
Serial.print(millis());
Serial.print("ms]");
Serial.print(msg);
}
// 控制指示灯闪烁
void blink()
{
printMsg("指示灯闪烁...");
pinMode(15, OUTPUT);
for (int i = 0; i < 2; i++)
{
digitalWrite(15, HIGH);
delay(200);
digitalWrite(15, LOW);
delay(200);
}
}
// 加密 (AES-CBC-128-pkcs5padding)
String encrypt(String plain_data, char *wumei_key, char *wumei_iv)
{
int i;
// pkcs7padding填充 Block Size : 16
int len = plain_data.length();
int n_blocks = len / 16 + 1;
uint8_t n_padding = n_blocks * 16 - len;
uint8_t data[n_blocks * 16];
memcpy(data, plain_data.c_str(), len);
for (i = len; i < n_blocks * 16; i++)
{
data[i] = n_padding;
}
uint8_t key[16], iv[16];
uint8_t crypt_data[3 * 16] = {0};
memcpy(key, wumei_key, 16);
memcpy(iv, wumei_iv, 16);
memset(crypt_data, 0, 48);
len = n_blocks * 16;
// 加密
mbedtls_aes_context aes_ctx;
mbedtls_aes_init(&aes_ctx);
mbedtls_aes_setkey_enc(&aes_ctx, key, 128);
mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, len, iv, data, crypt_data);
// Base64编码
char encoded_data[base64_enc_len(len)];
base64_encode(encoded_data, (char *)crypt_data, len);
return String(encoded_data);
}
// 解密 (AES-CBC-128-pkcs5padding)
String decrypt(String encoded_data_str, char *wumei_key, char *wumei_iv)
{
int input_len = encoded_data_str.length();
char *encoded_data = const_cast<char *>(encoded_data_str.c_str());
int len = base64_dec_len(encoded_data, input_len);
uint8_t data[len];
base64_decode((char *)data, encoded_data, input_len);
uint8_t key[16], iv[16];
memcpy(key, wumei_key, 16);
memcpy(iv, wumei_iv, 16);
int n_blocks = len / 16;
uint8_t n_padding = data[n_blocks * 16 - 1];
len = n_blocks * 16 - n_padding;
char plain_data[len + 1];
//密文空间
mbedtls_aes_context aes_ctx;
mbedtls_aes_init(&aes_ctx);
//设置解密密钥
mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, 48, iv, (unsigned char *)encoded_data, (unsigned char *)plain_data);
mbedtls_aes_free(&aes_ctx);
// PKCS#7 Padding 填充
plain_data[len] = '\0';
return String(plain_data);
}

View File

@@ -0,0 +1,79 @@
/***********************************************************
* author: LaoHuang
* create: 2022-04-14
* emailrememberyousaid@163.com
* source:https://github.com/kerwincui/wumei-smart
* board:esp32 版本1.0.6
***********************************************************/
#ifndef _HELPER_H
#define _HELPER_H
#include <mbedtls/aes.h>
#include "Base64.h"
#include <WiFiClient.h>
//#include <Ethernet.h>
#include <HTTPClient.h>
#include <PubSubClient.h> // 版本2.8.0
#include <ArduinoJson.h> // 版本6.19.4
extern WiFiClient wifiClient;
extern PubSubClient mqttClient;
extern String deviceNum ; // 设备编号重要同时是Mqtt的clientId
extern String userId; // 用户ID
extern String productId; // 产品ID
extern float rssi; // 信号强度信号极好4格[-55— 0]信号好3格[-70— -55]信号一般2格[-85— -70]信号差1格[-100— -85]
extern float firmwareVersion; // 固件版本
extern char *wifiSsid; // WIFI的SSID
extern char *wifiPwd; // WIFI的密码
extern char *mqttHost; // Mqtt消息服务器地址
extern int mqttPort; // Mqtt消息服务器端口
extern char *mqttUserName; // Mqtt消息服务器账号
extern char *mqttPwd; // Mqtt消息服务器密码
extern char mqttSecret[17]; // Mqtt秘钥,16位
extern char wumei_iv[17]; // AES加密偏移量固定值16位
extern String ntpServer; // NTP服务地址用于获取当前时间
extern int monitorCount; // 发布监测数据的最大次数
extern long monitorInterval; // 发布监测数据的间隔默认1000毫秒
// 连接wifi
void connectWifi();
// 连接mqtt
void connectMqtt();
// Mqtt回调
void callback(char *topic, byte *payload, unsigned int length);
// 发布设备信息
void publishInfo();
// 发布时钟同步信息
void publishNtp();
// 发布事件
void publishEvent();
// 发布实时监测数据
void publishMonitor();
// 随机生成监测值
String randomPropertyData();
// 发布属性
void publishProperty(String msg);
// 发布功能
void publishFunction(String msg);
// 属性处理
void processProperty(String payload);
// 功能处理
void processFunction(String payload);
// 生成密码
String generationPwd();
// 获取时间
String getTime();
// AES加密
String encrypt(String plain_data,char *wumei_key,char *wumei_iv);
// AES解密
String decrypt(String encoded_data_str,char *wumei_key,char *wumei_iv);
//打印提示信息
void printMsg(String tips);
// 控制指示灯闪烁
void blink();
#endif

View File

@@ -0,0 +1,137 @@
#include "Base64.h"
#if (defined(__AVR__))
#include <avr\pgmspace.h>
#else
#include <pgmspace.h>
#endif
const char PROGMEM b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* 'Private' declarations */
inline void a3_to_a4(unsigned char * a4, unsigned char * a3);
inline void a4_to_a3(unsigned char * a3, unsigned char * a4);
inline unsigned char b64_lookup(char c);
int base64_encode(char *output, char *input, int inputLen) {
int i = 0, j = 0;
int encLen = 0;
unsigned char a3[3];
unsigned char a4[4];
while(inputLen--) {
a3[i++] = *(input++);
if(i == 3) {
a3_to_a4(a4, a3);
for(i = 0; i < 4; i++) {
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]);
}
i = 0;
}
}
if(i) {
for(j = i; j < 3; j++) {
a3[j] = '\0';
}
a3_to_a4(a4, a3);
for(j = 0; j < i + 1; j++) {
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]);
}
while((i++ < 3)) {
output[encLen++] = '=';
}
}
output[encLen] = '\0';
return encLen;
}
int base64_decode(char * output, char * input, int inputLen) {
int i = 0, j = 0;
int decLen = 0;
unsigned char a3[3];
unsigned char a4[4];
while (inputLen--) {
if(*input == '=') {
break;
}
a4[i++] = *(input++);
if (i == 4) {
for (i = 0; i <4; i++) {
a4[i] = b64_lookup(a4[i]);
}
a4_to_a3(a3,a4);
for (i = 0; i < 3; i++) {
output[decLen++] = a3[i];
}
i = 0;
}
}
if (i) {
for (j = i; j < 4; j++) {
a4[j] = '\0';
}
for (j = 0; j <4; j++) {
a4[j] = b64_lookup(a4[j]);
}
a4_to_a3(a3,a4);
for (j = 0; j < i - 1; j++) {
output[decLen++] = a3[j];
}
}
output[decLen] = '\0';
return decLen;
}
int base64_enc_len(int plainLen) {
int n = plainLen;
return (n + 2 - ((n + 2) % 3)) / 3 * 4;
}
int base64_dec_len(char * input, int inputLen) {
int i = 0;
int numEq = 0;
for(i = inputLen - 1; input[i] == '='; i--) {
numEq++;
}
return ((6 * inputLen) / 8) - numEq;
}
inline void a3_to_a4(unsigned char * a4, unsigned char * a3) {
a4[0] = (a3[0] & 0xfc) >> 2;
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
a4[3] = (a3[2] & 0x3f);
}
inline void a4_to_a3(unsigned char * a3, unsigned char * a4) {
a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
}
inline unsigned char b64_lookup(char c) {
if(c >='A' && c <='Z') return c - 'A';
if(c >='a' && c <='z') return c - 71;
if(c >='0' && c <='9') return c + 4;
if(c == '+') return 62;
if(c == '/') return 63;
return -1;
}

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2013 Adam Rudd.
* See LICENSE for more information
*/
#ifndef _BASE64_H
#define _BASE64_H
/* b64_alphabet:
* Description: Base64 alphabet table, a mapping between integers
* and base64 digits
* Notes: This is an extern here but is defined in Base64.c
*/
extern const char b64_alphabet[];
/* base64_encode:
* Description:
* Encode a string of characters as base64
* Parameters:
* output: the output buffer for the encoding, stores the encoded string
* input: the input buffer for the encoding, stores the binary to be encoded
* inputLen: the length of the input buffer, in bytes
* Return value:
* Returns the length of the encoded string
* Requirements:
* 1. output must not be null or empty
* 2. input must not be null
* 3. inputLen must be greater than or equal to 0
*/
int base64_encode(char *output, char *input, int inputLen);
/* base64_decode:
* Description:
* Decode a base64 encoded string into bytes
* Parameters:
* output: the output buffer for the decoding,
* stores the decoded binary
* input: the input buffer for the decoding,
* stores the base64 string to be decoded
* inputLen: the length of the input buffer, in bytes
* Return value:
* Returns the length of the decoded string
* Requirements:
* 1. output must not be null or empty
* 2. input must not be null
* 3. inputLen must be greater than or equal to 0
*/
int base64_decode(char *output, char *input, int inputLen);
/* base64_enc_len:
* Description:
* Returns the length of a base64 encoded string whose decoded
* form is inputLen bytes long
* Parameters:
* inputLen: the length of the decoded string
* Return value:
* The length of a base64 encoded string whose decoded form
* is inputLen bytes long
* Requirements:
* None
*/
int base64_enc_len(int inputLen);
/* base64_dec_len:
* Description:
* Returns the length of the decoded form of a
* base64 encoded string
* Parameters:
* input: the base64 encoded string to be measured
* inputLen: the length of the base64 encoded string
* Return value:
* Returns the length of the decoded form of a
* base64 encoded string
* Requirements:
* 1. input must not be null
* 2. input must be greater than or equal to zero
*/
int base64_dec_len(char *input, int inputLen);
#endif // _BASE64_H

View File

@@ -17,21 +17,26 @@ long monitorInterval = 1000;
//==================================== 这是需要配置的项 ===============================
// Wifi配置
char *wifiSsid = "wifi账号";
char *wifiPwd = "wifi密码";
char *wifiSsid = "wumei";
char *wifiPwd = "wumei-smart";
// 设备信息配置
String deviceNum = "D6329VL54419L1Y0";
String deviceNum = "D6329VL548866";
String userId = "1";
String productId = "2";
String firmwareVersion = "1.0";
String productId = "41";
float firmwareVersion = 1.0;
// 经度和纬度可选,如果产品使用设备定位,则必须传
float latitude=0;
float longitude=0;
// Mqtt配置
char *mqttHost = "wumei.live";
int mqttPort = 1883;
char *mqttUserName = "wumei-smart";
char *mqttPwd = "P5FJKZJHIR82GNB2";
char mqttSecret[17] = "K63C4EA3AI5TER97";
char *mqttPwd = "PHYFED93WSFF1DAS";
char mqttSecret[17] = "K2V5DE28XNUU3497";
// 产品启用授权码,则授权码不能为空
String authCode="";
// NTP地址用于获取时间,可选的修改为自己部署项目的地址)
String ntpServer = "http://wumei.live:8080/iot/tool/ntp?deviceSendTime=";
@@ -39,6 +44,7 @@ String ntpServer = "http://wumei.live:8080/iot/tool/ntp?deviceSendTime=";
// 订阅的主题
String prefix = "/" + productId + "/" + deviceNum;
String sInfoTopic = prefix + "/info/get";
String sOtaTopic = prefix + "/ota/get";
String sNtpTopic = prefix + "/ntp/get";
String sPropertyTopic = prefix + "/property/get";
@@ -131,6 +137,24 @@ void callback(char *topic, byte *payload, unsigned int length)
if (strcmp(topic, sOtaTopic.c_str()) == 0)
{
printMsg("订阅到设备升级指令...");
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
String newVersion = doc["version"];
String downloadUrl = doc["downloadUrl"];
printMsg("固件版本:"+newVersion);
printMsg("下载地址:"+downloadUrl);
}
else if (strcmp(topic, sInfoTopic.c_str()) == 0)
{
printMsg("订阅到设备信息...");
// 发布设备信息
publishInfo();
}
else if (strcmp(topic, sNtpTopic.c_str()) == 0)
{
@@ -198,7 +222,7 @@ void connectWifi()
void connectMqtt()
{
printMsg("连接Mqtt服务器...");
// 生成mqtt认证密码(密码 = mqtt密码 & 用户ID & 过期时间)
// 生成mqtt认证密码(设备加密认证密码加密格式为mqtt密码 & 过期时间 & 授权码,其中授权码为可选)
String password = generationPwd();
String encryptPassword = encrypt(password, mqttSecret, wumei_iv);
printMsg("密码(已加密)" + encryptPassword);
@@ -207,13 +231,14 @@ void connectMqtt()
mqttClient.setCallback(callback);
mqttClient.setBufferSize(1024);
mqttClient.setKeepAlive(10);
//连接客户端ID = 设备编号 & 产品ID
String clientId = deviceNum + "&" + productId;
//连接 设备mqtt客户端Id格式为认证类型(E=加密、S=简单) & 设备编号 & 产品ID & 用户ID
String clientId = "E&" + deviceNum + "&" + productId +"&" + userId;
bool connectResult = mqttClient.connect(clientId.c_str(), mqttUserName, encryptPassword.c_str());
if (connectResult)
{
printMsg("连接成功");
// 订阅(OTA、NTP、属性、功能、实时监测)
// 订阅(OTA、NTP、属性、功能、实时监测、信息)
mqttClient.subscribe(sInfoTopic.c_str(), 1);
mqttClient.subscribe(sOtaTopic.c_str(), 1);
mqttClient.subscribe(sNtpTopic.c_str(), 1);
mqttClient.subscribe(sPropertyTopic.c_str(), 1);
@@ -221,6 +246,7 @@ void connectMqtt()
mqttClient.subscribe(sPropertyOnline.c_str(), 1);
mqttClient.subscribe(sFunctionOnline.c_str(), 1);
mqttClient.subscribe(sMonitorTopic.c_str(), 1);
printMsg("订阅主题:" + sInfoTopic);
printMsg("订阅主题:" + sOtaTopic);
printMsg("订阅主题:" + sNtpTopic);
printMsg("订阅主题:" + sPropertyTopic);
@@ -246,6 +272,15 @@ void publishInfo()
doc["firmwareVersion"] = firmwareVersion;
doc["status"] = 3; // 1-未激活2-禁用3-在线4-离线)
doc["userId"] = (String)userId;
doc["longitude"] = longitude; //经度 可选
doc["latitude"] = latitude; // 纬度 可选
// 设备摘要,可选(自定义配置信息)
JsonObject summary = doc.createNestedObject("summary");
summary["name"]="wumei-smart";
summary["chip"]="esp8266";
summary["author"]="kerwincui";
summary["version"]=1.6;
summary["create"]="2022-06-06";
printMsg("发布设备信息:");
serializeJson(doc, Serial);
@@ -371,7 +406,13 @@ String generationPwd()
float now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2;
// 过期时间 = 当前时间 + 1小时
float expireTime = now + 1 * 60 * 60 * 1000;
String password = (String)mqttPwd + "&" + userId + "&" + String(expireTime, 0);
// 密码加密格式为mqtt密码 & 过期时间 & 授权码(可选),如果产品启用了授权码就必须加上
String password="";
if(authCode==""){
password = (String)mqttPwd + "&" + String(expireTime, 0);
}else{
password = (String)mqttPwd + "&" + String(expireTime, 0)+ "&" + authCode;
}
printMsg("密码(未加密):" + password);
return password;
}

View File

@@ -23,7 +23,7 @@ extern String deviceNum ; // 设备编号重要同时是Mqtt的client
extern String userId; // 用户ID
extern String productId; // 产品ID
extern float rssi; // 信号强度信号极好4格[-55— 0]信号好3格[-70— -55]信号一般2格[-85— -70]信号差1格[-100— -85]
extern String firmwareVersion; // 固件版本
extern float firmwareVersion; // 固件版本
extern char *wifiSsid; // WIFI的SSID
extern char *wifiPwd; // WIFI的密码
extern char *mqttHost; // Mqtt消息服务器地址

View File

@@ -0,0 +1,134 @@
/*********************************************************************
* function 设备AP配网
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#include "ApConfig.h"
String randomName = "wumei-device" + (String)random(1000);
const char *ap_ssid = randomName.c_str();
//开放式网络,不设置密码
const char *ap_password = "";
IPAddress local_IP(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);
ESP8266WebServer server(80);
/**
* 启动AP配网
*/
void startApConfig()
{
ledStatus(true);
WiFi.mode(WIFI_AP_STA);
WiFi.softAPConfig(local_IP, gateway, subnet);
WiFi.softAP(ap_ssid, ap_password);
printMsg("已启动AP配网IP地址" + WiFi.softAPIP().toString() + " 热点名称:" + (String)ap_ssid);
// 启动web服务
startWebServer();
}
/**
* 启动Web服务
*/
void startWebServer()
{
isApMode = true;
server.on("/status", HTTP_GET, handleStatus);
server.on("/config", HTTP_POST, handleConfig);
server.onNotFound(handleNotFound);
server.enableCORS(true);
server.begin();
printMsg("HTTP服务已启动");
}
/**
* 检测设备接口
*/
void handleStatus()
{
server.send(200, "text/plain;charset=utf-8", "AP配网已准备就绪");
}
/**
* AP配网接口
*/
void handleConfig()
{
printMsg("进入配网......");
config_type config;
// wifi名称、wifi密码、用户编号
if (server.hasArg("SSID") && server.hasArg("password") && server.hasArg("userId"))
{
// 分配空间
wifiSsid = (char *)malloc(32 * sizeof(char));
wifiPwd = (char *)malloc(64 * sizeof(char));
userId = (char *)malloc(16 * sizeof(char));
strcpy(config.stassid, server.arg("SSID").c_str());
strcpy(wifiSsid, server.arg("SSID").c_str());
strcpy(config.stapsw, server.arg("password").c_str());
strcpy(wifiPwd, server.arg("password").c_str());
strcpy(config.userId, server.arg("userId").c_str());
strcpy(userId, server.arg("userId").c_str());
printMsg("收到WIFI名称" + (String)config.stassid);
printMsg("收到WIFI密码" + (String)config.stapsw);
printMsg("收到用户编号:" + (String)config.userId);
}
else
{
printMsg("配网必须传递用户编号、WIFI名称和WIFI密码,配网失败");
server.send(500, "text/plain;charset=utf-8", "配网必须传递用户编号、WIFI名称和WIFI密码配网失败");
return;
}
// 可选字段
if (server.hasArg("deviceNum"))
{
deviceNum = (char *)malloc(32 * sizeof(char));
strcpy(config.deviceNum, server.arg("deviceNum").c_str());
strcpy(deviceNum, server.arg("deviceNum").c_str());
printMsg("收到设备编号:" + server.arg("deviceNum"));
}
if (server.hasArg("authCode"))
{
authCode = (char *)malloc(32 * sizeof(char));
strcpy(config.authCode, server.arg("authCode").c_str());
strcpy(authCode, server.arg("authCode").c_str());
printMsg("收到产品授权码:" + server.arg("authCode"));
}
if (server.hasArg("extra"))
{
printMsg("收到补充信息:" + server.arg("extra"));
}
server.send(200, "text/plain;charset=utf-8", "设备已更新WIFI配置开始连接WIFI...");
// 统一设置Mqtt消息主题前缀
prefix = "/" + (String)productId + "/" + (String)deviceNum;
// 存储配置
saveConfig(config);
// 连接Wifi
connectWifi();
}
/**
* 找不到页面和跨域处理
*/
void handleNotFound()
{
printMsg("进入预检请求或请求地址找不到");
if (server.method() == HTTP_OPTIONS)
{
// 处理浏览器跨域问题
server.sendHeader("Access-Control-Max-Age", "10000");
server.sendHeader("Access-Control-Allow-Methods", "PUT,POST,GET,OPTIONS");
server.sendHeader("Access-Control-Allow-Headers", "*");
server.send(204);
}
else
{
server.send(404, "text/plain;charset=utf-8", "请求的地址找不到或无法访问");
}
}

View File

@@ -0,0 +1,28 @@
/*********************************************************************
* function 设备AP配网
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#ifndef _APCONFIG_H
#define _APCONFIG_H
#include "Config.h"
#include <ESP8266WebServer.h>
extern ESP8266WebServer server;
// 启动AP配网
void startApConfig();
// 启动Web服务
void startWebServer();
// 配网接口
void handleConfig();
// 检测设备接口
void handleStatus();
// 找不到页面和浏览器跨域处理
void handleNotFound();
#endif

View File

@@ -0,0 +1,176 @@
/*********************************************************************
* function 设备认证
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#include "Auth.h"
/*
* 连接MQTT加密认证
*/
void connectMqtt()
{
printMsg("连接Mqtt服务器...");
mqttClient.setClient(wifiClient);
mqttClient.setServer(mqttHost, mqttPort);
mqttClient.setBufferSize(1024);
mqttClient.setKeepAlive(5);
// 设置Mqtt回调函数
mqttClient.setCallback(mqttCallback);
// 生成mqtt加密密码
String aesPassword = generationAESPwd();
// 连接 设备mqtt客户端Id格式为认证类型(E=加密、S=简单) & 设备编号 & 产品ID & 用户ID
String clientId = "E&" + (String)deviceNum + "&" + (String)productId + "&" + (String)userId;
printMsg("客户端ID" + clientId);
bool connectResult = mqttClient.connect(clientId.c_str(), mqttUserName, aesPassword.c_str());
if (connectResult)
{
printMsg("连接Mqtt成功");
// 订阅系统主题
subscribeTopic();
// 发布设备信息,设备上电都需要发布一次
publishInfo();
}
else
{
printMsg("连接失败, rc=");
Serial.print(mqttClient.state());
}
}
/*
* 生成加密密码
*/
String generationAESPwd()
{
// 获取NTP时间
String jsonTime = getTime();
StaticJsonDocument<128> doc;
DeserializationError error = deserializeJson(doc, jsonTime);
if (error)
{
printMsg("Json解析失败");
Serial.print(error.f_str());
return "";
}
// 获取NTP时间=(设备发送消息时间 + 服务器接收消息时间 + 服务器发送消息时间 - 设备接收时间 最后除于2
float deviceSendTime = doc["deviceSendTime"];
float serverSendTime = doc["serverSendTime"];
float serverRecvTime = doc["serverRecvTime"];
float deviceRecvTime = millis();
float now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2;
// 过期时间 = 当前时间 + 1小时
float expireTime = now + 1 * 60 * 60 * 1000;
// 加密认证密码格式为mqtt密码 & 过期时间 & 授权码(可选),如果产品启用了授权码就必须加上
String password = "";
if (authCode == "")
{
password = (String)mqttPwd + "&" + String(expireTime, 0);
}
else
{
password = (String)mqttPwd + "&" + String(expireTime, 0) + "&" + authCode;
}
// 密码加密
printMsg("密码(未加密):" + password);
String encryptPassword = encrypt(password, mqttSecret, wumei_iv);
printMsg("密码(已加密)" + encryptPassword);
return encryptPassword;
}
/*
* 通过HTTP获取NTP时间
*/
String getTime()
{
while (WiFi.status() == WL_CONNECTED)
{
HTTPClient http;
printMsg("获取时间...");
if (http.begin(wifiClient, (ntpServer + (String)millis()).c_str()))
{
// 发送请求
int httpCode = http.GET();
if (httpCode > 0)
{
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY)
{
printMsg("获取时间成功data:");
Serial.print(http.getString());
return http.getString();
}
}
else
{
printMsg("获取时间失败error:");
Serial.printf(http.errorToString(httpCode).c_str());
}
http.end();
}
else
{
printMsg("连接Http失败");
}
delay(500);
}
}
/*
* AES加密 (AES-CBC-128-pkcs5padding)
*/
String encrypt(String plain_data, char *wumei_key, char *wumei_iv)
{
int i;
// pkcs7padding填充 Block Size : 16
int len = plain_data.length();
int n_blocks = len / 16 + 1;
uint8_t n_padding = n_blocks * 16 - len;
uint8_t data[n_blocks * 16];
memcpy(data, plain_data.c_str(), len);
for (i = len; i < n_blocks * 16; i++)
{
data[i] = n_padding;
}
uint8_t key[16], iv[16];
memcpy(key, wumei_key, 16);
memcpy(iv, wumei_iv, 16);
// 加密
br_aes_big_cbcenc_keys encCtx;
br_aes_big_cbcenc_init(&encCtx, key, 16);
br_aes_big_cbcenc_run(&encCtx, iv, data, n_blocks * 16);
// Base64编码
len = n_blocks * 16;
char encoded_data[base64_enc_len(len)];
base64_encode(encoded_data, (char *)data, len);
return String(encoded_data);
}
/*
* AES解密 (AES-CBC-128-pkcs5padding)
*/
String decrypt(String encoded_data_str, char *wumei_key, char *wumei_iv)
{
int input_len = encoded_data_str.length();
char *encoded_data = const_cast<char *>(encoded_data_str.c_str());
int len = base64_dec_len(encoded_data, input_len);
uint8_t data[len];
base64_decode((char *)data, encoded_data, input_len);
uint8_t key[16], iv[16];
memcpy(key, wumei_key, 16);
memcpy(iv, wumei_iv, 16);
int n_blocks = len / 16;
br_aes_big_cbcdec_keys decCtx;
br_aes_big_cbcdec_init(&decCtx, key, 16);
br_aes_big_cbcdec_run(&decCtx, iv, data, n_blocks * 16);
// PKCS#7 Padding 填充
uint8_t n_padding = data[n_blocks * 16 - 1];
len = n_blocks * 16 - n_padding;
char plain_data[len + 1];
memcpy(plain_data, data, len);
plain_data[len] = '\0';
return String(plain_data);
}

View File

@@ -0,0 +1,29 @@
/*********************************************************************
* function 设备认证
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#ifndef _AUTH_H
#define _AUTH_H
#include "Config.h"
#include "User.h"
#include "Mqtt.h"
#include <Ethernet.h>
#include <ESP8266HTTPClient.h>
// 连接mqtt, AES加密认证
void connectMqtt();
// 生成加密密码
String generationAESPwd();
// 获取时间
String getTime();
// AES加密
String encrypt(String plain_data, char *wumei_key, char *wumei_iv);
// AES解密
String decrypt(String encoded_data_str, char *wumei_key, char *wumei_iv);
#endif

View File

@@ -0,0 +1,173 @@
/*********************************************************************
* function Base64编码和解码
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: Copyright (c) 2013 Adam Rudd.
********************************************************************/
#include "Base64.h"
#if (defined(__AVR__))
#include <avr\pgmspace.h>
#else
#include <pgmspace.h>
#endif
const char PROGMEM b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* 'Private' declarations */
inline void a3_to_a4(unsigned char *a4, unsigned char *a3);
inline void a4_to_a3(unsigned char *a3, unsigned char *a4);
inline unsigned char b64_lookup(char c);
int base64_encode(char *output, char *input, int inputLen)
{
int i = 0, j = 0;
int encLen = 0;
unsigned char a3[3];
unsigned char a4[4];
while (inputLen--)
{
a3[i++] = *(input++);
if (i == 3)
{
a3_to_a4(a4, a3);
for (i = 0; i < 4; i++)
{
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]);
}
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
{
a3[j] = '\0';
}
a3_to_a4(a4, a3);
for (j = 0; j < i + 1; j++)
{
output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]);
}
while ((i++ < 3))
{
output[encLen++] = '=';
}
}
output[encLen] = '\0';
return encLen;
}
int base64_decode(char *output, char *input, int inputLen)
{
int i = 0, j = 0;
int decLen = 0;
unsigned char a3[3];
unsigned char a4[4];
while (inputLen--)
{
if (*input == '=')
{
break;
}
a4[i++] = *(input++);
if (i == 4)
{
for (i = 0; i < 4; i++)
{
a4[i] = b64_lookup(a4[i]);
}
a4_to_a3(a3, a4);
for (i = 0; i < 3; i++)
{
output[decLen++] = a3[i];
}
i = 0;
}
}
if (i)
{
for (j = i; j < 4; j++)
{
a4[j] = '\0';
}
for (j = 0; j < 4; j++)
{
a4[j] = b64_lookup(a4[j]);
}
a4_to_a3(a3, a4);
for (j = 0; j < i - 1; j++)
{
output[decLen++] = a3[j];
}
}
output[decLen] = '\0';
return decLen;
}
int base64_enc_len(int plainLen)
{
int n = plainLen;
return (n + 2 - ((n + 2) % 3)) / 3 * 4;
}
int base64_dec_len(char *input, int inputLen)
{
int i = 0;
int numEq = 0;
for (i = inputLen - 1; input[i] == '='; i--)
{
numEq++;
}
return ((6 * inputLen) / 8) - numEq;
}
inline void a3_to_a4(unsigned char *a4, unsigned char *a3)
{
a4[0] = (a3[0] & 0xfc) >> 2;
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
a4[3] = (a3[2] & 0x3f);
}
inline void a4_to_a3(unsigned char *a3, unsigned char *a4)
{
a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
}
inline unsigned char b64_lookup(char c)
{
if (c >= 'A' && c <= 'Z')
return c - 'A';
if (c >= 'a' && c <= 'z')
return c - 71;
if (c >= '0' && c <= '9')
return c + 4;
if (c == '+')
return 62;
if (c == '/')
return 63;
return -1;
}

View File

@@ -0,0 +1,84 @@
/*********************************************************************
* function Base64编码和解码
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: Copyright (c) 2013 Adam Rudd.
********************************************************************/
#ifndef _BASE64_H
#define _BASE64_H
/* b64_alphabet:
* Description: Base64 alphabet table, a mapping between integers
* and base64 digits
* Notes: This is an extern here but is defined in Base64.c
*/
extern const char b64_alphabet[];
/* base64_encode:
* Description:
* Encode a string of characters as base64
* Parameters:
* output: the output buffer for the encoding, stores the encoded string
* input: the input buffer for the encoding, stores the binary to be encoded
* inputLen: the length of the input buffer, in bytes
* Return value:
* Returns the length of the encoded string
* Requirements:
* 1. output must not be null or empty
* 2. input must not be null
* 3. inputLen must be greater than or equal to 0
*/
int base64_encode(char *output, char *input, int inputLen);
/* base64_decode:
* Description:
* Decode a base64 encoded string into bytes
* Parameters:
* output: the output buffer for the decoding,
* stores the decoded binary
* input: the input buffer for the decoding,
* stores the base64 string to be decoded
* inputLen: the length of the input buffer, in bytes
* Return value:
* Returns the length of the decoded string
* Requirements:
* 1. output must not be null or empty
* 2. input must not be null
* 3. inputLen must be greater than or equal to 0
*/
int base64_decode(char *output, char *input, int inputLen);
/* base64_enc_len:
* Description:
* Returns the length of a base64 encoded string whose decoded
* form is inputLen bytes long
* Parameters:
* inputLen: the length of the decoded string
* Return value:
* The length of a base64 encoded string whose decoded form
* is inputLen bytes long
* Requirements:
* None
*/
int base64_enc_len(int inputLen);
/* base64_dec_len:
* Description:
* Returns the length of the decoded form of a
* base64 encoded string
* Parameters:
* input: the base64 encoded string to be measured
* inputLen: the length of the base64 encoded string
* Return value:
* Returns the length of the decoded form of a
* base64 encoded string
* Requirements:
* 1. input must not be null
* 2. input must be greater than or equal to zero
*/
int base64_dec_len(char *input, int inputLen);
#endif // _BASE64_H

View File

@@ -0,0 +1,196 @@
/*********************************************************************
* function 设备配置和系统功能
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#include "Config.h"
#define LED 15 // LED指示灯引脚
WiFiClient wifiClient;
PubSubClient mqttClient;
float rssi = 0;
char wumei_iv[17] = "wumei-smart-open";
int monitorCount = 0;
long monitorInterval = 1000;
bool isApMode = false;
// Mqtt订阅的主题前缀格式为 /productId/devicenumber
String prefix = "";
String sInfoTopic = "/info/get";
String sOtaTopic = "/ota/get";
String sNtpTopic = "/ntp/get";
String sPropertyTopic = "/property/get";
String sFunctionTopic = "/function/get";
String sPropertyOnline = "/property-online/get";
String sFunctionOnline = "/function-online/get";
String sMonitorTopic = "/monitor/get";
// Mqtt发布的主题
String pInfoTopic = "/info/post";
String pNtpTopic = "/ntp/post";
String pPropertyTopic = "/property/post";
String pFunctionTopic = "/function/post";
String pMonitorTopic = "/monitor/post";
String pEventTopic = "/event/post";
/********************************** begin 可配置的项 **********************************/
// wifi信息
char *wifiSsid = "";
char *wifiPwd = "";
char *userId = "1";
// 产品启用授权码,则授权码不能为空
char *authCode = "";
// 设备信息配置
char *deviceNum = "D6329VL5668888";
char *productId = "41";
float firmwareVersion = 1.0;
// 经度和纬度可选,如果产品使用设备定位,则必须传
float latitude = 0;
float longitude = 0;
// Mqtt配置
char *mqttHost = "wumei.live";
int mqttPort = 1883;
char *mqttUserName = "wumei-smart";
char *mqttPwd = "PHYFED93WSFF1DAS";
char mqttSecret[17] = "K2V5DE28XNUU3497";
// NTP地址用于获取时间,修改为自己部署项目的接口地址)
String ntpServer = "http://wumei.live:8080/iot/tool/ntp?deviceSendTime=";
/********************************** end 可配置的项 **********************************/
// 连接wifi
void connectWifi()
{
if (isApMode)
{
// 关闭AP配网模式延迟2秒确保返回状态码给手机
isApMode = false;
delay(2000);
server.stop();
ledStatus(false);
}
printMsg("连接Wifi ");
Serial.print(wifiSsid);
WiFi.mode(WIFI_STA);
WiFi.begin(wifiSsid, wifiPwd);
}
// 存储配置
void saveConfig(config_type config)
{
// 标识为已经存储数据
config.flag = 1;
EEPROM.begin(240);
printMsg("存储配置...");
uint8_t *p = (uint8_t *)(&config);
for (int i = 0; i < sizeof(config); i++)
{
EEPROM.write(i, *(p + i));
}
EEPROM.end();
}
// 加载配置
void loadConfig()
{
config_type config;
EEPROM.begin(240);
printMsg("加载配置...");
uint8_t *p = (uint8_t *)(&config);
for (int i = 0; i < sizeof(config); i++)
{
*(p + i) = EEPROM.read(i);
}
if (config.flag != 1)
{
printMsg("flash暂无数据");
return;
}
// wifi名称
if (strlen(config.stassid) != 0)
{
wifiSsid = (char *)malloc(32 * sizeof(char));
strcpy(wifiSsid, config.stassid);
}
// wifi密码
if (strlen(config.stapsw) != 0)
{
wifiPwd = (char *)malloc(64 * sizeof(char));
strcpy(wifiPwd, config.stapsw);
}
// 设备编号
if (strlen(config.deviceNum) != 0)
{
deviceNum = (char *)malloc(32 * sizeof(char));
strcpy(deviceNum, config.deviceNum);
}
// 用户编号
if (strlen(config.userId) != 0)
{
userId = (char *)malloc(16 * sizeof(char));
strcpy(userId, config.userId);
}
// 授权码
if (strlen(config.authCode) != 0)
{
authCode = (char *)malloc(32 * sizeof(char));
strcpy(authCode, config.authCode);
}
// 统一设置Mqtt消息主题前缀
prefix = "/" + (String)productId + "/" + (String)deviceNum;
}
// 清空配置
void clearConfig()
{
EEPROM.begin(240);
for (int i = 0; i < 240; i++)
{
EEPROM.write(i, 0);
}
EEPROM.end();
}
//打印提示信息
void printMsg(String msg)
{
Serial.print("\r\n[");
Serial.print(millis());
Serial.print("ms]");
Serial.print(msg);
}
// 控制指示灯闪烁
void blink()
{
printMsg("指示灯闪烁...");
pinMode(LED, OUTPUT);
for (int i = 0; i < 2; i++)
{
digitalWrite(LED, HIGH);
delay(100);
digitalWrite(LED, LOW);
delay(100);
}
}
// 控制指示灯状态
void ledStatus(bool status)
{
printMsg("更改指示灯状态");
pinMode(LED, OUTPUT);
if (status)
{
digitalWrite(LED, HIGH);
}
else
{
digitalWrite(LED, LOW);
}
}

View File

@@ -0,0 +1,88 @@
/*********************************************************************
* function 设备配置和系统功能
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "Apconfig.h"
#include "Base64.h"
#include <ESP8266WiFi.h>
#include <EEPROM.h>
#include <PubSubClient.h> // 版本2.8.0
#include <ArduinoJson.h> // 版本6.19.1
// 存储的配置类型结构
struct config_type
{
char flag; // 是否有数据标识等于1表示有数据
char stassid[32]; // SSID配置项
char stapsw[64]; // Password配置项
char deviceNum[32]; // 设备编号配置项
char userId[16]; // 用户ID配置项
char authCode[32]; // 授权码配置项
};
extern WiFiClient wifiClient;
extern PubSubClient mqttClient;
// 全局变量
extern char *deviceNum; // 设备编号重要同时是Mqtt的clientId
extern char *userId; // 用户ID
extern char *productId; // 产品ID
extern float rssi; // 信号强度信号极好4格[-55— 0]信号好3格[-70— -55]信号一般2格[-85— -70]信号差1格[-100— -85]
extern float firmwareVersion; // 固件版本
extern float latitude; // 设备精度
extern float longitude; // 设备维度
extern char *wifiSsid; // WIFI的SSID
extern char *wifiPwd; // WIFI的密码
extern char *mqttHost; // Mqtt消息服务器地址
extern int mqttPort; // Mqtt消息服务器端口
extern char *mqttUserName; // Mqtt消息服务器账号
extern char *mqttPwd; // Mqtt消息服务器密码
extern char mqttSecret[17]; // Mqtt秘钥,16位
extern char wumei_iv[17]; // AES加密偏移量固定值16位
extern char *authCode; // 产品授权码,产品未启用时为空字符串
extern String ntpServer; // NTP服务地址用于获取当前时间
extern int monitorCount; // 发布监测数据的最大次数
extern long monitorInterval; // 发布监测数据的间隔默认1000毫秒
extern bool isApMode; // 是否进入AP配网模式
// 订阅的主题
extern String prefix; // Mqtt消息主题前缀
extern String sInfoTopic; // 订阅设备信息
extern String sOtaTopic; // 订阅OTA升级
extern String sNtpTopic; // 订阅NTP时间
extern String sPropertyTopic; // 订阅属性
extern String sFunctionTopic; // 订阅功能
extern String sPropertyOnline; // 订阅属性-在线模式
extern String sFunctionOnline; // 订阅功能-在线模式
extern String sMonitorTopic; // 订阅实时监测
// 发布的主题
extern String pInfoTopic; // 发布设备信息
extern String pNtpTopic; // 发布NTP时间
extern String pPropertyTopic; // 发布属性
extern String pFunctionTopic; // 发布功能
extern String pMonitorTopic; // 发布实时监测数据
extern String pEventTopic; // 发布事件
// 连接WIFI
void connectWifi();
// 加载配置
void loadConfig();
// 保存配置
void saveConfig(config_type config);
// 清空配置
void clearConfig();
//打印提示信息
void printMsg(String msg);
// 控制指示灯闪烁
void blink();
// 控制指示灯状态
void ledStatus(bool status);
#endif

View File

@@ -0,0 +1,94 @@
/*********************************************************************
* function 设备交互
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#include "Mqtt.h"
// 订阅系统主题
void subscribeTopic()
{
mqttClient.subscribe((prefix + sInfoTopic).c_str(), 1);
mqttClient.subscribe((prefix + sOtaTopic).c_str(), 1);
mqttClient.subscribe((prefix + sNtpTopic).c_str(), 1);
mqttClient.subscribe((prefix + sPropertyTopic).c_str(), 1);
mqttClient.subscribe((prefix + sFunctionTopic).c_str(), 1);
mqttClient.subscribe((prefix + sPropertyOnline).c_str(), 1);
mqttClient.subscribe((prefix + sFunctionOnline).c_str(), 1);
mqttClient.subscribe((prefix + sMonitorTopic).c_str(), 1);
printMsg("订阅主题完成");
}
// 1.发布设备信息
void publishInfo()
{
StaticJsonDocument<256> doc;
doc["rssi"] = WiFi.RSSI();
doc["firmwareVersion"] = firmwareVersion;
doc["status"] = 3; // 1-未激活2-禁用3-在线4-离线)
doc["userId"] = (String)userId;
doc["longitude"] = longitude; //经度 可选
doc["latitude"] = latitude; // 纬度 可选
// 设备摘要,可选(自定义配置信息)
JsonObject summary = doc.createNestedObject("summary");
summary["name"] = "wumei-smart";
summary["chip"] = "esp8266";
summary["author"] = "kerwincui";
summary["version"] = 1.6;
summary["create"] = "2022-06-06";
printMsg("发布设备信息:");
serializeJson(doc, Serial);
String output;
serializeJson(doc, output);
printMsg("主题为:" + prefix + pInfoTopic);
mqttClient.publish((prefix + pInfoTopic).c_str(), output.c_str());
}
// 2.发布时钟同步信,用于获取当前时间(可选)
void publishNtp()
{
StaticJsonDocument<128> doc;
doc["deviceSendTime"] = millis();
printMsg("发布主题:" + prefix + pNtpTopic);
printMsg("信息:");
serializeJson(doc, Serial);
String output;
serializeJson(doc, output);
mqttClient.publish((prefix + pNtpTopic).c_str(), output.c_str());
}
// 3.发布属性
void publishProperty(String msg)
{
printMsg("发布属性:" + prefix + pPropertyTopic);
printMsg("消息:" + msg);
mqttClient.publish((prefix + pPropertyTopic).c_str(), msg.c_str());
}
// 4.发布功能
void publishFunction(String msg)
{
printMsg("发布功能:" + prefix + pFunctionTopic);
printMsg("消息:" + msg);
mqttClient.publish((prefix + pFunctionTopic).c_str(), msg.c_str());
}
// 5.发布事件
void publishEvent(String msg)
{
printMsg("发布事件:" + prefix + pEventTopic);
printMsg("消息:" + msg);
mqttClient.publish((prefix + pEventTopic).c_str(), msg.c_str());
}
// 6.发布实时监测数据
void publishMonitor(String msg)
{
// 发布实时监测数据(不会存储,需要实时存储则发布为属性)
printMsg("发布实时监测消息:" + msg);
mqttClient.publish((prefix + pMonitorTopic).c_str(), msg.c_str());
}

View File

@@ -0,0 +1,29 @@
/*********************************************************************
* function 设备交互
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#ifndef _MQTT_H
#define _MQTT_H
#include "Config.h"
// 订阅系统主题
void subscribeTopic();
// 发布设备信息
void publishInfo();
// 发布时钟同步信息
void publishNtp();
// 发布事件
void publishEvent(String msg);
// 发布实时监测数据(不会存储,需要实时存储则发布属性)
void publishMonitor(String msg);
// 发布属性
void publishProperty(String msg);
// 发布功能
void publishFunction(String msg);
#endif

View File

@@ -0,0 +1,296 @@
/*********************************************************************
* function 用户自定义功能
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#include "User.h"
#define BUTTON 14 // 按键引脚
#define RELAY 12 // 继电器引脚
OneButton button;
// 按钮单击事件
static void buttonClick();
// 按钮双击事件
static void buttonDoubleClick();
// 按钮长按事件
static void buttonLongPress();
// 初始化用户配置
void initUser()
{
// 初始化按键为低电平,并添加单击、双击、长按事件
button = OneButton(BUTTON, true, true);
button.attachClick(buttonClick);
button.attachDoubleClick(buttonDoubleClick);
button.attachLongPressStart(buttonLongPress);
}
// Mqtt回调
void mqttCallback(char *topic, byte *payload, unsigned int length)
{
blink();
printMsg("接收数据:");
String data = "";
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
data += (char)payload[i];
}
if (strcmp(topic, (prefix + sOtaTopic).c_str()) == 0)
{
printMsg("订阅到设备升级指令...");
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
String newVersion = doc["version"];
String downloadUrl = doc["downloadUrl"];
printMsg("固件版本:" + newVersion);
printMsg("下载地址:" + downloadUrl);
}
else if (strcmp(topic, (prefix + sInfoTopic).c_str()) == 0)
{
printMsg("订阅到设备信息...");
// 发布设备信息
publishInfo();
}
else if (strcmp(topic, (prefix + sNtpTopic).c_str()) == 0)
{
printMsg("订阅到NTP时间...");
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
// 计算设备当前时间:(${serverRecvTime} + ${serverSendTime} + ${deviceRecvTime} - ${deviceSendTime}) / 2
float deviceSendTime = doc["deviceSendTime"];
float serverSendTime = doc["serverSendTime"];
float serverRecvTime = doc["serverRecvTime"];
float deviceRecvTime = millis();
float now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2;
printMsg("当前时间:" + String(now, 0));
}
else if (strcmp(topic, (prefix + sPropertyTopic).c_str()) == 0 || strcmp(topic, (prefix + sPropertyOnline).c_str()) == 0)
{
printMsg("订阅到属性指令...");
processProperty(data);
}
else if (strcmp(topic, (prefix + sFunctionTopic).c_str()) == 0 || strcmp(topic, (prefix + sFunctionOnline).c_str()) == 0)
{
printMsg("订阅到功能指令...");
processFunction(data);
}
else if (strcmp(topic, (prefix + sMonitorTopic).c_str()) == 0)
{
printMsg("订阅到实时监测指令...");
StaticJsonDocument<128> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
monitorCount = doc["count"];
monitorInterval = doc["interval"];
}
}
// 随机生成监测值
String randomPropertyData()
{
// 匹配云端定义的监测数据,随机数代替监测值
float randFloat = 0;
int randInt = 0;
StaticJsonDocument<1024> doc;
JsonObject objTmeperature = doc.createNestedObject();
objTmeperature["id"] = "temperature";
randFloat = random(1000, 3000);
objTmeperature["value"] = (String)(randFloat / 100);
objTmeperature["remark"] = (String)millis();
JsonObject objHumidity = doc.createNestedObject();
objHumidity["id"] = "humidity";
randFloat = random(3000, 6000);
objHumidity["value"] = (String)(randFloat / 100);
objHumidity["remark"] = (String)millis();
JsonObject objCo2 = doc.createNestedObject();
objCo2["id"] = "co2";
randInt = random(400, 1000);
objCo2["value"] = (String)(randInt);
objCo2["remark"] = (String)millis();
JsonObject objBrightness = doc.createNestedObject();
objBrightness["id"] = "brightness";
randInt = random(1000, 10000);
objBrightness["value"] = (String)(randInt);
objBrightness["remark"] = (String)millis();
printMsg("模拟监测数据值:");
serializeJson(doc, Serial);
String output;
serializeJson(doc, output);
return output;
}
// 物模型-属性处理
void processProperty(String msg)
{
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, msg);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
for (JsonObject object : doc.as<JsonArray>())
{
// 匹配云端定义的属性(不包含属性中的监测数据)
const char *id = object["id"];
const char *value = object["value"];
printMsg((String)id + "" + (String)value);
}
// 最后发布属性,服务端订阅存储(重要)
publishProperty(msg);
}
// 物模型-功能处理
void processFunction(String msg)
{
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, msg);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
for (JsonObject object : doc.as<JsonArray>())
{
// 匹配云端定义的功能
const char *id = object["id"];
const char *value = object["value"];
if (strcmp(id, "switch") == 0)
{
printMsg("开关 switch" + (String)value);
if (strcmp(value, "1") == 0)
{
// 打开继电器
relayStatus(true);
}
else if (strcmp(value, "0") == 0)
{
// 关闭继电器
relayStatus(false);
}
}
else if (strcmp(id, "gear") == 0)
{
printMsg("档位 gear" + (String)value);
}
else if (strcmp(id, "light_color") == 0)
{
printMsg("灯光颜色 light_color" + (String)value);
}
else if (strcmp(id, "message") == 0)
{
printMsg("屏显消息 message" + (String)value);
}
else if (strcmp(id, "report_monitor") == 0)
{
String msg = randomPropertyData();
printMsg("订阅到上报监测数据指令,上报数据:");
printMsg(msg);
publishProperty(msg);
}
}
// 最后发布功能,服务端订阅存储(重要)
publishFunction(msg);
}
// 物模型-事件上传
void processEvent()
{
// 匹配云端的事件
StaticJsonDocument<512> doc;
JsonObject objTmeperature = doc.createNestedObject();
objTmeperature["id"] = "height_temperature";
objTmeperature["value"] = "40";
objTmeperature["remark"] = "温度过高警告";
JsonObject objException = doc.createNestedObject();
objException["id"] = "exception";
objException["value"] = "异常消息消息内容XXXXXXXX";
objException["remark"] = "设备发生错误";
printMsg("发布事件:");
serializeJson(doc, Serial);
String output;
serializeJson(doc, output);
// 最后发布功能,服务端订阅存储(重要)
publishEvent(output);
}
//打开继电器A
void relayStatus(bool status)
{
pinMode(RELAY, OUTPUT);
if (status)
{
digitalWrite(RELAY, HIGH);
}
else
{
digitalWrite(RELAY, LOW);
}
}
// 按钮单击事件
static void buttonClick()
{
printMsg("检测到按键单击,打开继电器");
relayStatus(true);
// 匹配云端定义的开关,格式如:[{"id":"switch","value":"1"}]
String msg = "[{\"id\":\"switch\",\"value\":\"1\"}]";
publishProperty(msg);
}
// 按钮双击事件
static void buttonDoubleClick()
{
printMsg("检测到按键双击,关闭继电器");
relayStatus(false);
// 匹配云端定义的开关,格式如:[{"id":"switch","value":"0"}]
String msg = "[{\"id\":\"switch\",\"value\":\"0\"}]";
publishProperty(msg);
}
// 按钮长按事件,进入配网模式
static void buttonLongPress()
{
printMsg("检测到按键长按");
if (isApMode)
{
printMsg("设备重启...");
ESP.restart();
}
else
{
printMsg("开始AP配网");
startApConfig();
}
}

View File

@@ -0,0 +1,33 @@
/*********************************************************************
* function 用户自定义功能
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#ifndef _USER_H
#define _USER_H
#include "Config.h"
#include "Mqtt.h"
#include <OneButton.h> // 版本2.0.4
extern OneButton button;
// 初始化用户配置
void initUser();
// Mqtt回调
void mqttCallback(char *topic, byte *payload, unsigned int length);
// 属性处理(物模型)
void processProperty(String msg);
// 功能处理(物模型)
void processFunction(String msg);
// 事件处理(无模型)
void processEvent();
// 模拟监测值
String randomPropertyData();
// 控制继电器状态
void relayStatus(bool status);
#endif

View File

@@ -0,0 +1,149 @@
/*********************************************************************
* function 程序入口
* board: esp8266 core for arduino v3.0.2
* library PubSubClient2.8.0 & ArduinoJson6.19.1 & OneButton2.0.4
* source: https://gitee.com/kerwincui/wumei-smart
* copyright: wumei-smart and kerwincui all rights reserved.
********************************************************************/
#include "Config.h"
#include "Auth.h"
#include "Apconfig.h"
#include "User.h"
long lastWifiConn; // 上次wifi连接时间
long lastMqttConn; // 上次mqtt连接时间
long lastPublishMonitor; // 上次发布监测数据时间
long lastPublishSimulateData; // 上次发布测试数据时间
/**
* 启动
*/
void setup()
{
//打开串行端口:
Serial.begin(115200);
printMsg("wumei smart device starting...");
// 加载配置
loadConfig();
// 初始化用户配置
initUser();
if (strcmp(wifiSsid, "") == 0)
{
// 启动配网
startApConfig();
}
else
{
// 连接Wifi
connectWifi();
}
}
/**
* 循环执行
*/
void loop()
{
// 监测按钮
button.tick();
if (isApMode)
{
// 配网时的Web服务
server.handleClient();
}
else
{
// Wifi重连
wifiReconnectionClient();
// Mqtt连接
mqttReconnectionClient();
// 发布实时监测数据
publicMonitorClient();
// 发布模拟数据,测试用
publishSimulateDataClient();
}
}
/*
* Wifi掉线重连(非阻塞间隔5s)
*/
void wifiReconnectionClient()
{
long now = millis();
if (WiFi.status() != WL_CONNECTED)
{
if (now - lastWifiConn > 5000)
{
lastWifiConn = now;
WiFi.reconnect();
}
}
}
/*
* mqtt连接(非阻塞、间隔5s)
*/
void mqttReconnectionClient()
{
if (WiFi.status() == WL_CONNECTED)
{
long now = millis();
if (!mqttClient.connected())
{
if (now - lastMqttConn > 5000)
{
lastMqttConn = now;
connectMqtt();
}
}
else
{
mqttClient.loop();
}
}
}
/*
* 发布实时监测数据非阻塞、间隔默认1秒
*/
void publicMonitorClient()
{
if (WiFi.status() == WL_CONNECTED && monitorCount > 0)
{
long now = millis();
if (now - lastPublishMonitor > monitorInterval)
{
lastPublishMonitor = now;
monitorCount--;
String msg = randomPropertyData();
publishMonitor(msg);
}
}
}
/*
* 发布模拟数据非阻塞、仅用于测试间隔60秒
*/
void publishSimulateDataClient()
{
if (WiFi.status() == WL_CONNECTED)
{
long now = millis();
if (now - lastPublishSimulateData > 60000)
{
lastPublishSimulateData = now;
printMsg("执行定时上报");
// 发布事件
processEvent();
// 发布时钟同步
publishNtp();
// 发布属性(监测值)
String msg = randomPropertyData();
publishProperty(msg);
}
}
}

0
sdk/ESP-IDF/README.md Normal file
View File

51
sdk/RaspberryPi/README.md Normal file
View File

@@ -0,0 +1,51 @@
## 硬件端树莓派SDK说明
#### 一、运行环境
- Python 3.7.2 (其他python3的版本一般也可以)
- 开发板树莓派4b没有加入硬件相关代码安装好python3环境win下linux下都能运行
- 库 需要安装库
1. mqtt库
```
pip install paho-mqtt
```
2. ase加密库
```
# 前面两个卸载命令是为了防止一些安装环境问题
pip uninstall crypto
pip uninstall pycryptodome
pip install pycryptodome
```
3. 报错缺少xx库命令
```
pip install xx
```
#### 二、运行程序
```
python3 main_sdk.py
# 备注程序运行依赖aes.py文件保证该文件和main_sdk.py在同一目录
```
#### 三、开发参考资料:
- [Eclipse Paho MQTT Python Client 使用手册](https://www.cooooder.com/archives/20210303)
- [Python 实现AES加密](https://zhuanlan.zhihu.com/p/261694311)
- [python实现AES加密解密](https://blog.csdn.net/chouzhou9701/article/details/122019967)
- [使用python time()方法](http://www.py.cn/jishu/jichu/20424.html)
- [python 线程定时器Timer](https://zhuanlan.zhihu.com/p/91412537)
- [浅谈Python的格式化输出](https://www.jb51.net/article/225609.htm)
- [Python Request库入门](https://www.jianshu.com/p/d78982126318)
- [Python JSON ](https://www.runoob.com/python/python-json.html)
- [Python random() 函数 ](https://www.runoob.com/python/func-number-random.html)

210
sdk/RaspberryPi/aes.py Normal file
View File

@@ -0,0 +1,210 @@
from Crypto.Cipher import AES
import base64
import binascii
# 数据类
class MData():
def __init__(self, data = b"",characterSet='utf-8'):
# data肯定为bytes
self.data = data
self.characterSet = characterSet
def saveData(self,FileName):
with open(FileName,'wb') as f:
f.write(self.data)
def fromString(self,data):
self.data = data.encode(self.characterSet)
return self.data
def fromBase64(self,data):
self.data = base64.b64decode(data.encode(self.characterSet))
return self.data
def fromHexStr(self,data):
self.data = binascii.a2b_hex(data)
return self.data
def toString(self):
return self.data.decode(self.characterSet)
def toBase64(self):
return base64.b64encode(self.data).decode() #decode()转成字符串形式,否则为字节型数据
def toHexStr(self):
return binascii.b2a_hex(self.data).decode()
def toBytes(self):
return self.data
def __str__(self):
try:
return self.toString()
except Exception:
return self.toBase64()
### 封装类
class AEScryptor():
def __init__(self,key,mode,iv = '',paddingMode= "NoPadding",characterSet ="utf-8"):
'''
构建一个AES对象
key: 秘钥,字节型数据
mode: 使用模式只提供两种AES.MODE_CBC, AES.MODE_ECB
iv iv偏移量字节型数据
paddingMode: 填充模式默认为NoPadding, 可选NoPaddingZeroPaddingPKCS5PaddingPKCS7Padding
characterSet: 字符集编码
'''
self.key = key
self.mode = mode
self.iv = iv
self.characterSet = characterSet
self.paddingMode = paddingMode
self.data = ""
def __ZeroPadding(self,data):
data += b'\x00'
while len(data) % 16 != 0:
data += b'\x00'
return data
def __StripZeroPadding(self,data):
data = data[:-1]
while len(data) % 16 != 0:
data = data.rstrip(b'\x00')
if data[-1] != b"\x00":
break
return data
def __PKCS5_7Padding(self,data):
needSize = 16-len(data) % 16
if needSize == 0:
needSize = 16
return data + needSize.to_bytes(1,'little')*needSize
def __StripPKCS5_7Padding(self,data):
paddingSize = data[-1]
return data.rstrip(paddingSize.to_bytes(1,'little'))
def __paddingData(self,data):
if self.paddingMode == "NoPadding":
if len(data) % 16 == 0:
return data
else:
return self.__ZeroPadding(data)
elif self.paddingMode == "ZeroPadding":
return self.__ZeroPadding(data)
elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding":
return self.__PKCS5_7Padding(data)
else:
print("不支持Padding")
def __stripPaddingData(self,data):
if self.paddingMode == "NoPadding":
return self.__StripZeroPadding(data)
elif self.paddingMode == "ZeroPadding":
return self.__StripZeroPadding(data)
elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding":
return self.__StripPKCS5_7Padding(data)
else:
print("不支持Padding")
def setCharacterSet(self,characterSet):
'''
设置字符集编码
characterSet: 字符集编码
'''
self.characterSet = characterSet
def setPaddingMode(self,mode):
'''
设置填充模式
mode: 可选NoPaddingZeroPaddingPKCS5PaddingPKCS7Padding
'''
self.paddingMode = mode
def decryptFromBase64(self,entext):
'''
从base64编码字符串编码进行AES解密
entext: 数据类型str
'''
mData = MData(characterSet=self.characterSet)
self.data = mData.fromBase64(entext)
return self.__decrypt()
def decryptFromHexStr(self,entext):
'''
从hexstr编码字符串编码进行AES解密
entext: 数据类型str
'''
mData = MData(characterSet=self.characterSet)
self.data = mData.fromHexStr(entext)
return self.__decrypt()
def decryptFromString(self,entext):
'''
从字符串进行AES解密
entext: 数据类型str
'''
mData = MData(characterSet=self.characterSet)
self.data = mData.fromString(entext)
return self.__decrypt()
def decryptFromBytes(self,entext):
'''
从二进制进行AES解密
entext: 数据类型bytes
'''
self.data = entext
return self.__decrypt()
def encryptFromString(self,data):
'''
对字符串进行AES加密
data: 待加密字符串数据类型为str
'''
self.data = data.encode(self.characterSet)
return self.__encrypt()
def __encrypt(self):
if self.mode == AES.MODE_CBC:
aes = AES.new(self.key,self.mode,self.iv)
elif self.mode == AES.MODE_ECB:
aes = AES.new(self.key,self.mode)
else:
print("不支持这种模式")
return
data = self.__paddingData(self.data)
enData = aes.encrypt(data)
return MData(enData)
def __decrypt(self):
if self.mode == AES.MODE_CBC:
aes = AES.new(self.key,self.mode,self.iv)
elif self.mode == AES.MODE_ECB:
aes = AES.new(self.key,self.mode)
else:
print("不支持这种模式")
return
data = aes.decrypt(self.data)
# mData = MData(self.__stripPaddingData(data),characterSet=self.characterSet)
# return mData()
return MData(self.__stripPaddingData(data),characterSet=self.characterSet)
if __name__ == '__main__':
key = b"1234567812345678"
iv = b"0000000000000000"
aes = AEScryptor(key,AES.MODE_CBC,iv,paddingMode= "ZeroPadding",characterSet='utf-8')
data = "好好学习"
rData = aes.encryptFromString(data)
print("密文:",rData.toBase64())
rData = aes.decryptFromBase64(rData.toBase64())
print("明文:",rData)
# ————————————————
# 版权声明本文为CSDN博主「Hello_wshuo」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。
# 原文链接https://blog.csdn.net/chouzhou9701/article/details/122019967

351
sdk/RaspberryPi/main_sdk.py Normal file
View File

@@ -0,0 +1,351 @@
# /***********************************************************
# * author: xiaoY [物美智能 wumei-smart]
# * create: 2022-05-10
# * emailqimint@outlook.com
# * source:https://github.com/kerwincui/wumei-smart
# * board:raspberry 4b
# ***********************************************************/
import time
import requests
import json
from aes import AEScryptor,AES
import paho.mqtt.client as mqtt
import random
import threading #导入线程模块,用作定时器
#################################################################
# 需要连接好外部网络
#################################################################
# 作为python的AES的iv,应该为16位字节型数据
wumei_iv = b"wumei-smart-open"
#发布监测数据的最大次数
monitorCount =5
# 发布监测数据的间隔默认5秒。 使用esp8266单片机时服务器传来的间隔单位为毫秒本程序由于定时运行需要的是秒将转化为秒如需毫秒运行自行更改程序
monitorInterval =5
# NTP地址用于获取时间,可选的修改为自己部署项目的地址)
ntpServer = "http://120.24.218.158:8080/iot/tool/ntp?deviceSendTime="
# 连接成功标志位
g_rc=-1
#全局变量,管理定时监测
global t2
# 设备信息配置
deviceNum = "DW43CI6RM8GMG23H"
userId = "1"
productId = "4"
firmwareVersion = "1.0"
# 经度和纬度可选,如果产品使用设备定位,则必须传
latitude=0
longitude=0
# Mqtt配置
mqttHost = "120.24.218.158"
mqttPort = 1883
mqttUserName = "wumei-smart"
mqttPwd = "P261I5G3RY3MCIGG"
# 作为python的AES的key,应该为16位字节型数据
mqttSecret = b"K2IB784BM0O01GG6"
# 产品启用授权码则authCode不能为空
authCode=""
# 订阅的主题
prefix = "/" + productId + "/" + deviceNum
sInfoTopic = prefix + "/info/get"
sOtaTopic = prefix + "/ota/get"
sNtpTopic = prefix + "/ntp/get"
sPropertyTopic = prefix + "/property/get"
sFunctionTopic = prefix + "/function/get"
sPropertyOnline = prefix + "/property-online/get"
sFunctionOnline = prefix + "/function-online/get"
sMonitorTopic = prefix + "/monitor/get"
# 发布的主题
pInfoTopic = prefix + "/info/post"
pNtpTopic = prefix + "/ntp/post"
pPropertyTopic = prefix + "/property/post"
pFunctionTopic = prefix + "/function/post"
pMonitorTopic = prefix + "/monitor/post"
pEventTopic = prefix + "/event/post"
# 初始化,连接 设备mqtt客户端Id格式为认证类型(E=加密、S=简单) & 设备编号 & 产品ID & 用户ID
clientId = "E&" + deviceNum + "&" + productId +"&" + userId
client=mqtt.Client(clientId)
#加密 (AES-CBC-128-pkcs5padding)
def encrypt(plain_data,wumei_key,wumei_iv):
aes=AEScryptor(wumei_key,AES.MODE_CBC,wumei_iv,paddingMode="PKCS5Padding",characterSet='utf-8')
rData=aes.encryptFromString(plain_data)
printMsg("密码(已加密)"+rData.toBase64())
return rData.toBase64()
#回调函数。当尝试与MQTT broker 建立连接时,触发该函数。
#client 是本次连接的客户端实例。
#userdata 是用户的信息,一般为空。但如果有需要,也可以通过 user_data_set 函数设置。
#flags 保存服务器响应标志的字典
#rc 是响应码。
# 0: 连接成功
# 1: 连接失败-不正确的协议版本
# 2: 连接失败-无效的客户端标识符
# 3: 连接失败-服务器不可用
# 4: 连接失败-错误的用户名或密码
# 5: 连接失败-未授权
# 6-255: 未定义.
#一般情况下我们只需要关注rc响应码是否为0就可以了。
def on_connect(client,userdata,flags,rc):
if rc==0:
printMsg("连接成功")
# 放在on_connect下可以保证重连重新订阅
# 订阅(OTA、NTP、属性、功能、实时监测)
client.subscribe(sInfoTopic, 1)
client.subscribe(sOtaTopic, 1)
client.subscribe(sNtpTopic, 1)
client.subscribe(sPropertyTopic, 1)
client.subscribe(sFunctionTopic, 1)
client.subscribe(sPropertyOnline, 1)
client.subscribe(sFunctionOnline, 1)
client.subscribe(sMonitorTopic, 1)
printMsg("订阅主题:" + sInfoTopic)
printMsg("订阅主题:" + sOtaTopic)
printMsg("订阅主题:" + sNtpTopic)
printMsg("订阅主题:" + sPropertyTopic)
printMsg("订阅主题:" + sFunctionTopic)
printMsg("订阅主题:" + sPropertyOnline)
printMsg("订阅主题:" + sFunctionOnline)
printMsg("订阅主题:" + sMonitorTopic)
# 发布设备信息
publishInfo()
global g_rc
g_rc=0
else:
printMsg("连接失败rc="+str(rc))
printMsg("3秒后重连...")
time.sleep(3)
connectMqtt()
# 物模型-属性处理
def processProperty(payload):
data=json.loads(payload)
for item in data:
# 匹配云端定义的属性(不包含属性中的监测数据)
id = item["id"]
value=item["value"]
printMsg(str(id)+":"+str(value))
# 最后发布属性,服务端订阅存储(重要)
publishProperty(json.dumps(data))
# 物模型-功能处理
def processFunction(payload):
data=json.loads(payload)
for item in data:
# 匹配云端定义的功能
id = item["id"]
value=item["value"]
if(id=="switch"):
printMsg("开关 switch"+ str(value))
elif(id=="gear"):
printMsg("档位 gear"+ str(value))
elif(id=="light_color"):
printMsg("灯光颜色 light_color"+ str(value))
elif(id=="message"):
printMsg("屏显消息 message"+ str(value))
elif(id=="report_monitor"):
msg=randomPropertyData();
printMsg("订阅到上报监测数据指令,上报数据:")
printMsg(msg)
publishProperty(msg)
# 最后发布属性,服务端订阅存储(重要)
publishProperty(json.dumps(data))
# 回调函数在客户端订阅的主题上接收到消息时调用“message”变量是一个MQTT消息描述所有消息特征
def on_message(client,userdata,msg):
printMsg("接收数据:"+msg.topic+" "+str(msg.payload))
if(msg.topic==sOtaTopic):
printMsg("订阅到设备升级指令...")
jsonData=json.loads(msg.payload)
newVersion = jsonData["version"]
downloadUrl = jsonData["downloadUrl"]
printMsg("固件版本:"+newVersion)
printMsg("下载地址:"+downloadUrl)
elif(msg.topic==sInfoTopic):
printMsg("订阅到设备信息指令...")
# 发布设备信息
publishInfo()
elif(msg.topic==sNtpTopic):
printMsg("订阅到NTP时间...");
jsonData=json.loads(msg.payload)
deviceSendTime = jsonData["deviceSendTime"]
serverSendTime = jsonData["serverSendTime"]
serverRecvTime = jsonData["serverRecvTime"]
deviceRecvTime = round(time.time()*1000)
now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2
printMsg("当前时间:"+str(round(now)))
elif(msg.topic==sPropertyTopic or msg.topic==sPropertyOnline):
printMsg("订阅到属性指令...")
processProperty(msg.payload)
elif(msg.topic==sFunctionTopic or msg.topic==sFunctionOnline):
printMsg("订阅到功能指令...")
processFunction(msg.payload)
elif(msg.topic==sMonitorTopic):
# python全局变量的使用
global t2
global monitorCount
global monitorInterval
printMsg("订阅到实时监测指令...")
jsonData=json.loads(msg.payload)
monitorCount = jsonData["count"]
monitorInterval = jsonData["interval"]/1000
t2.cancel()
t2=threading.Timer(monitorInterval,timing_publishMonitor)
t2.start()
# 1.发布设备信息
def publishInfo():
# rssi值 树莓派中暂时不处理wifi信号问题
# 信号强度信号极好4格[-55— 0]信号好3格[-70— -55]信号一般2格[-85— -70]信号差1格[-100— -85]
# status值 1-未激活2-禁用3-在线4-离线)
doc={"rssi":1,"firmwareVersion":firmwareVersion,"status":3,"userId":userId,"longitude":longitude,"latitude":latitude,"summary":{"name":"device","chip":"esp8266","author":"kerwincui","version":1.6,"create":"2022 - 06 - 06"}}
# client.publish('raspberry/topic',payload=i,qos=0,retain=False)
jsonData=json.dumps(doc)
printMsg("发布设备信息:"+pInfoTopic+" "+jsonData)
client.publish(pInfoTopic,jsonData)
# 2.发布时钟同步信,用于获取当前时间(可选)
def publishNtp():
data={"deviceSendTime":round(time.time()*1000)}
jsonData=json.dumps(data)
printMsg("发布NTP信息"+jsonData)
client.publish(pNtpTopic,jsonData)
# 3.发布属性
# msg 接收格式json
def publishProperty(msg):
printMsg("发布属性:" + msg)
client.publish(pPropertyTopic, msg)
# 4.发布功能
def publishFunction( msg):
printMsg("发布功能:" + msg)
client.publish(pFunctionTopic, msg)
# 5.发布事件
def publishEvent():
objTmeperature={"id":"height_temperature","value":40,"remark":"温度过高警告"}
objException={"id":"exception","value":"异常消息消息内容XXXXXXXX","remark":"设备发生错误"}
data=[objTmeperature,objException]
jsonData=json.dumps(data)
printMsg("发布事件:"+jsonData)
client.publish(pEventTopic,jsonData)
# 6.发布实时监测数据
def publishMonitor():
msg=randomPropertyData()
# 发布为实时监测数据,不会存储
printMsg("发布实时监测数据:"+msg)
client.publish(pMonitorTopic,msg)
# 随机生成监测值
def randomPropertyData():
# 匹配云端定义的监测数据,随机数代替监测结果
# random.randint(0,10) #生成数据包括0,10
# random.uniform(30,60)生成数据为浮点型
objTmeperature={"id":"temperature","value":str(round(random.uniform(10,30),2)),"remark":""}
objHumidity={"id":"humidity","value":str(round(random.uniform(30,60),2)),"remark":""}
objCo2={"id":"co2","value":str(random.randint(400,1000)),"remark":""}
objBrightness={"id":"brightness","value":str(random.randint(1000,10000)),"remark":""}
printMsg("随机生成监测数据值:")
data=[objTmeperature,objHumidity,objCo2,objBrightness]
print(json.dumps(data))
return json.dumps(data)
#连接mqtt
def connectMqtt():
printMsg("连接Mqtt服务器")
# 生成mqtt认证密码(设备加密认证密码加密格式为mqtt密码 & 过期时间 & 授权码,其中授权码为可选)
password = generationPwd()
encryptPassword=encrypt(password,mqttSecret,wumei_iv)
client.username_pw_set(mqttUserName,encryptPassword)
client.on_connect=on_connect
client.on_message=on_message
client.connect(mqttHost,mqttPort,10)
#打印提示信息
def printMsg(msg):
print("[{}] {}".format(time.strftime("%Y-%m-%d %H:%M:%S"),msg))
# 生成密码
def generationPwd():
try:
doc=json.loads(getTime())
except:
printMsg("Json解析失败")
exit()
deviceSendTime = doc["deviceSendTime"]
serverSendTime = doc["serverSendTime"]
serverRecvTime = doc["serverRecvTime"]
deviceRecvTime = round(time.time()*1000)
now = (serverSendTime + serverRecvTime + deviceRecvTime - deviceSendTime) / 2
expireTime = int(now + 1 * 60 * 60 * 1000)
# 密码加密格式为mqtt密码 & 过期时间 & 授权码(可选),如果产品启用了授权码就必须加上
password=""
if(authCode == ""):
password = mqttPwd + "&" + str(expireTime, 0)
else:
password = mqttPwd + "&" + str(expireTime, 0) + "&" + authCode
printMsg("密码(未加密):" + password)
return password
# HTTP获取时间
def getTime():
try:
r=requests.get(ntpServer+str(round(time.time()*1000)))
if(r.status_code>0):
if(r.status_code==200 or r.status_code==301):
printMsg("获取时间成功data:"+r.text)
return r.text
else:
printMsg("获取时间失败error:"+r.status_code)
except:
printMsg("连接Http失败")
# 定时上报属性
def timing_publishProperty():
printMsg("执行定时上报")
#发布事件
publishEvent()
#发布时钟同步
publishNtp()
# 发布属性(监测值)
msg=randomPropertyData()
publishProperty(msg)
t1=threading.Timer(60,timing_publishProperty)
t1.start()
# 定时上报监测数据
def timing_publishMonitor():
global monitorCount
monitorCount=monitorCount-1
printMsg("执行监测")
publishMonitor()
if(monitorCount>0):
t2=threading.Timer(monitorInterval,timing_publishMonitor)
t2.start()
if __name__ == '__main__':
connectMqtt()
client.loop_start()
printMsg("等待连接MQTT")
while(g_rc!=0):
print("-",end=" ")
time.sleep(1)
t1=threading.Timer(60,timing_publishProperty)
t1.setDaemon(True) #当主线程被关闭后,子线程也关闭
t1.start()
t2=threading.Timer(monitorInterval,timing_publishMonitor)
t2.setDaemon(True) #当主线程被关闭后,子线程也关闭
t2.start()
while True:
time.sleep(10) #定时上报、检测上报都是线程执行,主线程可以做自己的任务

View File

@@ -0,0 +1,26 @@
Eclipse Paho MQTT Python Client 使用手册
https://www.cooooder.com/archives/20210303
Python 实现AES加密
https://zhuanlan.zhihu.com/p/261694311
python实现AES加密解密
https://blog.csdn.net/chouzhou9701/article/details/122019967
使用python time()方法
http://www.py.cn/jishu/jichu/20424.html
python 线程定时器Timer
https://zhuanlan.zhihu.com/p/91412537
浅谈Python的格式化输出
https://www.jb51.net/article/225609.htm
Python Request库入门
https://www.jianshu.com/p/d78982126318
Python JSON
https://www.runoob.com/python/python-json.html
Python random() 函数
https://www.runoob.com/python/func-number-random.html

View File

@@ -1,3 +0,0 @@
{
"C_Cpp.errorSquiggles": "Disabled"
}

37
sdk/合宙/README.md Normal file
View File

@@ -0,0 +1,37 @@
## 硬件端合宙SDK说明
#### 一、运行环境
- vs code 仿真
- air724板子 在选择底层库pac文件时注意 支持float 类型
1. 在vs code 里面安装 luatIDE
2. 安装air724 usb 相关驱动
3. 使用luatools
以上均参考 https://doc.openluat.com/wiki/26?wiki_page_id=3063
#### 二、运行代码
1. 在vs code 下仿真调试
mainVscode.lua 复制为 main.lua
注释掉 WeiMeiApp.lua 里面与硬件相关的代码 如adc 温度等
在WuMeiTest.lua 文件里面 配置 产品ID MQTT 等信息
仿真调试
2. 在air724硬件上运行代码
mainAir724.lua 复制为 main.lua
取消 WeiMeiApp.lua 里面与硬件相关的代码注释 如adc 温度等
在WuMeiTest.lua 文件里面 配置 产品ID MQTT 等信息
用luatools 建立工程 需要加载 main.lua WeiMeiApp.lua WeiMeiComAuth.lua WeiMeiComInteraction.lua WuMeiTest.lua 文件 以及带float 类型的底层库
#### 三、代码文件说明
1. WeiMeiComAuth.lua 用于认证处理
支持 简单认证和加密认证
2. WeiMeiComInteraction.lua 用户交互
支持 信息 属性 功能 事件 监控
支持 设置定时上传 属性 功能 事件
3. WeiMeiApp.lua
主要开发在这个文件里面
对外提供 信息 属性 功能 事件 数据函数 改函数直接返回打包好的json 字符串

83
sdk/合宙/WeiMeiApp.lua Normal file
View File

@@ -0,0 +1,83 @@
--- 模块功能物美MQTT应用
-- @author 杜兴杰
-- @module 物美MQTT应用
-- @license MIT
-- @copyright 杜兴杰
-- @email 1066950103@qq.com
-- @release 2022.8.5
module(..., package.seeall)
local VERSION = "0.1"
local m_strUserId = "1"
local m_strLongitude = "0"
local m_strLatitude = "0"
local m_nTemperature = 25
--local m_nVoltval = 4.0
--模块温度返回回调函数
--@temp温度srting类型如果要对该值进行运算可以使用带float的固件将该值转为number
local function getTemperatureCb(temp)
m_nTemperature = temp
end
--- ADC读取测试
-- @return 无
-- @usage read()
local function read0()
--ADC0接口用来读取电压
local ADC_ID = 0
local adcval,voltval = adc.read(ADC_ID)
log.info("testAdc0.read",adcval,(voltval-(voltval%3))/3,voltval)
-- 输出计算得出的原始电压值
m_nVoltval = voltval/3 * 3127 / 1000
log.info("testAdc0.Vbat", m_nVoltval)
end
--2秒循环查询模块温度
sys.timerLoopStart(misc.getTemperature,1000,getTemperatureCb)
sys.timerLoopStart(read0,1000)
-- 开启对应的adc通道
adc.open(0)
function FunctionData()
local jsonStr = ""
end
function PropertyData()
local jsonData = {{
id= "temperature",
value= m_nTemperature ,
remark="温度信息"
},{
id= "voltage",
value= m_nVoltval,
remark="电压信息"
}}
local jsonStr = json.encode(jsonData)
return jsonStr
end
function InformationData()
local jsonData = {
rssi = net.getRssi(),
firmwareVersion = VERSION,
status = 3 ,
userId = m_strUserId ,
longitude = m_strLongitude ,
latitude = m_strLatitude,
summary = {
name= "device",
chip = "air724",
author = "duxingjie",
version=0.1,
create = "2022-08-07"
}
}
local jsonStr = json.encode(jsonData)
return jsonStr
end

View File

@@ -0,0 +1,175 @@
--- 模块功能物美MQTT认证
-- @author 杜兴杰
-- @module 物美MQTT通信
-- @license MIT
-- @copyright 杜兴杰
-- @email 1066950103@qq.com
-- @release 2022.8.4
module(..., package.seeall)
require"http"
require"utils"
require "common"
require"misc"
local m_strEncryptionMode
local m_strProductId
local m_strDeviceId
local m_strUserId
local m_strUser
local m_strPassword
local m_nTimeout
local m_strIp
local m_strDeviceAuthorizationCode = nil
local m_strProductPassword = nil
local m_InitCallback = nil
local m_strOutPassword
local m_strClientId
local m_nTimeSyncFlag
local function CreateCommunicationPassword()
if m_strEncryptionMode == "S" then
if nil == m_strDeviceAuthorizationCode then
m_strOutPassword = m_strPassword
else
m_strOutPassword = m_strPassword .. "&" .. m_strDeviceAuthorizationCode
end
return true
end
if m_strEncryptionMode == "E" then
m_strOutPassword = AesPassword()
return true
end
return false
end
local function Callback(nResult)
log.info("Callback" .. nResult)
if m_InitCallback ~= nil then
m_InitCallback(nResult)
end
end
local function ParameterCheck()
return true
end
local function FormatUnixTime2Date(unixTime)
if unixTime and unixTime >= 0 then
unixTime = unixTime /1000
local ntim = os.date("*t", unixTime)
return ntim
end
end
local function CreatedClientId()
m_strClientId = m_strEncryptionMode .. "&" .. m_strDeviceId .. "&" .. m_strProductId .. "&" .. m_strUserId
end
local function httpCallbackFun(result,prompt,head,body)
log.info("GetTimeHttp.cbFnc",result,prompt)
if result and body then
log.info("GetTimeHttp.cbFnc"..body.."bodyLen="..body:len())
local nDeviceRunTickMs = rtos.tick() * 5
local jsonObj = json.decode(body)
local nDeviceSendTime = jsonObj["deviceSendTime"]
local nServerSendTime = jsonObj["serverSendTime"]
local nServerRecvTime = jsonObj["serverRecvTime"]
local nSyncTime = (nServerRecvTime + nServerSendTime + nDeviceRunTickMs - nDeviceSendTime)/2
log.info("nSyncTime=" .. nSyncTime)
local tTime = FormatUnixTime2Date(nSyncTime)
log.info("tTime" .. tTime.year)
misc.setClock(tTime,nil)
--rtos.set_time(tTime.year,tTime.month,tTime.day,tTime.hour,tTime.min,tTime.sec)
--创建客户端ID
CreatedClientId()
--创建密码
CreateCommunicationPassword()
Callback(1)
m_nTimeSyncFlag = 1
end
end
function SyncTime()
local nDeviceRunTickMs = rtos.tick() * 5
local strUrl = "http://" .. m_strIp .. ":8080/iot/tool/ntp?deviceSendTime=" .. nDeviceRunTickMs
http.request("GET",strUrl,nil,nil,nil,nil,httpCallbackFun)
end
local function GetCurrentTime()
local tm = misc.getClock()
local nCurrentTime = os.time(tm)
return nCurrentTime
end
local function AesPassword()
local nCurrentTime = GetCurrentTime()
local nExpireTime = m_nTimeout + nCurrentTime
local strAesSource = nil
if nil == m_strDeviceAuthorizationCode then
strAesSource = m_strPassword .. "&" .. nExpireTime
else
strAesSource = m_strPassword .. "&" .. nExpireTime .. "&" .. m_strDeviceAuthorizationCode
end
--加密内容: mqtt密码 & expireTime & 授权码(可选)
--加密模式CBC填充方式Pkcs5Padding密钥1234567890123456密钥长度128 bit偏移量1234567890666666
encodeStr = crypto.aes_encrypt("CBC","PKCS5",strAesSource,m_strProductPassword,"wumei-smart-open")
log.info("AesPassword strAesSource" .. strAesSource .. " encodeStr " .. encodeStr )
encodeStr = crypto.base64_encode(encodeStr,slen(encodeStr))
log.info("AesPassword strAesSource" .. strAesSource .. " encodeStrbase64 " .. encodeStr )
return encodeStr
end
--- mqtt认证初始化
-- @string strEncryptionMode,string类型,认证类型S=简单认证E=加密认证
-- @string strProductId,string类型物美里面定义的产品ID
-- @string strDeviceId,string类型设备ID 一般用imei
-- @string strUserId,string类型用户ID
-- @string strUser,string类型用户
-- @string strPassword,string类型密码
-- @number nTimeout,number类型延迟秒为单位
-- @string strIp,string类型Ip
-- @string strDeviceAuthorizationCode,string类型 设备认证码 不用不填
-- @string strProductPassword,string类型 产品密码
-- @return nil
function Init(strEncryptionMode,strProductId,strDeviceId,strUserId,strUser,strPassword,nTimeout,strIp,strDeviceAuthorizationCode,strProductPassword,callback)
m_strEncryptionMode = strEncryptionMode
m_strProductId = strProductId
m_strDeviceId = strDeviceId
m_strUserId = strUserId
m_strUser = strUser
m_strPassword = strPassword
m_nTimeout = nTimeout
m_strIp = strIp
if nil == strDeviceAuthorizationCode then
m_strDeviceAuthorizationCode = strDeviceAuthorizationCode
end
if nil == strProductPassword then
m_strProductPassword = strProductPassword
end
m_nTimeSyncFlag = 0
m_InitCallback = callback
--if ParameterCheck() == false then
-- Callback(0)
-- end
SyncTime()
end
function GetUser()
return m_strUser
end
function GetPassword()
return m_strOutPassword
end
function GetClientId()
return m_strClientId
end
function GetIP()
return m_strIp
end

View File

@@ -0,0 +1,289 @@
--- 模块功能物美MQTT交互
-- @author 杜兴杰
-- @module 物美MQTT通信
-- @license MIT
-- @copyright 杜兴杰
-- @email 1066950103@qq.com
-- @release 2022.8.5
module(..., package.seeall)
local m_strProductId
local m_strDeviceNum
local m_tMessageQueue = {}
local m_callbackPropertyData = nil
local m_callbackFunctionData = nil
local m_callbackEventData = nil
local m_callbackDeviceInformationData = nil
local m_timePropertyId = 0
local m_timeFunctionId = 0
local m_timeEventId = 0
local m_nMonitorCount = 0
local m_nMonitorTime = 0
local m_timeMonitorId = 0
local function GetSubscriberDeviceInformation()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/info/get"
end
local function GetSubscriberDeviceInOta()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/ota/get"
end
local function GetSubscriberDeviceProperty()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/property/get"
end
local function GetSubscriberDevicePropertyOnline()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/property-online/get"
end
local function GetSubscriberDeviceFunction()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/function/get"
end
local function GetSubscriberDeviceFunctionOnline()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/function-online/get"
end
local function GetSubscriberDeviceMonitor()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/monitor/get"
end
local function GetSubscriberDeviceNtp()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/ntp/get"
end
local function GetPublishDeviceInformation()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/info/post"
end
local function GetPublishDeviceProperty()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/property/post"
end
local function GetPublishDeviceFunction()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/function/post"
end
local function GetPublishDeviceEvent()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/event/post"
end
local function GetPublishDeviceNtp()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/ntp/post"
end
local function GetPublishMonitorProperty()
return "/" .. m_strProductId .. "/" .. m_strDeviceNum .. "/monitor/post"
end
local function PropertyPush()
if m_callbackPropertyData ~= nil then
local strTopic = GetPublishDeviceProperty()
local strMessage = m_callbackPropertyData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
log.info("------------------PropertyPush---------------")
end
end
local function FunctionPush()
if m_callbackFunctionData ~= nil then
local strTopic = GetPublishDeviceFunction()
local strMessage = m_callbackFunctionData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
log.info("------------------FunctionPush---------------")
end
end
local function EventPush()
if m_callbackEventData ~= nil then
local strTopic = GetPublishDeviceEvent()
local strMessage = m_callbackEventData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
log.info("------------------EventPush---------------")
end
end
local function MonitorPush()
if m_callbackPropertyData ~= nil then
local strTopic = GetPublishMonitorProperty()
local strMessage = m_callbackPropertyData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
log.info("------------------MonitorPush---------------")
end
end
local function DeviceMonitorTimeCallback()
MonitorPush()
if m_nMonitorCount ~= 0 then
m_nMonitorCount = m_nMonitorCount -1
m_timeMonitorId = sys.timerStart(
DeviceMonitorTimeCallback
,m_nMonitorTime)
else
sys.timerStop(m_timeMonitorId)
m_timeMonitorId= 0
end
log.info("----m_nMonitorCount=" .. m_nMonitorCount)
end
local function DeviceInformationPush()
if m_callbackDeviceInformationData ~= nil then
local strTopic = GetPublishDeviceInformation()
local strMessage = m_callbackDeviceInformationData()
local nQos = 1
table.insert(m_tMessageQueue,{topic=strTopic,payload=strMessage,qosr=nQos})
end
end
--- mqtt交互初始化
-- @string strProductId,string类型,产品ID
-- @string strDeviceNum,string类型设备号 IMEI
-- @return nil
function Init(strProductId,strDeviceNum)
m_strProductId = strProductId
m_strDeviceNum = strDeviceNum
end
--- mqtt交互延时初始化
-- @return nil
function DelayInit()
DeviceInformationPush();
end
--- mqtt 获取待发送数据 一次取出一天且删除
-- @return bResult false 没有数据 true 有数据
-- @return strMessage 要发送的数据
-- @return strTopic 要发送的主题
-- @return nQos 发送消息级别
function GetData()
local bResult = false
local strMessage =""
local strTopic =""
local nQos = 0
if #m_tMessageQueue>0 then
local outMsg = table.remove(m_tMessageQueue,1)
bResult = true
strMessage = outMsg.payload
strTopic = outMsg.topic
nQos = outMsg.qosr
end
return bResult,strMessage,strTopic,nQos
end
--- mqtt 设置属性的获取获取函数,内部调用发送的时候会执行这个函数 这个函数外部实现
-- @function callback,函数类型, 数据函
function SetCallbackPropertyData(callback)
m_callbackPropertyData = callback
end
--- mqtt 设置功能的获取获取函数,内部调用发送的时候会执行这个函数 这个函数外部实现
-- @function callback,函数类型, 数据函
function SetCallbackFunctionData(callback)
m_callbackFunctionData = callback
end
--- mqtt 设置事件的获取获取函数,内部调用发送的时候会执行这个函数 这个函数外部实现
-- @function callback,函数类型, 数据函
function SetCallbackEventData(callback)
m_callbackEventData = callback
end
--- mqtt 设置设备信息获取函数,这个函数外部实现
-- @function callback,函数类型, 数据函
function SetCallbackInformationData(callback)
m_callbackDeviceInformationData = callback
end
--- mqtt 设置属性发布
-- @number nTime,数字类型, 0停止定时器 其他值开启定时器
function SetPropertyPush(nTime)
if m_timePropertyId ~= 0 then
sys.timerStop(m_timePropertyId)
m_timePropertyId = 0
end
if nTime~= 0 then
m_timePropertyId = sys.timerLoopStart(PropertyPush,nTime)
end
end
--- mqtt 设置功能发布
-- @number nTime,数字类型, 0停止定时器 其他值开启定时器
function SetFunctionPush(nTime)
if m_timeFunctionId ~= 0 then
sys.timerStop(m_timeFunctionId)
m_timeFunctionId = 0
end
if nTime~= 0 then
m_timeFunctionId = sys.timerLoopStart(FunctionPush,nTime)
end
end
--- mqtt 设置事件发布
-- @number nTime,数字类型, 0停止定时器 其他值开启定时器
function SetEventPush(nTime)
if m_timeEventId ~= 0 then
sys.timerStop(m_timeEventId)
m_timeEventId = 0
end
if nTime~= 0 then
m_timeEventId = sys.timerLoopStart(EventPush,nTime)
end
end
--- mqtt 获取要订阅的所有主题
-- @return tSubscriber,表类型, topic 主题 qos级别
function GetSubscriberAll()
local tSubscriber ={}
table.insert(tSubscriber,{topic=GetSubscriberDeviceInformation(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceProperty(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDevicePropertyOnline(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceFunction(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceFunctionOnline(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceMonitor(),qos=1})
table.insert(tSubscriber,{topic=GetSubscriberDeviceNtp(),qos=1})
return tSubscriber
end
--- mqtt接受数据
-- @string topic,string类型,接收到的主题
-- @string message,string类型消息内容
-- @return nil
function OnRecvData(topic , message)
if topic == GetSubscriberDeviceInformation() then
DeviceInformationPush();
elseif topic == GetSubscriberDeviceInOta() then
local jsonObj = json.decode(message)
local strVersion = jsonObj["version"]
local strUrl = jsonObj["downloadUrl"]
elseif topic == GetSubscriberDeviceProperty() then
PropertyPush();
elseif topic == GetSubscriberDevicePropertyOnline() then
PropertyPush();
elseif topic == GetSubscriberDeviceFunction() then
FunctionPush();
elseif topic == GetSubscriberDeviceFunctionOnline() then
FunctionPush();
elseif topic == GetSubscriberDeviceMonitor() then
local jsonObj = json.decode(message)
m_nMonitorCount = jsonObj["count"]
m_nMonitorTime = jsonObj["interval"]
if m_timeMonitorId ~= 0 then
sys.timerStop(m_timeMonitorId)
m_timeMonitorId = 0
end
m_timeMonitorId = sys.timerStart(
DeviceMonitorTimeCallback
,m_nMonitorTime)
elseif topic == GetSubscriberDeviceNtp() then
log.info("--DeviceNtp---" .. message)
end
end

133
sdk/合宙/WuMeiTest.lua Normal file
View File

@@ -0,0 +1,133 @@
--- 模块功能物美MQTT测试
-- @author 杜兴杰
-- @module 物美MQTT通信测试
-- @license MIT
-- @copyright 杜兴杰
-- @email 1066950103@qq.com
-- @release 2022.8.5
module(..., package.seeall)
require"WeiMeiComAuth"
require"WeiMeiComInteraction"
require"WeiMeiApp"
require"misc"
require"mqtt"
local ready = false
--物美配置参数相关配置
local m_strEncryptionMode = "S"
local m_strProductId = 220
local m_strDeviceId = nil
local m_strUserId = "1" -- admin
local m_strMqttUser = "wumei-smart"
local m_strMqttPassword = "PVMXS6V46205CAQ5"
local m_strProductPassword = "KC3169JOU816X5C0" --产品密码
local m_nMqttAuthenticationTimeout = 24*60*60*1000 --24小时
local m_strMqttIp = "wumei.live"
local m_strDeviceAuthorizationCode = "A25040D2E34B483DA371B5F9A315BB43" --设备授权码
local m_mqttClient = nil
local m_mqttFlag = 0
function AuthenticationResultCallback(nResult)
if nResult == 1 then
log.info("---AuthenticationResultCallback---ok")
WeiMeiComInteraction.Init(m_strProductId,m_strDeviceId)
m_mqttFlag = 1
end
end
local function MqttInit()
WeiMeiComAuth.Init(m_strEncryptionMode,m_strProductId,m_strDeviceId,m_strUserId,m_strMqttUser,m_strMqttPassword,m_nMqttAuthenticationTimeout,m_strMqttIp,m_strDeviceAuthorizationCode,m_strProductPassword,AuthenticationResultCallback)
end
-- 订阅所有主题
local function GetSubscriberAll()
local tSubscriber = WeiMeiComInteraction.GetSubscriberAll()
while #tSubscriber > 0 do
local ouSubscriber = table.remove(tSubscriber,1)
if m_mqttClient:subscribe({[ouSubscriber.topic]=ouSubscriber.qos}) == nil then
log.info("subscribe eeror ")
return false
end
end
return true
end
--- MQTT连接是否处于激活状态
-- @return 激活状态返回true非激活状态返回false
-- @usage mqttTask.isReady()
function isReady()
return ready
end
--启动MQTT客户端任务
sys.taskInit(
function()
local retryConnectCnt = 0
while true do
if not socket.isReady() then
retryConnectCnt = 0
--等待网络环境准备就绪超时时间是5分钟
sys.waitUntil("IP_READY_IND",300000)
end
if socket.isReady() then
m_strDeviceId = misc.getImei()
MqttInit()
while m_mqttFlag == 0 do
sys.wait(50)
end
--创建一个MQTT客户端
log.info("ClientId=" .. WeiMeiComAuth.GetClientId() )
log.info("User=" .. WeiMeiComAuth.GetUser() )
log.info("Password=" .. WeiMeiComAuth.GetPassword() )
log.info("Ip=" .. WeiMeiComAuth.GetIP() )
m_mqttClient = mqtt.client(WeiMeiComAuth.GetClientId(),600,WeiMeiComAuth.GetUser(),WeiMeiComAuth.GetPassword())
if m_mqttClient:connect(WeiMeiComAuth.GetIP(),1883,"tcp") then
retryConnectCnt = 0
ready = true
--订阅主题
if GetSubscriberAll() == true then
WeiMeiComInteraction.SetCallbackInformationData(WeiMeiApp.InformationData)
WeiMeiComInteraction.SetCallbackPropertyData(WeiMeiApp.PropertyData)
WeiMeiComInteraction.SetPropertyPush(1000*30) --30秒钟定时上传一次属性
WeiMeiComInteraction.DelayInit()
--循环处理接收和发送的数据
while true do
local result,data = m_mqttClient:receive(300,"APP_SOCKET_SEND_DATA")
if result or data=="timeout" or data=="APP_SOCKET_SEND_DATA" then
if result then
log.info("data.topic" .. data.topic .. "data.payload" .. data.payload)
WeiMeiComInteraction.OnRecvData(data.topic,data.payload);
end
else
break -- 出错了
end
result,strMessage,strTopic,nQos = WeiMeiComInteraction.GetData()
if result == true then
local mqttResult = m_mqttClient:publish(strTopic,strMessage,nQos)
if not mqttResult then
break
end
end
end
end
ready = false
else
retryConnectCnt = retryConnectCnt+1
end
--断开MQTT连接
m_mqttClient:disconnect()
if retryConnectCnt>=5 then link.shut() retryConnectCnt=0 end
sys.wait(5000)
else
--进入飞行模式20秒之后退出飞行模式
net.switchFly(true)
sys.wait(20000)
net.switchFly(false)
end
end
end
)

65
sdk/合宙/main.lua Normal file
View File

@@ -0,0 +1,65 @@
--必须在这个位置定义PROJECT和VERSION变量
--PROJECTascii string类型可以随便定义只要不使用,就行
--VERSIONascii string类型如果使用Luat物联云平台固件升级的功能必须按照"X.X.X"定义X表示1位数字否则可随便定义
PROJECT = "DTU"
VERSION = "1.0.0"
--加载日志功能模块,并且设置日志输出等级
--如果关闭调用log模块接口输出的日志等级设置为log.LOG_SILENT即可
require "log"
LOG_LEVEL = log.LOGLEVEL_TRACE
--[[
如果使用UART输出日志打开这行注释的代码"--log.openTrace(true,1,115200)"即可,根据自己的需求修改此接口的参数
如果要彻底关闭脚本中的输出日志包括调用log模块接口和Lua标准print接口输出的日志执行log.openTrace(false,第二个参数跟调用openTrace接口打开日志的第二个参数相同),例如:
1、没有调用过sys.opntrace配置日志输出端口或者最后一次是调用log.openTrace(true,nil,921600)配置日志输出端口此时要关闭输出日志直接调用log.openTrace(false)即可
2、最后一次是调用log.openTrace(true,1,115200)配置日志输出端口此时要关闭输出日志直接调用log.openTrace(false,1)即可
--]]
--log.openTrace(true,1,115200)
require "sys"
require "net"
--每1分钟查询一次GSM信号强度
--每1分钟查询一次基站信息
net.startQueryAll(60000, 60000)
--此处关闭RNDIS网卡功能
--否则模块通过USB连接电脑后会在电脑的网络适配器中枚举一个RNDIS网卡电脑默认使用此网卡上网导致模块使用的sim卡流量流失
--如果项目中需要打开此功能把ril.request("AT+RNDISCALL=0,1")修改为ril.request("AT+RNDISCALL=1,1")即可
--注意core固件V0030以及之后的版本、V3028以及之后的版本才以稳定地支持此功能
ril.request("AT+RNDISCALL=1,1")
--加载控制台调试功能模块此处代码配置的是uart2波特率115200
--此功能模块不是必须的,根据项目需求决定是否加载
--使用时注意控制台使用的uart不要和其他功能使用的uart冲突
--使用说明参考demo/console下的《console功能使用说明.docx》
--require "console"
--console.setup(2, 115200)
--加载网络指示灯和LTE指示灯功能模块
--根据自己的项目需求和硬件配置决定1、是否加载此功能模块2、配置指示灯引脚
--合宙官方出售的Air720U开发板上的网络指示灯引脚为pio.P0_1LTE指示灯引脚为pio.P0_4
require "netLed"
pmd.ldoset(2,pmd.LDO_VLCD)
netLed.setup(true,pio.P0_1,pio.P0_4)
--网络指示灯功能模块中默认配置了各种工作状态下指示灯的闪烁规律参考netLed.lua中ledBlinkTime配置的默认值
--如果默认值满足不了需求此处调用netLed.updateBlinkTime去配置闪烁时长
--LTE指示灯功能模块中配置的是注册上4G网络灯就常亮其余任何状态灯都会熄灭
--加载错误日志管理功能模块【强烈建议打开此功能】
--如下2行代码只是简单的演示如何使用errDump功能详情参考errDump的api
require "errDump"
errDump.request("udp://dev_msg1.openluat.com:12425", nil, true)
--加载远程升级功能模块【强烈建议打开此功能如果使用了阿里云的OTA功能可以不打开此功能】
--如下3行代码只是简单的演示如何使用update功能详情参考update的api以及demo/update
PRODUCT_KEY = "7wazHLKGOdfjrSoG5tXOr4uUg7D5wT9k"
--require "update"
--update.request()
--加载MQTT功能测试模块
require "WuMeiTest"
--启动系统框架
sys.init(0, 0)
sys.run()

65
sdk/合宙/mainAir724.lua Normal file
View File

@@ -0,0 +1,65 @@
--必须在这个位置定义PROJECT和VERSION变量
--PROJECTascii string类型可以随便定义只要不使用,就行
--VERSIONascii string类型如果使用Luat物联云平台固件升级的功能必须按照"X.X.X"定义X表示1位数字否则可随便定义
PROJECT = "DTU"
VERSION = "1.0.0"
--加载日志功能模块,并且设置日志输出等级
--如果关闭调用log模块接口输出的日志等级设置为log.LOG_SILENT即可
require "log"
LOG_LEVEL = log.LOGLEVEL_TRACE
--[[
如果使用UART输出日志打开这行注释的代码"--log.openTrace(true,1,115200)"即可,根据自己的需求修改此接口的参数
如果要彻底关闭脚本中的输出日志包括调用log模块接口和Lua标准print接口输出的日志执行log.openTrace(false,第二个参数跟调用openTrace接口打开日志的第二个参数相同),例如:
1、没有调用过sys.opntrace配置日志输出端口或者最后一次是调用log.openTrace(true,nil,921600)配置日志输出端口此时要关闭输出日志直接调用log.openTrace(false)即可
2、最后一次是调用log.openTrace(true,1,115200)配置日志输出端口此时要关闭输出日志直接调用log.openTrace(false,1)即可
--]]
--log.openTrace(true,1,115200)
require "sys"
require "net"
--每1分钟查询一次GSM信号强度
--每1分钟查询一次基站信息
net.startQueryAll(60000, 60000)
--此处关闭RNDIS网卡功能
--否则模块通过USB连接电脑后会在电脑的网络适配器中枚举一个RNDIS网卡电脑默认使用此网卡上网导致模块使用的sim卡流量流失
--如果项目中需要打开此功能把ril.request("AT+RNDISCALL=0,1")修改为ril.request("AT+RNDISCALL=1,1")即可
--注意core固件V0030以及之后的版本、V3028以及之后的版本才以稳定地支持此功能
ril.request("AT+RNDISCALL=1,1")
--加载控制台调试功能模块此处代码配置的是uart2波特率115200
--此功能模块不是必须的,根据项目需求决定是否加载
--使用时注意控制台使用的uart不要和其他功能使用的uart冲突
--使用说明参考demo/console下的《console功能使用说明.docx》
--require "console"
--console.setup(2, 115200)
--加载网络指示灯和LTE指示灯功能模块
--根据自己的项目需求和硬件配置决定1、是否加载此功能模块2、配置指示灯引脚
--合宙官方出售的Air720U开发板上的网络指示灯引脚为pio.P0_1LTE指示灯引脚为pio.P0_4
require "netLed"
pmd.ldoset(2,pmd.LDO_VLCD)
netLed.setup(true,pio.P0_1,pio.P0_4)
--网络指示灯功能模块中默认配置了各种工作状态下指示灯的闪烁规律参考netLed.lua中ledBlinkTime配置的默认值
--如果默认值满足不了需求此处调用netLed.updateBlinkTime去配置闪烁时长
--LTE指示灯功能模块中配置的是注册上4G网络灯就常亮其余任何状态灯都会熄灭
--加载错误日志管理功能模块【强烈建议打开此功能】
--如下2行代码只是简单的演示如何使用errDump功能详情参考errDump的api
require "errDump"
errDump.request("udp://dev_msg1.openluat.com:12425", nil, true)
--加载远程升级功能模块【强烈建议打开此功能如果使用了阿里云的OTA功能可以不打开此功能】
--如下3行代码只是简单的演示如何使用update功能详情参考update的api以及demo/update
PRODUCT_KEY = "7wazHLKGOdfjrSoG5tXOr4uUg7D5wT9k"
--require "update"
--update.request()
--加载MQTT功能测试模块
require "WuMeiTest"
--启动系统框架
sys.init(0, 0)
sys.run()

10
sdk/合宙/mainVscode.lua Normal file
View File

@@ -0,0 +1,10 @@
PROJECT = 'test'
VERSION = '2.0.0'
require 'log'
LOG_LEVEL = log.LOGLEVEL_TRACE
require 'sys'
require "WuMeiTest"
sys.init(0, 0)
sys.run()

View File

@@ -24,6 +24,7 @@ target/
*.iws
*.iml
*.ipr
../.idea
### NetBeans ###
nbproject/private/
@@ -39,6 +40,8 @@ nbdist/
*.xml.versionsBackup
*.swp
own-*
!*/build/*.java
!*/build/*.html
!*/build/*.xml

View File

@@ -3,7 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wumei</groupId>
<artifactId>wumei</artifactId>
<version>3.8.0</version>
@@ -11,7 +11,7 @@
<name>wumei</name>
<url>http://www.wumei.live</url>
<description>物美智能开源生活物联网平台</description>
<properties>
<wumei.version>3.8.0</wumei.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -33,8 +33,10 @@
<poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version>
<jwt.version>0.9.1</jwt.version>
<justAuth.version>1.16.5</justAuth.version>
<forest.version>1.5.19</forest.version>
</properties>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
@@ -206,6 +208,8 @@
<version>${wumei.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
<version>3.8.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<packaging>jar</packaging>
<artifactId>wumei-admin</artifactId>
<description>

View File

@@ -1,15 +1,5 @@
package com.ruoyi.web.controller.system;
import java.io.IOException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.UserConstants;
@@ -22,34 +12,42 @@ import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.iot.service.IUserSocialProfileService;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/**
* 个人信息 业务处理
*
*
* @author ruoyi
*/
@RestController
@RequestMapping("/system/user/profile")
public class SysProfileController extends BaseController
{
public class SysProfileController extends BaseController {
@Autowired
private ISysUserService userService;
@Autowired
private TokenService tokenService;
@Autowired
private IUserSocialProfileService iUserSocialProfileService;
/**
* 个人信息
*/
@GetMapping
public AjaxResult profile()
{
public AjaxResult profile() {
LoginUser loginUser = getLoginUser();
SysUser user = loginUser.getUser();
AjaxResult ajax = AjaxResult.success(user);
ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
ajax.put("socialGroup", iUserSocialProfileService.selectUserSocialProfile(loginUser.getUserId()));
return ajax;
}

View File

@@ -1,57 +1,68 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost/wumeismart?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: admin
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: admin
login-password: admin123
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://localhost/wumei-smart?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: admin
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# TDengine数据库
tdengine-server:
# 默认不启用TDenginetrue=启用false=不启用
enabled: false
driverClassName: com.taosdata.jdbc.TSDBDriver
url: jdbc:TAOS://localhost:6030/wumei_smart_log?timezone=Asia/Beijing&charset=utf-8
username: root
password: taosdata
dbName: wumei_smart_log
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: wumei-smart
login-password: wumei-smart
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true

View File

@@ -8,8 +8,8 @@ ruoyi:
copyrightYear: 2021
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/wumei/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: D:\project\github\wumei-smart\springboot\uploadpath
# 文件路径以uploadPath结尾 示例( Windows配置 D:/uploadPathLinux配置 /uploadPath
profile: /uploadPath
# 获取ip地址开关
addressEnabled: true
# 验证码类型 math 数组计算 char 字符验证
@@ -42,15 +42,15 @@ spring:
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
# 服务模块
devtools:
restart:
@@ -63,9 +63,9 @@ spring:
# 端口默认为6379
port: 6379
# 数据库索引
database: 1
database: 0
# 密码
password: admin
password: wumei-smart
# 连接超时时间
timeout: 10s
lettuce:
@@ -78,39 +78,46 @@ spring:
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# mqtt 配置
# mqtt 配置
mqtt:
username: wumei-smart # 账号
password: wumei-smart # 密码
host-url: tcp://localhost:1883 # mqtt连接tcp地址
client-id: ${random.value} # 客户端Id不能相同采用随机数 ${random.value}
default-topic: test # 默认主题
timeout: 60000 # 超时时间
keepalive: 30 # 保持连接
username: wumei-smart # 账号
password: wumei-smart # 密码
host-url: tcp://localhost:1883 # mqtt连接tcp地址
client-id: ${random.int} # 客户端Id不能相同采用随机数 ${random.value}
default-topic: test # 默认主题
timeout: 30 # 超时时间
keepalive: 30 # 保持连接
clearSession: true # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
task:
execution:
pool:
core-size: 10 # 最小连接数
max-size: 30 # 最大连接数
queue-capacity: 3000 # 最大容量
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklwumeismartrstuvwxyz
# 令牌有效期默认30分钟1440为一天
expireTime: 1440
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklwumeismartrstuvwxyz
# 令牌有效期默认30分钟1440为一天
expireTime: 1440
# MyBatis配置
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
pagehelper:
helperDialect: mysql
supportMethodsArguments: true
params: count=countSql
params: count=countSql
# Swagger配置
swagger:
@@ -120,7 +127,7 @@ swagger:
pathMapping: /dev-api
# 防止XSS攻击
xss:
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/home/wumei/logs" />
<property name="log.path" value="/logs" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />

View File

@@ -86,4 +86,9 @@ public class HttpStatus
* 接口未实现
*/
public static final int NOT_IMPLEMENTED = 501;
/**
* 不弹窗显示
*/
public static final int NO_MESSAGE_ALERT = 502;
}

Some files were not shown because too many files have changed in this diff Show More