├── APPFont
├── .babelrc
├── .editorconfig
├── .gitignore
├── .postcssrc.js
├── README.md
├── build
│ ├── build.js
│ ├── check-versions.js
│ ├── logo.png
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ └── webpack.prod.conf.js
├── config
│ ├── dev.env.js
│ ├── index.js
│ └── prod.env.js
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── icon
│ │ │ ├── demo.css
│ │ │ ├── demo_fontclass.html
│ │ │ ├── demo_symbol.html
│ │ │ ├── demo_unicode.html
│ │ │ ├── iconfont.css
│ │ │ ├── iconfont.eot
│ │ │ ├── iconfont.js
│ │ │ ├── iconfont.svg
│ │ │ ├── iconfont.ttf
│ │ │ └── iconfont.woff
│ │ └── imgs
│ │ │ ├── 1.png
│ │ │ ├── 3.png
│ │ │ ├── 404.jpg
│ │ │ ├── EMQ.png
│ │ │ ├── dataPoint.png
│ │ │ ├── dataStream.png
│ │ │ ├── default-head.png
│ │ │ ├── device.png
│ │ │ ├── head.png
│ │ │ ├── logo.png
│ │ │ ├── nodeMCU.jpg
│ │ │ └── trigger.png
│ ├── axios.js
│ ├── components
│ │ ├── developer
│ │ │ ├── charts.vue
│ │ │ ├── console.vue
│ │ │ ├── dashboard.vue
│ │ │ ├── device.vue
│ │ │ ├── index.vue
│ │ │ ├── leftNavBar.vue
│ │ │ ├── stream.vue
│ │ │ ├── topNavBar.vue
│ │ │ └── trigger.vue
│ │ ├── home
│ │ │ ├── document.vue
│ │ │ ├── footer.vue
│ │ │ ├── home.vue
│ │ │ ├── introduce.vue
│ │ │ ├── resource.vue
│ │ │ └── topNavBar.vue
│ │ ├── identify.vue
│ │ ├── login.vue
│ │ ├── notFound.vue
│ │ ├── register.vue
│ │ └── test.vue
│ ├── main.js
│ ├── router
│ │ └── index.js
│ └── store
│ │ ├── actions.js
│ │ ├── index.js
│ │ ├── mutations.js
│ │ └── types.js
└── static
│ └── .gitkeep
├── Hardware
└── NodeMCU_MQTT
│ └── NodeMCU_MQTT.ino
├── IOTPlatform
├── .idea
│ ├── IOTPlatform.iml
│ ├── dataSources.local.xml
│ ├── dataSources.xml
│ ├── dataSources
│ │ └── ce1742cf-a77e-4b79-aa2f-b768e4210bdd.xml
│ ├── dictionaries
│ │ └── fml.xml
│ ├── inspectionProfiles
│ │ └── Project_Default.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── workspace.xml
├── IOTPlatform
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ ├── __init__.cpython-37.pyc
│ │ ├── settings.cpython-36.pyc
│ │ ├── settings.cpython-37.pyc
│ │ ├── urls.cpython-36.pyc
│ │ ├── urls.cpython-37.pyc
│ │ ├── wsgi.cpython-36.pyc
│ │ └── wsgi.cpython-37.pyc
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── middleware
│ ├── __pycache__
│ │ └── authentication.cpython-36.pyc
│ └── authentication.py
├── utils
│ ├── __pycache__
│ │ ├── models.cpython-37.pyc
│ │ └── time_tools.cpython-37.pyc
│ ├── database.py
│ ├── models.py
│ ├── mqtt_client.py
│ └── time_tools.py
├── website
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ ├── __init__.cpython-37.pyc
│ │ ├── admin.cpython-36.pyc
│ │ ├── admin.cpython-37.pyc
│ │ ├── console.cpython-37.pyc
│ │ ├── database.cpython-36.pyc
│ │ ├── database.cpython-37.pyc
│ │ ├── models.cpython-36.pyc
│ │ ├── models.cpython-37.pyc
│ │ ├── urls.cpython-36.pyc
│ │ ├── urls.cpython-37.pyc
│ │ ├── views.cpython-36.pyc
│ │ └── views.cpython-37.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── console.py
│ ├── database.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20181110_0221.py
│ │ ├── 0003_auto_20181114_0143.py
│ │ ├── 0004_auto_20181114_0144.py
│ │ ├── 0005_auto_20181114_0148.py
│ │ ├── 0006_auto_20181118_1522.py
│ │ ├── 0007_auto_20181118_1618.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ │ │ ├── 0001_initial.cpython-36.pyc
│ │ │ ├── 0001_initial.cpython-37.pyc
│ │ │ ├── 0002_auto_20181110_0221.cpython-37.pyc
│ │ │ ├── 0003_auto_20181114_0143.cpython-37.pyc
│ │ │ ├── 0004_auto_20181114_0144.cpython-37.pyc
│ │ │ ├── 0005_auto_20181114_0148.cpython-37.pyc
│ │ │ ├── 0006_auto_20181118_1522.cpython-37.pyc
│ │ │ ├── 0007_auto_20181118_1618.cpython-37.pyc
│ │ │ ├── __init__.cpython-36.pyc
│ │ │ └── __init__.cpython-37.pyc
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ ├── utils
│ │ ├── __pycache__
│ │ │ ├── auth.cpython-37.pyc
│ │ │ ├── create.cpython-36.pyc
│ │ │ └── create.cpython-37.pyc
│ │ ├── auth.py
│ │ └── create.py
│ └── views.py
└── weixin
│ ├── __init__.py
│ ├── __pycache__
│ ├── __init__.cpython-36.pyc
│ ├── __init__.cpython-37.pyc
│ ├── admin.cpython-36.pyc
│ ├── admin.cpython-37.pyc
│ ├── models.cpython-36.pyc
│ ├── models.cpython-37.pyc
│ ├── urls.cpython-36.pyc
│ ├── urls.cpython-37.pyc
│ ├── views.cpython-36.pyc
│ └── views.cpython-37.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ ├── __init__.py
│ └── __pycache__
│ │ ├── __init__.cpython-36.pyc
│ │ └── __init__.cpython-37.pyc
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── MQTT
├── .idea
│ ├── MQTT.iml
│ ├── dictionaries
│ │ └── fml.xml
│ ├── inspectionProfiles
│ │ └── Project_Default.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── workspace.xml
├── __pycache__
│ ├── database.cpython-37.pyc
│ └── models.cpython-37.pyc
├── database.py
├── models.py
└── mqtt_client.py
└── readme.md
/APPFont/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-vue-jsx", "transform-runtime"]
12 | }
13 |
--------------------------------------------------------------------------------
/APPFont/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/APPFont/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Editor directories and files
9 | .idea
10 | .vscode
11 | *.suo
12 | *.ntvs*
13 | *.njsproj
14 | *.sln
15 |
--------------------------------------------------------------------------------
/APPFont/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | "postcss-import": {},
6 | "postcss-url": {},
7 | // to edit target browsers: use "browserslist" field in package.json
8 | "autoprefixer": {}
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/APPFont/README.md:
--------------------------------------------------------------------------------
1 | # cms
2 |
3 | > A Vue.js project
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | # install dependencies
9 | npm install
10 |
11 | # serve with hot reload at localhost:8080
12 | npm run dev
13 |
14 | # build for production with minification
15 | npm run build
16 |
17 | # build for production and view the bundle analyzer report
18 | npm run build --report
19 | ```
20 |
21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
22 |
--------------------------------------------------------------------------------
/APPFont/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | require('./check-versions')()
3 |
4 | process.env.NODE_ENV = 'production'
5 |
6 | const ora = require('ora')
7 | const rm = require('rimraf')
8 | const path = require('path')
9 | const chalk = require('chalk')
10 | const webpack = require('webpack')
11 | const config = require('../config')
12 | const webpackConfig = require('./webpack.prod.conf')
13 |
14 | const spinner = ora('building for production...')
15 | spinner.start()
16 |
17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
18 | if (err) throw err
19 | webpack(webpackConfig, (err, stats) => {
20 | spinner.stop()
21 | if (err) throw err
22 | process.stdout.write(stats.toString({
23 | colors: true,
24 | modules: false,
25 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
26 | chunks: false,
27 | chunkModules: false
28 | }) + '\n\n')
29 |
30 | if (stats.hasErrors()) {
31 | console.log(chalk.red(' Build failed with errors.\n'))
32 | process.exit(1)
33 | }
34 |
35 | console.log(chalk.cyan(' Build complete.\n'))
36 | console.log(chalk.yellow(
37 | ' Tip: built files are meant to be served over an HTTP server.\n' +
38 | ' Opening index.html over file:// won\'t work.\n'
39 | ))
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/APPFont/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const chalk = require('chalk')
3 | const semver = require('semver')
4 | const packageConfig = require('../package.json')
5 | const shell = require('shelljs')
6 |
7 | function exec (cmd) {
8 | return require('child_process').execSync(cmd).toString().trim()
9 | }
10 |
11 | const versionRequirements = [
12 | {
13 | name: 'node',
14 | currentVersion: semver.clean(process.version),
15 | versionRequirement: packageConfig.engines.node
16 | }
17 | ]
18 |
19 | if (shell.which('npm')) {
20 | versionRequirements.push({
21 | name: 'npm',
22 | currentVersion: exec('npm --version'),
23 | versionRequirement: packageConfig.engines.npm
24 | })
25 | }
26 |
27 | module.exports = function () {
28 | const warnings = []
29 |
30 | for (let i = 0; i < versionRequirements.length; i++) {
31 | const mod = versionRequirements[i]
32 |
33 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
34 | warnings.push(mod.name + ': ' +
35 | chalk.red(mod.currentVersion) + ' should be ' +
36 | chalk.green(mod.versionRequirement)
37 | )
38 | }
39 | }
40 |
41 | if (warnings.length) {
42 | console.log('')
43 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
44 | console.log()
45 |
46 | for (let i = 0; i < warnings.length; i++) {
47 | const warning = warnings[i]
48 | console.log(' ' + warning)
49 | }
50 |
51 | console.log()
52 | process.exit(1)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/APPFont/build/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/build/logo.png
--------------------------------------------------------------------------------
/APPFont/build/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const config = require('../config')
4 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
5 | const packageConfig = require('../package.json')
6 |
7 | exports.assetsPath = function (_path) {
8 | const assetsSubDirectory = process.env.NODE_ENV === 'production'
9 | ? config.build.assetsSubDirectory
10 | : config.dev.assetsSubDirectory
11 |
12 | return path.posix.join(assetsSubDirectory, _path)
13 | }
14 |
15 | exports.cssLoaders = function (options) {
16 | options = options || {}
17 |
18 | const cssLoader = {
19 | loader: 'css-loader',
20 | options: {
21 | sourceMap: options.sourceMap
22 | }
23 | }
24 |
25 | const postcssLoader = {
26 | loader: 'postcss-loader',
27 | options: {
28 | sourceMap: options.sourceMap
29 | }
30 | }
31 |
32 | // generate loader string to be used with extract text plugin
33 | function generateLoaders (loader, loaderOptions) {
34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
35 |
36 | if (loader) {
37 | loaders.push({
38 | loader: loader + '-loader',
39 | options: Object.assign({}, loaderOptions, {
40 | sourceMap: options.sourceMap
41 | })
42 | })
43 | }
44 |
45 | // Extract CSS when that option is specified
46 | // (which is the case during production build)
47 | if (options.extract) {
48 | return ExtractTextPlugin.extract({
49 | use: loaders,
50 | fallback: 'vue-style-loader'
51 | })
52 | } else {
53 | return ['vue-style-loader'].concat(loaders)
54 | }
55 | }
56 |
57 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
58 | return {
59 | css: generateLoaders(),
60 | postcss: generateLoaders(),
61 | less: generateLoaders('less'),
62 | sass: generateLoaders('sass', { indentedSyntax: true }),
63 | scss: generateLoaders('sass'),
64 | stylus: generateLoaders('stylus'),
65 | styl: generateLoaders('stylus')
66 | }
67 | }
68 |
69 | // Generate loaders for standalone style files (outside of .vue)
70 | exports.styleLoaders = function (options) {
71 | const output = []
72 | const loaders = exports.cssLoaders(options)
73 |
74 | for (const extension in loaders) {
75 | const loader = loaders[extension]
76 | output.push({
77 | test: new RegExp('\\.' + extension + '$'),
78 | use: loader
79 | })
80 | }
81 |
82 | return output
83 | }
84 |
85 | exports.createNotifierCallback = () => {
86 | const notifier = require('node-notifier')
87 |
88 | return (severity, errors) => {
89 | if (severity !== 'error') return
90 |
91 | const error = errors[0]
92 | const filename = error.file && error.file.split('!').pop()
93 |
94 | notifier.notify({
95 | title: packageConfig.name,
96 | message: severity + ': ' + error.name,
97 | subtitle: filename || '',
98 | icon: path.join(__dirname, 'logo.png')
99 | })
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/APPFont/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const config = require('../config')
4 | const isProduction = process.env.NODE_ENV === 'production'
5 | const sourceMapEnabled = isProduction
6 | ? config.build.productionSourceMap
7 | : config.dev.cssSourceMap
8 |
9 | module.exports = {
10 | loaders: utils.cssLoaders({
11 | sourceMap: sourceMapEnabled,
12 | extract: isProduction
13 | }),
14 | cssSourceMap: sourceMapEnabled,
15 | cacheBusting: config.dev.cacheBusting,
16 | transformToRequire: {
17 | video: ['src', 'poster'],
18 | source: 'src',
19 | img: 'src',
20 | image: 'xlink:href'
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/APPFont/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const config = require('../config')
5 | const vueLoaderConfig = require('./vue-loader.conf')
6 |
7 | function resolve (dir) {
8 | return path.join(__dirname, '..', dir)
9 | }
10 |
11 |
12 |
13 | module.exports = {
14 | context: path.resolve(__dirname, '../'),
15 | entry: {
16 | app: './src/main.js'
17 | },
18 | output: {
19 | path: config.build.assetsRoot,
20 | filename: '[name].js',
21 | publicPath: process.env.NODE_ENV === 'production'
22 | ? config.build.assetsPublicPath
23 | : config.dev.assetsPublicPath
24 | },
25 | resolve: {
26 | extensions: ['.js', '.vue', '.json'],
27 | alias: {
28 | 'vue$': 'vue/dist/vue.esm.js',
29 | '@': resolve('src'),
30 | }
31 | },
32 | module: {
33 | rules: [
34 | {
35 | test: /\.vue$/,
36 | loader: 'vue-loader',
37 | options: vueLoaderConfig
38 | },
39 | {
40 | test: /\.js$/,
41 | loader: 'babel-loader',
42 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
43 | },
44 | {
45 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
46 | loader: 'url-loader',
47 | options: {
48 | limit: 10000,
49 | name: utils.assetsPath('imgs/[name].[hash:7].[ext]')
50 | }
51 | },
52 | {
53 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
54 | loader: 'url-loader',
55 | options: {
56 | limit: 10000,
57 | name: utils.assetsPath('media/[name].[hash:7].[ext]')
58 | }
59 | },
60 | {
61 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
62 | loader: 'url-loader',
63 | options: {
64 | limit: 10000,
65 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
66 | }
67 | }
68 | ]
69 | },
70 | node: {
71 | // prevent webpack from injecting useless setImmediate polyfill because Vue
72 | // source contains it (although only uses it if it's native).
73 | setImmediate: false,
74 | // prevent webpack from injecting mocks to Node native modules
75 | // that does not make sense for the client
76 | dgram: 'empty',
77 | fs: 'empty',
78 | net: 'empty',
79 | tls: 'empty',
80 | child_process: 'empty'
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/APPFont/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const utils = require('./utils')
3 | const webpack = require('webpack')
4 | const config = require('../config')
5 | const merge = require('webpack-merge')
6 | const path = require('path')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
11 | const portfinder = require('portfinder')
12 |
13 | const HOST = process.env.HOST
14 | const PORT = process.env.PORT && Number(process.env.PORT)
15 |
16 | const devWebpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
19 | },
20 | // cheap-module-eval-source-map is faster for development
21 | devtool: config.dev.devtool,
22 |
23 | // these devServer options should be customized in /config/index.js
24 | devServer: {
25 | clientLogLevel: 'warning',
26 | historyApiFallback: {
27 | rewrites: [
28 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
29 | ],
30 | },
31 | hot: true,
32 | contentBase: false, // since we use CopyWebpackPlugin.
33 | compress: true,
34 | host: HOST || config.dev.host,
35 | port: PORT || config.dev.port,
36 | open: config.dev.autoOpenBrowser,
37 | overlay: config.dev.errorOverlay
38 | ? { warnings: false, errors: true }
39 | : false,
40 | publicPath: config.dev.assetsPublicPath,
41 | proxy: config.dev.proxyTable,
42 | quiet: true, // necessary for FriendlyErrorsPlugin
43 | watchOptions: {
44 | poll: config.dev.poll,
45 | }
46 | },
47 | plugins: [
48 | new webpack.DefinePlugin({
49 | 'process.env': require('../config/dev.env')
50 | }),
51 | new webpack.HotModuleReplacementPlugin(),
52 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
53 | new webpack.NoEmitOnErrorsPlugin(),
54 | // https://github.com/ampedandwired/html-webpack-plugin
55 | new HtmlWebpackPlugin({
56 | filename: 'index.html',
57 | template: 'index.html',
58 | inject: true
59 | }),
60 | // copy custom static assets
61 | new CopyWebpackPlugin([
62 | {
63 | from: path.resolve(__dirname, '../static'),
64 | to: config.dev.assetsSubDirectory,
65 | ignore: ['.*']
66 | }
67 | ])
68 | ]
69 | })
70 |
71 | module.exports = new Promise((resolve, reject) => {
72 | portfinder.basePort = process.env.PORT || config.dev.port
73 | portfinder.getPort((err, port) => {
74 | if (err) {
75 | reject(err)
76 | } else {
77 | // publish the new Port, necessary for e2e tests
78 | process.env.PORT = port
79 | // add port to devServer config
80 | devWebpackConfig.devServer.port = port
81 |
82 | // Add FriendlyErrorsPlugin
83 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
84 | compilationSuccessInfo: {
85 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
86 | },
87 | onErrors: config.dev.notifyOnErrors
88 | ? utils.createNotifierCallback()
89 | : undefined
90 | }))
91 |
92 | resolve(devWebpackConfig)
93 | }
94 | })
95 | })
96 |
--------------------------------------------------------------------------------
/APPFont/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const path = require('path')
3 | const utils = require('./utils')
4 | const webpack = require('webpack')
5 | const config = require('../config')
6 | const merge = require('webpack-merge')
7 | const baseWebpackConfig = require('./webpack.base.conf')
8 | const CopyWebpackPlugin = require('copy-webpack-plugin')
9 | const HtmlWebpackPlugin = require('html-webpack-plugin')
10 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
13 |
14 | const env = require('../config/prod.env')
15 |
16 | const webpackConfig = merge(baseWebpackConfig, {
17 | module: {
18 | rules: utils.styleLoaders({
19 | sourceMap: config.build.productionSourceMap,
20 | extract: true,
21 | usePostCSS: true
22 | })
23 | },
24 | devtool: config.build.productionSourceMap ? config.build.devtool : false,
25 | output: {
26 | path: config.build.assetsRoot,
27 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
28 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
29 | },
30 | plugins: [
31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
32 | new webpack.DefinePlugin({
33 | 'process.env': env
34 | }),
35 | new UglifyJsPlugin({
36 | uglifyOptions: {
37 | compress: {
38 | warnings: false
39 | }
40 | },
41 | sourceMap: config.build.productionSourceMap,
42 | parallel: true
43 | }),
44 | // extract css into its own file
45 | new ExtractTextPlugin({
46 | filename: utils.assetsPath('css/[name].[contenthash].css'),
47 | // Setting the following option to `false` will not extract CSS from codesplit chunks.
48 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
49 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
50 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
51 | allChunks: true,
52 | }),
53 | // Compress extracted CSS. We are using this plugin so that possible
54 | // duplicated CSS from different components can be deduped.
55 | new OptimizeCSSPlugin({
56 | cssProcessorOptions: config.build.productionSourceMap
57 | ? { safe: true, map: { inline: false } }
58 | : { safe: true }
59 | }),
60 | // generate dist index.html with correct asset hash for caching.
61 | // you can customize output by editing /index.html
62 | // see https://github.com/ampedandwired/html-webpack-plugin
63 | new HtmlWebpackPlugin({
64 | filename: config.build.index,
65 | template: 'index.html',
66 | inject: true,
67 | minify: {
68 | removeComments: true,
69 | collapseWhitespace: true,
70 | removeAttributeQuotes: true
71 | // more options:
72 | // https://github.com/kangax/html-minifier#options-quick-reference
73 | },
74 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
75 | chunksSortMode: 'dependency'
76 | }),
77 | // keep module.id stable when vendor modules does not change
78 | new webpack.HashedModuleIdsPlugin(),
79 | // enable scope hoisting
80 | new webpack.optimize.ModuleConcatenationPlugin(),
81 | // split vendor js into its own file
82 | new webpack.optimize.CommonsChunkPlugin({
83 | name: 'vendor',
84 | minChunks (module) {
85 | // any required modules inside node_modules are extracted to vendor
86 | return (
87 | module.resource &&
88 | /\.js$/.test(module.resource) &&
89 | module.resource.indexOf(
90 | path.join(__dirname, '../node_modules')
91 | ) === 0
92 | )
93 | }
94 | }),
95 | // extract webpack runtime and module manifest to its own file in order to
96 | // prevent vendor hash from being updated whenever app bundle is updated
97 | new webpack.optimize.CommonsChunkPlugin({
98 | name: 'manifest',
99 | minChunks: Infinity
100 | }),
101 | // This instance extracts shared chunks from code splitted chunks and bundles them
102 | // in a separate chunk, similar to the vendor chunk
103 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
104 | new webpack.optimize.CommonsChunkPlugin({
105 | name: 'app',
106 | async: 'vendor-async',
107 | children: true,
108 | minChunks: 3
109 | }),
110 |
111 | // copy custom static assets
112 | new CopyWebpackPlugin([
113 | {
114 | from: path.resolve(__dirname, '../static'),
115 | to: config.build.assetsSubDirectory,
116 | ignore: ['.*']
117 | }
118 | ])
119 | ]
120 | })
121 |
122 | if (config.build.productionGzip) {
123 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
124 |
125 | webpackConfig.plugins.push(
126 | new CompressionWebpackPlugin({
127 | asset: '[path].gz[query]',
128 | algorithm: 'gzip',
129 | test: new RegExp(
130 | '\\.(' +
131 | config.build.productionGzipExtensions.join('|') +
132 | ')$'
133 | ),
134 | threshold: 10240,
135 | minRatio: 0.8
136 | })
137 | )
138 | }
139 |
140 | if (config.build.bundleAnalyzerReport) {
141 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
142 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
143 | }
144 |
145 | module.exports = webpackConfig
146 |
--------------------------------------------------------------------------------
/APPFont/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | const merge = require('webpack-merge')
3 | const prodEnv = require('./prod.env')
4 |
5 | module.exports = merge(prodEnv, {
6 | NODE_ENV: '"development"'
7 | })
8 |
--------------------------------------------------------------------------------
/APPFont/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | // Template version: 1.3.1
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 |
5 | const path = require('path')
6 |
7 | module.exports = {
8 | dev: {
9 |
10 | // Paths
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | proxyTable: {},
14 |
15 | // Various Dev Server settings
16 | host: 'localhost', // can be overwritten by process.env.HOST
17 | port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
18 | autoOpenBrowser: false,
19 | errorOverlay: true,
20 | notifyOnErrors: true,
21 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
22 |
23 |
24 | /**
25 | * Source Maps
26 | */
27 |
28 | // https://webpack.js.org/configuration/devtool/#development
29 | devtool: 'cheap-module-eval-source-map',
30 |
31 | // If you have problems debugging vue-files in devtools,
32 | // set this to false - it *may* help
33 | // https://vue-loader.vuejs.org/en/options.html#cachebusting
34 | cacheBusting: true,
35 |
36 | cssSourceMap: true
37 | },
38 |
39 | build: {
40 | // Template for index.html
41 | index: path.resolve(__dirname, '../dist/index.html'),
42 |
43 | // Paths
44 | assetsRoot: path.resolve(__dirname, '../dist'),
45 | assetsSubDirectory: 'static',
46 | assetsPublicPath: '/',
47 |
48 | /**
49 | * Source Maps
50 | */
51 |
52 | productionSourceMap: true,
53 | // https://webpack.js.org/configuration/devtool/#production
54 | devtool: '#source-map',
55 |
56 | // Gzip off by default as many popular static hosts such as
57 | // Surge or Netlify already gzip all static assets for you.
58 | // Before setting to `true`, make sure to:
59 | // npm install --save-dev compression-webpack-plugin
60 | productionGzip: false,
61 | productionGzipExtensions: ['js', 'css'],
62 |
63 | // Run the build command with an extra argument to
64 | // View the bundle analyzer report after build finishes:
65 | // `npm run build --report`
66 | // Set to `true` or `false` to always turn it on or off
67 | bundleAnalyzerReport: process.env.npm_config_report
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/APPFont/config/prod.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | module.exports = {
3 | NODE_ENV: '"production"'
4 | }
5 |
--------------------------------------------------------------------------------
/APPFont/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | IOTPlatform
8 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/APPFont/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cms",
3 | "version": "1.0.0",
4 | "description": "A Vue.js project",
5 | "author": "FanMLei <15638515832@163.com>",
6 | "private": true,
7 | "scripts": {
8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
9 | "start": "npm run dev",
10 | "build": "node build/build.js"
11 | },
12 | "dependencies": {
13 | "axios": "^0.18.0",
14 | "echarts": "^4.2.0-rc.2",
15 | "element-ui": "^2.4.9",
16 | "vue": "^2.5.2",
17 | "vue-router": "^3.0.1",
18 | "vuex": "^3.0.1"
19 | },
20 | "devDependencies": {
21 | "autoprefixer": "^7.1.2",
22 | "babel-core": "^6.22.1",
23 | "babel-helper-vue-jsx-merge-props": "^2.0.3",
24 | "babel-loader": "^7.1.1",
25 | "babel-plugin-syntax-jsx": "^6.18.0",
26 | "babel-plugin-transform-runtime": "^6.22.0",
27 | "babel-plugin-transform-vue-jsx": "^3.5.0",
28 | "babel-preset-env": "^1.3.2",
29 | "babel-preset-stage-2": "^6.22.0",
30 | "chalk": "^2.0.1",
31 | "copy-webpack-plugin": "^4.0.1",
32 | "css-loader": "^0.28.0",
33 | "extract-text-webpack-plugin": "^3.0.0",
34 | "file-loader": "^1.1.4",
35 | "friendly-errors-webpack-plugin": "^1.6.1",
36 | "html-webpack-plugin": "^2.30.1",
37 | "node-notifier": "^5.1.2",
38 | "optimize-css-assets-webpack-plugin": "^3.2.0",
39 | "ora": "^1.2.0",
40 | "portfinder": "^1.0.13",
41 | "postcss-import": "^11.0.0",
42 | "postcss-loader": "^2.0.8",
43 | "postcss-url": "^7.2.1",
44 | "rimraf": "^2.6.0",
45 | "semver": "^5.3.0",
46 | "shelljs": "^0.7.6",
47 | "uglifyjs-webpack-plugin": "^1.1.1",
48 | "url-loader": "^0.5.8",
49 | "vue-loader": "^13.3.0",
50 | "vue-style-loader": "^3.0.1",
51 | "vue-template-compiler": "^2.5.2",
52 | "webpack": "^3.6.0",
53 | "webpack-bundle-analyzer": "^2.9.0",
54 | "webpack-dev-server": "^2.9.1",
55 | "webpack-merge": "^4.1.0"
56 | },
57 | "engines": {
58 | "node": ">= 6.0.0",
59 | "npm": ">= 3.0.0"
60 | },
61 | "browserslist": [
62 | "> 1%",
63 | "last 2 versions",
64 | "not ie <= 8"
65 | ]
66 | }
67 |
--------------------------------------------------------------------------------
/APPFont/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/APPFont/src/assets/icon/demo.css:
--------------------------------------------------------------------------------
1 | *{margin: 0;padding: 0;list-style: none;}
2 | /*
3 | KISSY CSS Reset
4 | 理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。
5 | 2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。
6 | 3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。
7 | 特色:1. 适应中文;2. 基于最新主流浏览器。
8 | 维护:玉伯, 正淳
9 | */
10 |
11 | /** 清除内外边距 **/
12 | body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */
13 | dl, dt, dd, ul, ol, li, /* list elements 列表元素 */
14 | pre, /* text formatting elements 文本格式元素 */
15 | form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */
16 | th, td /* table elements 表格元素 */ {
17 | margin: 0;
18 | padding: 0;
19 | }
20 |
21 | /** 设置默认字体 **/
22 | body,
23 | button, input, select, textarea /* for ie */ {
24 | font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif;
25 | }
26 | h1, h2, h3, h4, h5, h6 { font-size: 100%; }
27 | address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */
28 | code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */
29 | small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */
30 |
31 | /** 重置列表元素 **/
32 | ul, ol { list-style: none; }
33 |
34 | /** 重置文本格式元素 **/
35 | a { text-decoration: none; }
36 | a:hover { text-decoration: underline; }
37 |
38 |
39 | /** 重置表单元素 **/
40 | legend { color: #000; } /* for ie6 */
41 | fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */
42 | button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */
43 | /* 注:optgroup 无法扶正 */
44 |
45 | /** 重置表格元素 **/
46 | table { border-collapse: collapse; border-spacing: 0; }
47 |
48 | /* 清除浮动 */
49 | .ks-clear:after, .clear:after {
50 | content: '\20';
51 | display: block;
52 | height: 0;
53 | clear: both;
54 | }
55 | .ks-clear, .clear {
56 | *zoom: 1;
57 | }
58 |
59 | .main {
60 | padding: 30px 100px;
61 | width: 960px;
62 | margin: 0 auto;
63 | }
64 | .main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;}
65 |
66 | .helps{margin-top:40px;}
67 | .helps pre{
68 | padding:20px;
69 | margin:10px 0;
70 | border:solid 1px #e7e1cd;
71 | background-color: #fffdef;
72 | overflow: auto;
73 | }
74 |
75 | .icon_lists{
76 | width: 100% !important;
77 |
78 | }
79 |
80 | .icon_lists li{
81 | float:left;
82 | width: 100px;
83 | height:180px;
84 | text-align: center;
85 | list-style: none !important;
86 | }
87 | .icon_lists .icon{
88 | font-size: 42px;
89 | line-height: 100px;
90 | margin: 10px 0;
91 | color:#333;
92 | -webkit-transition: font-size 0.25s ease-out 0s;
93 | -moz-transition: font-size 0.25s ease-out 0s;
94 | transition: font-size 0.25s ease-out 0s;
95 |
96 | }
97 | .icon_lists .icon:hover{
98 | font-size: 100px;
99 | }
100 |
101 |
102 |
103 | .markdown {
104 | color: #666;
105 | font-size: 14px;
106 | line-height: 1.8;
107 | }
108 |
109 | .highlight {
110 | line-height: 1.5;
111 | }
112 |
113 | .markdown img {
114 | vertical-align: middle;
115 | max-width: 100%;
116 | }
117 |
118 | .markdown h1 {
119 | color: #404040;
120 | font-weight: 500;
121 | line-height: 40px;
122 | margin-bottom: 24px;
123 | }
124 |
125 | .markdown h2,
126 | .markdown h3,
127 | .markdown h4,
128 | .markdown h5,
129 | .markdown h6 {
130 | color: #404040;
131 | margin: 1.6em 0 0.6em 0;
132 | font-weight: 500;
133 | clear: both;
134 | }
135 |
136 | .markdown h1 {
137 | font-size: 28px;
138 | }
139 |
140 | .markdown h2 {
141 | font-size: 22px;
142 | }
143 |
144 | .markdown h3 {
145 | font-size: 16px;
146 | }
147 |
148 | .markdown h4 {
149 | font-size: 14px;
150 | }
151 |
152 | .markdown h5 {
153 | font-size: 12px;
154 | }
155 |
156 | .markdown h6 {
157 | font-size: 12px;
158 | }
159 |
160 | .markdown hr {
161 | height: 1px;
162 | border: 0;
163 | background: #e9e9e9;
164 | margin: 16px 0;
165 | clear: both;
166 | }
167 |
168 | .markdown p,
169 | .markdown pre {
170 | margin: 1em 0;
171 | }
172 |
173 | .markdown > p,
174 | .markdown > blockquote,
175 | .markdown > .highlight,
176 | .markdown > ol,
177 | .markdown > ul {
178 | width: 80%;
179 | }
180 |
181 | .markdown ul > li {
182 | list-style: circle;
183 | }
184 |
185 | .markdown > ul li,
186 | .markdown blockquote ul > li {
187 | margin-left: 20px;
188 | padding-left: 4px;
189 | }
190 |
191 | .markdown > ul li p,
192 | .markdown > ol li p {
193 | margin: 0.6em 0;
194 | }
195 |
196 | .markdown ol > li {
197 | list-style: decimal;
198 | }
199 |
200 | .markdown > ol li,
201 | .markdown blockquote ol > li {
202 | margin-left: 20px;
203 | padding-left: 4px;
204 | }
205 |
206 | .markdown code {
207 | margin: 0 3px;
208 | padding: 0 5px;
209 | background: #eee;
210 | border-radius: 3px;
211 | }
212 |
213 | .markdown pre {
214 | border-radius: 6px;
215 | background: #f7f7f7;
216 | padding: 20px;
217 | }
218 |
219 | .markdown pre code {
220 | border: none;
221 | background: #f7f7f7;
222 | margin: 0;
223 | }
224 |
225 | .markdown strong,
226 | .markdown b {
227 | font-weight: 600;
228 | }
229 |
230 | .markdown > table {
231 | border-collapse: collapse;
232 | border-spacing: 0px;
233 | empty-cells: show;
234 | border: 1px solid #e9e9e9;
235 | width: 95%;
236 | margin-bottom: 24px;
237 | }
238 |
239 | .markdown > table th {
240 | white-space: nowrap;
241 | color: #333;
242 | font-weight: 600;
243 |
244 | }
245 |
246 | .markdown > table th,
247 | .markdown > table td {
248 | border: 1px solid #e9e9e9;
249 | padding: 8px 16px;
250 | text-align: left;
251 | }
252 |
253 | .markdown > table th {
254 | background: #F7F7F7;
255 | }
256 |
257 | .markdown blockquote {
258 | font-size: 90%;
259 | color: #999;
260 | border-left: 4px solid #e9e9e9;
261 | padding-left: 0.8em;
262 | margin: 1em 0;
263 | font-style: italic;
264 | }
265 |
266 | .markdown blockquote p {
267 | margin: 0;
268 | }
269 |
270 | .markdown .anchor {
271 | opacity: 0;
272 | transition: opacity 0.3s ease;
273 | margin-left: 8px;
274 | }
275 |
276 | .markdown .waiting {
277 | color: #ccc;
278 | }
279 |
280 | .markdown h1:hover .anchor,
281 | .markdown h2:hover .anchor,
282 | .markdown h3:hover .anchor,
283 | .markdown h4:hover .anchor,
284 | .markdown h5:hover .anchor,
285 | .markdown h6:hover .anchor {
286 | opacity: 1;
287 | display: inline-block;
288 | }
289 |
290 | .markdown > br,
291 | .markdown > p > br {
292 | clear: both;
293 | }
294 |
295 |
296 | .hljs {
297 | display: block;
298 | background: white;
299 | padding: 0.5em;
300 | color: #333333;
301 | overflow-x: auto;
302 | }
303 |
304 | .hljs-comment,
305 | .hljs-meta {
306 | color: #969896;
307 | }
308 |
309 | .hljs-string,
310 | .hljs-variable,
311 | .hljs-template-variable,
312 | .hljs-strong,
313 | .hljs-emphasis,
314 | .hljs-quote {
315 | color: #df5000;
316 | }
317 |
318 | .hljs-keyword,
319 | .hljs-selector-tag,
320 | .hljs-type {
321 | color: #a71d5d;
322 | }
323 |
324 | .hljs-literal,
325 | .hljs-symbol,
326 | .hljs-bullet,
327 | .hljs-attribute {
328 | color: #0086b3;
329 | }
330 |
331 | .hljs-section,
332 | .hljs-name {
333 | color: #63a35c;
334 | }
335 |
336 | .hljs-tag {
337 | color: #333333;
338 | }
339 |
340 | .hljs-title,
341 | .hljs-attr,
342 | .hljs-selector-id,
343 | .hljs-selector-class,
344 | .hljs-selector-attr,
345 | .hljs-selector-pseudo {
346 | color: #795da3;
347 | }
348 |
349 | .hljs-addition {
350 | color: #55a532;
351 | background-color: #eaffea;
352 | }
353 |
354 | .hljs-deletion {
355 | color: #bd2c00;
356 | background-color: #ffecec;
357 | }
358 |
359 | .hljs-link {
360 | text-decoration: underline;
361 | }
362 |
363 | pre{
364 | background: #fff;
365 | }
366 |
367 |
368 |
369 |
370 |
371 |
--------------------------------------------------------------------------------
/APPFont/src/assets/icon/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/icon/iconfont.eot
--------------------------------------------------------------------------------
/APPFont/src/assets/icon/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/icon/iconfont.ttf
--------------------------------------------------------------------------------
/APPFont/src/assets/icon/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/icon/iconfont.woff
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/1.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/3.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/404.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/404.jpg
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/EMQ.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/EMQ.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/dataPoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/dataPoint.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/dataStream.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/dataStream.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/default-head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/default-head.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/device.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/device.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/head.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/logo.png
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/nodeMCU.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/nodeMCU.jpg
--------------------------------------------------------------------------------
/APPFont/src/assets/imgs/trigger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/src/assets/imgs/trigger.png
--------------------------------------------------------------------------------
/APPFont/src/axios.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import store from './store'
3 | import router from './router'
4 |
5 | //设置全局axios默认值
6 | // axios.defaults.timeout = 5000; //5000的超时验证
7 | // axios.defaults.baseURL = 'http://127.0.0.1:8000/';
8 | axios.defaults.baseURL = 'http://123.207.87.193:8000/';
9 | axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
10 |
11 | //创建一个axios实例
12 | const instance = axios.create();
13 | instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
14 | // axios.defaults.baseURL = 'http://127.0.0.1:8000/';
15 | axios.interceptors.request.use = instance.interceptors.request.use;
16 |
17 | //request拦截器
18 | instance.interceptors.request.use(
19 | config => {
20 | //每次发送请求之前检测都vuex存有token,那么都要放在请求头发送给服务器
21 | if (store.state.token) {
22 | config.headers.Authorization = `${store.state.token}`;
23 | }
24 | return config;
25 | },
26 | err => {
27 | return Promise.reject(err);
28 | }
29 | );
30 | //respone拦截器
31 | instance.interceptors.response.use(
32 | response => {
33 | return response;
34 | },
35 | error => { //默认除了2XX之外的都是错误的,就会走这里
36 | if (error.response) {
37 | switch (error.response.status) {
38 | case 401:
39 | store.dispatch('UserLogout'); //可能是token过期,清除它
40 | router.replace({ //跳转到登录页面
41 | path: 'login',
42 | query: {redirect: router.currentRoute.fullPath} // 将跳转的路由path作为参数,登录成功后跳转到该路由
43 | });
44 | }
45 | }
46 | return Promise.reject(error.response);
47 | }
48 | );
49 |
50 | export default {
51 | //用户注册
52 | userRegister(data) {
53 | return instance.post('/register', data);
54 | },
55 | //用户登录
56 | userLogin(data) {
57 | return instance.post('/login', data);
58 | },
59 | //获取用户
60 | getUser() {
61 | return instance.get('/api/user');
62 | },
63 | //获取概览页面数据
64 | dashboard() {
65 | return instance.get('/dashboard');
66 | },
67 | //获取历史数据
68 | charts() {
69 | return instance.get('/charts');
70 | },
71 | // 获取设备信息
72 | getDevice() {
73 | return instance.get('/devices');
74 | },
75 | // 删除设备
76 | delDevice(id,apiKey) {
77 | return instance.delete('/devices', {data:{id:id,apiKey:apiKey}});
78 | },
79 | // 更新设备信息
80 | updateDevice(data) {
81 | return instance.put('/devices', data)
82 | },
83 | // 新增设备
84 | addDevice(data) {
85 | return instance.post('/devices', data);
86 | },
87 | updateStream(data) {
88 | return instance.put('/streams', data)
89 | },
90 | addStream(data) {
91 | return instance.post('/streams', data);
92 | },
93 | delStream(id,name) {
94 | return instance.delete('/streams', {data:{dev_id:id,name:name}});
95 | },
96 | getStream(){
97 | return instance.get('/streams');
98 | },
99 | publish(data){
100 | return instance.post('/console', data)
101 | },
102 | getTrigger(){
103 | return instance.get('/triggers')
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/APPFont/src/components/developer/charts.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
102 |
103 |
115 |
--------------------------------------------------------------------------------
/APPFont/src/components/developer/console.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
如果你只是希望控制自己的设备,那么选择好设备号,输入需要发送的内容
11 |
如果你的设备订阅了自己的主题,那么需要选择自定义方式发送,填写主题名和消息内容
12 |
13 |
14 |
15 |
16 | 默认消息
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 确认发送
39 |
40 |
41 |
42 | 自定义消息
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | 确认发送
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
133 |
134 |
169 |
--------------------------------------------------------------------------------
/APPFont/src/components/developer/dashboard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
接入设备总数
9 |
{{dev_num}}
10 |
11 |
12 |
13 |
14 |
15 |
数据流模板
16 |
{{str_num}}
17 |
18 |
19 |
20 |
21 |
22 |
数据点总量
23 |
{{dp_num}}
24 |
25 |
26 |
27 |
28 |
29 |
触发器个数
30 |
{{trg_num}}
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
131 |
132 |
202 |
--------------------------------------------------------------------------------
/APPFont/src/components/developer/device.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 搜索
12 | 刷新
13 | 添加设备
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 | {{ props.row.id }}
25 |
26 |
27 | {{ props.row.name }}
28 |
29 |
30 |
32 | {{ props.row.status ?'在线' : '离线' }}
33 |
34 |
35 | {{ props.row.create_time }}
36 |
37 |
38 | {{ props.row.introduce }}
39 |
40 |
41 | {{ props.row.APIkey }}
42 |
43 |
44 |
45 | {{props.row.tag}}
46 |
47 |
48 | 无
49 |
50 |
51 |
52 | {{ props.row.stream_num }}
53 |
54 |
55 | 编辑设备信息
56 | 删除设备
57 |
58 |
59 |
60 |
61 |
64 |
65 |
68 |
69 |
72 |
73 |
75 |
76 | {{ scope.row.status ?'在线' : '离线' }}
77 |
78 |
79 |
80 |
83 |
84 |
87 |
88 |
89 | {{scope.row.tag}}
90 |
91 |
92 | 无
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
138 |
139 |
140 |
141 |
142 |
143 |
283 |
284 |
331 |
--------------------------------------------------------------------------------
/APPFont/src/components/developer/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
32 |
64 |
--------------------------------------------------------------------------------
/APPFont/src/components/developer/leftNavBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
36 |
37 |
38 |
39 |
40 |
41 |
51 |
52 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/APPFont/src/components/developer/topNavBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
26 |
27 |
42 |
68 |
--------------------------------------------------------------------------------
/APPFont/src/components/developer/trigger.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
31 |
35 |
36 |
40 |
41 |
42 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
82 |
83 |
98 |
--------------------------------------------------------------------------------
/APPFont/src/components/home/document.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
29 |
--------------------------------------------------------------------------------
/APPFont/src/components/home/footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
17 |
18 |
30 |
--------------------------------------------------------------------------------
/APPFont/src/components/home/home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
36 |
48 |
--------------------------------------------------------------------------------
/APPFont/src/components/home/introduce.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
MQTT协议
19 |
支持大多数MQTT协议的物联网设备的接入,提供Arduino接入实例
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
网页控制
28 |
在开发者中心可对接入设备进行管理、查看、下发指令
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
微信通知
37 |
绑定微信后可随时随地通过微信公众号实现网页端操作,接收触发器通知
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
51 |
52 |

53 |
54 |
55 |
基于EMQ消息服务
56 |
MQTT协议,可用传感器数据储存,或是中继服务器,组件自己的传感器网络
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
高适用性
65 |
对于连接设备的性能没有要求,有网络支持MQTT协议即可使用
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
适用人群
74 |
适用于创客和物联网爱好者,有能力编写基本的硬件连接代码
75 |
76 |
77 |
78 |
79 |
80 |
81 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
天气服务
92 |
实时广播各大城市天气信息
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
邮箱服务
101 |
预设报警信息主动推送
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
微信服务
110 |
公众号操作使用更方便
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
API接口
119 |
开放API方便二次开发
120 |
121 |
122 |
123 |
124 |
125 |
126 |
154 |
274 |
--------------------------------------------------------------------------------
/APPFont/src/components/home/resource.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/APPFont/src/components/home/topNavBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
55 |
56 |
57 |
58 |
59 |
74 |
99 |
--------------------------------------------------------------------------------
/APPFont/src/components/identify.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
133 |
--------------------------------------------------------------------------------
/APPFont/src/components/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 欢迎使用IOTforFML开放平台!
15 |
16 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
28 |
29 |
30 |
32 |
33 |
34 |
35 |
36 |
37 | 自动登录
38 | 忘记密码?
39 |
40 |
41 | 立即登录
42 | 取消
43 |
44 |
45 |
46 |
47 | 没有账户?现在就去注册吧→
48 | 立即注册
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
186 |
187 |
188 |
240 |
--------------------------------------------------------------------------------
/APPFont/src/components/notFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
15 |
18 |
--------------------------------------------------------------------------------
/APPFont/src/components/register.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 欢迎注册IOTforFML开放平台!
15 |
16 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
28 |
29 |
30 |
32 |
33 |
34 |
36 |
37 |
38 |
40 |
41 |
42 |
43 |
44 |
45 | 立即注册
46 | 再看一看
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
202 |
203 |
204 |
250 |
--------------------------------------------------------------------------------
/APPFont/src/components/test.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 提交
15 | 重置
16 |
17 |
18 |
19 |
20 |
94 |
--------------------------------------------------------------------------------
/APPFont/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App'
5 | //引入路由
6 | import router from './router'
7 |
8 | //引入elementUI
9 | import ElementUI from 'element-ui'
10 | import 'element-ui/lib/theme-chalk/index.css'
11 | //引入图标
12 | import './assets/icon/iconfont.css'
13 | import SIdentify from './components/identify'
14 | Vue.use(SIdentify);
15 |
16 | //安装插件
17 | Vue.use(ElementUI);
18 |
19 | //引入axios
20 | // import Axios from 'axios'
21 | // //设置全局URL
22 | // Axios.defaults.baseURL = 'http://127.0.0.1:8000/';
23 | // Axios.defaults.headers.common["Authorization"] = '9a14fb9da6d2ffbf1d0e663d401e201b';
24 | // // Axios.defaults.headers.common["Authorization"] = '7a88e6d7177a1360b06a3a437079c34d';
25 | // Axios.defaults.headers.post['Content-Type']='application/x-www-form-urlencoded';
26 | // Vue.prototype.$axios = Axios;
27 |
28 |
29 |
30 |
31 | import store from './store'
32 |
33 |
34 |
35 |
36 |
37 | //引入echarts
38 | import echarts from 'echarts'
39 | Vue.prototype.$echarts = echarts;
40 |
41 |
42 | // router.beforeEach((to, from, next) => {
43 | // next()
44 | // });
45 |
46 | new Vue({
47 | el: '#app',
48 | router,
49 | store,
50 | components: { App },
51 | template: ''
52 | });
53 |
--------------------------------------------------------------------------------
/APPFont/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import store from '../store/index.js'
3 | import Router from 'vue-router'
4 |
5 | //路由懒加载
6 |
7 | const Home = resolve => {
8 | require.ensure(['../components/home/Home.vue'], () => {
9 | resolve(require('../components/home/Home.vue'));
10 | });
11 | };
12 |
13 | const Document = resolve => {
14 | require.ensure(['../components/home/document.vue'], () => {
15 | resolve(require('../components/home/document.vue'));
16 | });
17 | };
18 |
19 | const Introduce = resolve => {
20 | require.ensure(['../components/home/introduce.vue'], () => {
21 | resolve(require('../components/home/introduce.vue'));
22 | });
23 | };
24 |
25 | const Resource = resolve => {
26 | require.ensure(['../components/home/resource.vue'], () => {
27 | resolve(require('../components/home/resource.vue'));
28 | });
29 | };
30 |
31 | const Login = resolve => {
32 | require.ensure(['../components/login.vue'], () => {
33 | resolve(require('../components/login.vue'));
34 | });
35 | };
36 |
37 | const Register = resolve => {
38 | require.ensure(['../components/register.vue'], () => {
39 | resolve(require('../components/register'));
40 | });
41 | };
42 |
43 | const NotFound = resolve => {
44 | require.ensure(['../components/notFound.vue'], () => {
45 | resolve(require('../components/notFound.vue'));
46 | });
47 | };
48 |
49 | import Developer from '../components/developer/index'
50 | import Dashboard from '../components/developer/dashboard'
51 | import Charts from '../components/developer/charts'
52 | import Devices from '../components/developer/device'
53 | import Streams from '../components/developer/stream'
54 | import Triggers from '../components/developer/trigger'
55 | import Console from '../components/developer/console'
56 | import test from '../components/test'
57 |
58 | Vue.use(Router);
59 |
60 | const router = new Router({
61 | mode:'history',
62 | routes: [
63 | {path: '/', redirect: {path: '/home/introduce'}},
64 | {path: '/home', redirect: {path: '/home/introduce'}},
65 | {path: '/developer', redirect: {path: '/developer/dashboard'}},
66 | {
67 | name: 'home',
68 | path: '/home',
69 | component: Home,
70 | children: [
71 | {name: 'introduce', path: 'introduce', component: Introduce},
72 | {name: 'document', path: 'document', component: Document},
73 | {name: 'resource', path: 'resource', component: Resource},
74 | ]
75 | },
76 | {
77 | name: 'developer',
78 | path: '/developer',
79 | component: Developer,
80 | meta: {
81 | requiresAuth: true
82 | },
83 | children: [
84 | {name: 'dashboard', path: 'dashboard', component: Dashboard,meta: {requiresAuth: true}},
85 | {name: 'charts', path: 'charts', component: Charts,meta: {requiresAuth: true}},
86 | {name: 'devices', path: 'devices', component: Devices,meta: {requiresAuth: true}},
87 | {name: 'streams', path: 'streams', component: Streams,meta: {requiresAuth: true}},
88 | {name: 'console', path: 'console', component: Console,meta: {requiresAuth: true}},
89 | {name: 'triggers', path: 'triggers', component: Triggers,meta: {requiresAuth: true}},
90 | ]
91 | },
92 | {name: 'login', path: '/login', component: Login},
93 | {name: 'register', path: '/register', component: Register},
94 | {name: 'test', path: '/test', component: test},
95 | {path: '*', component: NotFound}
96 | ]
97 | });
98 |
99 | router.beforeEach((to, from, next) => {
100 | //获取store里面的token
101 | let token = store.state.token;
102 | //判断要去的路由有没有requiresAuth
103 | if (to.meta.requiresAuth) {
104 |
105 | if (token) {
106 | next();
107 | } else {
108 | next({
109 | path: '/login',
110 | query: {redirect: to.fullPath} // 将刚刚要去的路由path(却无权限)作为参数,方便登录成功后直接跳转到该路由
111 | });
112 | }
113 |
114 | } else {
115 | next();//如果无需token,那么随它去吧
116 | }
117 | });
118 | export default router;
119 |
120 |
--------------------------------------------------------------------------------
/APPFont/src/store/actions.js:
--------------------------------------------------------------------------------
1 | import * as types from './types.js'
2 |
3 | //actions常用于异步更改状态。也就是说它一般用来先发送请求,然后再commit
4 |
5 | //下面的代码可以说没必要。没发请求,多此一举。因为项目很久之前写的,这里我就不做大更改了,更改看下面
6 | //对于vuex不是很理解的可不看下面,先跟着我先的代码走一遍,之后思想明了,自己再做更改即可。写代码就是这样,刚开始难以写一手漂亮的代码。
7 | //直接在页面发送请求后再store.commit()是完全可以的
8 | export default {
9 | UserLogin({ commit }, data){
10 | commit(types.LOGIN, data);
11 | },
12 | UserLogout({ commit }){
13 | commit(types.LOGOUT);
14 | },
15 | UserName({ commit }, data){
16 | commit(types.USERNAME, data);
17 | }
18 | }
19 |
20 | //改法:
21 | //举个例子:先引入api, 利用载荷拿到参数,然后发送登录请求
22 | // import api from '../axios.js';
23 | // export default {
24 | // actions需要返回一个promise对象,是用于通知外面该actions执行完毕。(官网有写)
25 | // UserLogin({ commit }, { username, password }){
26 | //
27 | // return new Promise((resolve, reject) => {
28 | // api.userLogin({ username, password})
29 | // .then(res => {
30 | // //登录成功
31 | // if(res.data.success === true){
32 | // let token = res.data.data.token;
33 | // commit(types.LOGIN, token);
34 | // resolve(res.data.success);
35 | // }
36 | // //登录失败: 用户名或密码错误
37 | // if(res.data.success === false){
38 | // commit(types.LOGOUT);
39 | // resolve(res.data.success)
40 | // }
41 | // })
42 | // .catch(err => {
43 | // reject(err);
44 | // });
45 | // });
46 | //
47 | // }
48 | // }
49 |
--------------------------------------------------------------------------------
/APPFont/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | import mutations from './mutations.js'
5 | import actions from './actions.js'
6 |
7 |
8 | Vue.use(Vuex);
9 |
10 | //初始化时用sessionStore.getItem('token'),这样子刷新页面就无需重新登录
11 | const state = {
12 | token: window.sessionStorage.getItem('token'),
13 | username: ''
14 | };
15 |
16 | export default new Vuex.Store({
17 | state,
18 | mutations,
19 | actions
20 | });
--------------------------------------------------------------------------------
/APPFont/src/store/mutations.js:
--------------------------------------------------------------------------------
1 | import * as types from './types.js'
2 |
3 | //关于token的存放位置
4 | //1.只用vuex存储:刷新页面vuex重新初始化,token消失导致需要重新登录
5 | //2.window.sessionStorage: 初始化的时候用sessionStorage来赋值,刷新页面重新初始化,但因为sessionStorage里面存有token有值,
6 | //那么state.token就有值了,vue-router就不会拦截,则无需重新登录。(这个demo用的是这种)
7 | //3.window.localStorage: 初始化的时候用localStorage来赋值,这种情况跟sessionStorage差不多。后台配合给长时间有效的token比较好,
8 | //如果token的有效期比较短,直接有sessionStorage比较好。
9 |
10 | const mutations = {
11 | [types.LOGIN]: (state, data) => {
12 | //更改token的值
13 | state.token = data;
14 | window.sessionStorage.setItem('token', data);
15 | },
16 | [types.LOGOUT]: (state) => {
17 | //登出的时候要清除token
18 | state.token = null;
19 | window.sessionStorage.removeItem('token');
20 | },
21 | //这步可有可无,根据自己需求去写
22 | [types.USERNAME]: (state, data) => {
23 | //把用户名存起来
24 | state.username = data;
25 | window.sessionStorage.setItem('username', data);
26 | }
27 | };
28 |
29 | export default mutations;
--------------------------------------------------------------------------------
/APPFont/src/store/types.js:
--------------------------------------------------------------------------------
1 | //常量用来给mutations用
2 | export const LOGIN = 'LOGIN';
3 |
4 | export const LOGOUT = 'LOGOUT';
5 |
6 | export const USERNAME = 'USERNAME';
--------------------------------------------------------------------------------
/APPFont/static/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/APPFont/static/.gitkeep
--------------------------------------------------------------------------------
/Hardware/NodeMCU_MQTT/NodeMCU_MQTT.ino:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 |
5 | // Update these with values suitable for your network.
6 |
7 | const char* ssid = "JKGY-5F";
8 | const char* password = "jkgy2017";
9 | const char* mqtt_server = "123.207.87.193";
10 |
11 | WiFiClient espClient;
12 | PubSubClient client(espClient);
13 | long lastMsg = 0;
14 | char msg[50];
15 | int value = 0;
16 | int randNum;
17 | void setup() {
18 | pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
19 | Serial.begin(115200);
20 | setup_wifi();
21 | client.setServer(mqtt_server, 1883);
22 | client.setCallback(callback);
23 | }
24 |
25 | void setup_wifi() {
26 |
27 | delay(10);
28 | // We start by connecting to a WiFi network
29 | Serial.println();
30 | Serial.print("Connecting to ");
31 | Serial.println(ssid);
32 |
33 | WiFi.begin(ssid, password);
34 |
35 | while (WiFi.status() != WL_CONNECTED) {
36 | delay(500);
37 | Serial.print(".");
38 | }
39 |
40 | Serial.println("");
41 | Serial.println("WiFi connected");
42 | Serial.println("IP address: ");
43 | Serial.println(WiFi.localIP());
44 | }
45 |
46 | void callback(char* topic, byte* payload, unsigned int length) {
47 | Serial.print("Message arrived [");
48 | Serial.print(topic);
49 | Serial.print("] ");
50 | for (int i = 0; i < length; i++) {
51 | Serial.print((char)payload[i]);
52 | }
53 | Serial.println();
54 |
55 | // Switch on the LED if an 1 was received as first character
56 | if ((char)payload[0] == '1') {
57 | digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
58 | // but actually the LED is on; this is because
59 | // it is acive low on the ESP-01)
60 | } else {
61 | digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
62 | }
63 |
64 | }
65 |
66 | void reconnect() {
67 | // Loop until we're reconnected
68 | while (!client.connected()) {
69 | Serial.print("Attempting MQTT connection...");
70 | // Attempt to connect
71 | if (client.connect("123456","123","123")) {
72 | Serial.println("connected");
73 | client.publish("123456/temp1", "1");
74 | } else {
75 | Serial.print("failed, rc=");
76 | Serial.print(client.state());
77 | Serial.println(" try again in 5 seconds");
78 | // Wait 5 seconds before retrying
79 | delay(5000);
80 | }
81 | }
82 | }
83 | void loop() {
84 |
85 | if (!client.connected()) {
86 | reconnect();
87 | }
88 | client.loop();
89 |
90 | long now = millis();
91 | if (now - lastMsg > 2000) {
92 | lastMsg = now;
93 | ++value;
94 | snprintf (msg, 75, "%ld", value);
95 | Serial.print("Publish message: ");
96 | Serial.println(msg);
97 | client.publish("123456/temp1", msg);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/IOTPlatform/.idea/IOTPlatform.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/IOTPlatform/.idea/dataSources.local.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #@
7 | `
8 |
9 |
10 | master_key
11 | root
12 | *:IOTPlatform
13 |
14 |
15 |
--------------------------------------------------------------------------------
/IOTPlatform/.idea/dataSources.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | mysql
6 | true
7 | com.mysql.jdbc.Driver
8 | jdbc:mysql://123.207.87.193:3306/IOTPlatform
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/IOTPlatform/.idea/dictionaries/fml.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | cloop
5 | cors
6 | corsheaders
7 | csrftoken
8 | keepalive
9 | mqtt
10 |
11 |
12 |
--------------------------------------------------------------------------------
/IOTPlatform/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/IOTPlatform/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/IOTPlatform/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__init__.py:
--------------------------------------------------------------------------------
1 | import pymysql
2 | # from utils.mqtt_client import MqClient
3 |
4 | pymysql.install_as_MySQLdb()
5 |
6 |
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/IOTPlatform/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/IOTPlatform/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__pycache__/settings.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/IOTPlatform/__pycache__/settings.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__pycache__/settings.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/IOTPlatform/__pycache__/settings.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__pycache__/urls.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/IOTPlatform/__pycache__/urls.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__pycache__/urls.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/IOTPlatform/__pycache__/urls.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__pycache__/wsgi.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/IOTPlatform/__pycache__/wsgi.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/__pycache__/wsgi.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/IOTPlatform/__pycache__/wsgi.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for IOTPlatform project.
3 |
4 | Generated by 'django-admin startproject' using Django 2.1.2.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.1/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/2.1/ref/settings/
11 | """
12 |
13 |
14 | import os
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '8byztyq^ile$4-4#ph=r88ic)^a4ry^068yd5!p)dio+r0oi#l'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = ['*',]
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = (
34 | 'django.contrib.admin',
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | 'django.contrib.staticfiles',
40 | 'corsheaders',
41 | 'rest_framework',
42 | 'website',
43 | 'weixin',
44 | )
45 |
46 | MIDDLEWARE = [
47 | 'django.middleware.security.SecurityMiddleware',
48 | 'django.contrib.sessions.middleware.SessionMiddleware',
49 | 'corsheaders.middleware.CorsMiddleware',
50 | 'django.middleware.common.CommonMiddleware',
51 | # 'django.middleware.csrf.CsrfViewMiddleware',
52 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
53 | 'django.contrib.messages.middleware.MessageMiddleware',
54 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
55 | ]
56 |
57 | ROOT_URLCONF = 'IOTPlatform.urls'
58 |
59 | TEMPLATES = [
60 | {
61 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
62 | 'DIRS': [],
63 | 'APP_DIRS': True,
64 | 'OPTIONS': {
65 | 'context_processors': [
66 | 'django.template.context_processors.debug',
67 | 'django.template.context_processors.request',
68 | 'django.contrib.auth.context_processors.auth',
69 | 'django.contrib.messages.context_processors.messages',
70 | ],
71 | },
72 | },
73 | ]
74 |
75 | WSGI_APPLICATION = 'IOTPlatform.wsgi.application'
76 |
77 |
78 | # Database
79 | # https://docs.djangoproject.com/en/2.1/ref/settings/#databases
80 |
81 |
82 | DATABASES = {
83 | 'default': {
84 | 'ENGINE': 'django.db.backends.mysql',
85 | 'NAME': 'IOTPlatform',
86 | 'USER': '***',
87 | 'PASSWORD': '****',
88 | 'HOST': '****',
89 | 'PORT': '3306',
90 | }
91 | }
92 |
93 |
94 | # Password validation
95 | # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
96 |
97 | AUTH_PASSWORD_VALIDATORS = [
98 | {
99 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
100 | },
101 | {
102 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
103 | },
104 | {
105 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
106 | },
107 | {
108 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
109 | },
110 | ]
111 |
112 |
113 | # Internationalization
114 | # https://docs.djangoproject.com/en/2.1/topics/i18n/
115 |
116 | LANGUAGE_CODE = 'zh-Hans'
117 |
118 | TIME_ZONE = 'Asia/Shanghai'
119 |
120 | USE_I18N = True
121 |
122 | USE_L10N = True
123 |
124 | USE_TZ = False
125 |
126 | # Static files (CSS, JavaScript, Images)
127 | # https://docs.djangoproject.com/en/2.1/howto/static-files/
128 |
129 |
130 |
131 | STATIC_URL = '/static/'
132 |
133 | TEMPLATE_DIRS = (os.path.join(BASE_DIR, 'templates'),)
134 |
135 |
136 | # cors跨域设置
137 | CORS_ALLOW_CREDENTIALS = True
138 | CORS_ORIGIN_ALLOW_ALL = True
139 | CORS_ORIGIN_WHITELIST = (
140 | "*"
141 | )
142 | CORS_ALLOW_METHODS = (
143 | 'DELETE',
144 | 'GET',
145 | 'OPTIONS',
146 | 'PATCH',
147 | 'POST',
148 | 'PUT',
149 | 'VIEW',
150 | )
151 |
152 | CORS_ALLOW_HEADERS = (
153 | 'XMLHttpRequest',
154 | 'X_FILENAME',
155 | 'accept-encoding',
156 | 'authorization',
157 | 'content-type',
158 | 'dnt',
159 | 'origin',
160 | 'user-agent',
161 | 'x-csrftoken',
162 | 'x-requested-with',
163 | 'Pragma',
164 | )
165 |
166 | # rest_framework全局权限认证类
167 | REST_FRAMEWORK = {
168 | "DEFAULT_AUTHENTICATION_CLASSES": ["website.utils.auth.Authtication"]
169 | }
170 |
171 |
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/urls.py:
--------------------------------------------------------------------------------
1 | """IOTPlatform URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/2.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path, include
18 | urlpatterns = [
19 | path(r'', include('website.urls')),
20 | path(r'wx/', include('weixin.urls')),
21 |
22 | ]
23 |
--------------------------------------------------------------------------------
/IOTPlatform/IOTPlatform/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for IOTPlatform project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'IOTPlatform.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/IOTPlatform/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == '__main__':
6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'IOTPlatform.settings')
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError as exc:
10 | raise ImportError(
11 | "Couldn't import Django. Are you sure it's installed and "
12 | "available on your PYTHONPATH environment variable? Did you "
13 | "forget to activate a virtual environment?"
14 | ) from exc
15 | execute_from_command_line(sys.argv)
16 |
--------------------------------------------------------------------------------
/IOTPlatform/middleware/__pycache__/authentication.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/middleware/__pycache__/authentication.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/middleware/authentication.py:
--------------------------------------------------------------------------------
1 | from django.utils.deprecation import MiddlewareMixin
2 | from django.shortcuts import render, HttpResponse, redirect
3 | from website.datebase import API
4 |
5 |
6 | class AuthMiddleware(MiddlewareMixin):
7 | '''
8 | 用户登录验证中间件
9 | '''
10 | def process_request(self, request):
11 | print(request.COOKIES.get('is_log', None))
12 | print(request.COOKIES.get('username', None))
13 | print(request.path)
14 | # print(API().get_user_aid(request.COOKIES.get('username')))
15 | if request.path != '/oa/login':
16 | # 如果不是登录页面并且没有登录状态则跳转到登录界面
17 | if request.COOKIES.get('is_log', None):
18 | name = request.COOKIES.get('username',None)
19 | if name:
20 | # 获取权限列表中的url
21 | url = API().get_user_url(name)
22 | url.append('/oa/error')
23 | url.append('/oa/userapi')
24 | url.append('/oa/api')
25 | url.append('/oa/device')
26 | url.append('/oa/logout')
27 | url.append('/oa/login')
28 | url.append('/oa/input/')
29 | if url:
30 | if request.path in url:
31 | return
32 | else:
33 | return render(request, '../templates/website/bad_request.html')
34 | else:
35 | return redirect('/oa/login')
36 | else:
37 | return
38 |
39 | def process_view(self, request, callback, callback_args, callback_kwargs):
40 | pass
41 |
42 | def process_response(self, request):
43 | pass
44 |
45 | def process_exception(self, request, exception):
46 | pass
47 |
48 | def process_response(self, request, response):
49 | return response
50 |
51 |
--------------------------------------------------------------------------------
/IOTPlatform/utils/__pycache__/models.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/utils/__pycache__/models.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/utils/__pycache__/time_tools.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/utils/__pycache__/time_tools.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/utils/database.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import create_engine
2 | from sqlalchemy.orm import sessionmaker
3 | from models import * # 导入生成的model
4 |
5 |
6 | class DB(object):
7 | def __init__(self):
8 | engine = create_engine('mysql+pymysql://root:fml950826cs@123.207.87.193:3306/IOTPlatform')
9 | Session = sessionmaker(bind=engine)
10 | self.session = Session()
11 |
12 |
13 | def update_dev_stus(self, device_id, status):
14 | """
15 | 更改设备状态
16 | :param device_id: 设备ID
17 | :param status: 状态
18 | :return: None
19 | """
20 | try:
21 | self.session.query(WebsiteDevice).filter(WebsiteDevice.device_id==device_id).update({WebsiteDevice.dev_status:status})
22 | self.session.flush()
23 | self.session.commit()
24 | return True
25 | except Exception as e:
26 | return False
27 |
28 |
29 |
30 | # db = DB()
31 | # db.update_dev_stus(123456,0)
--------------------------------------------------------------------------------
/IOTPlatform/utils/models.py:
--------------------------------------------------------------------------------
1 | # pip install sqlacodegen
2 | # sqlacodegen mysql+pymysql://root:fml950826cs@123.207.87.193:3306/IOTPlatform > models.py
3 |
4 |
5 | # coding: utf-8
6 | from sqlalchemy import Column, ForeignKey, Index, String
7 | from sqlalchemy.dialects.mysql import DATETIME, INTEGER, LONGTEXT, SMALLINT, TINYINT, VARCHAR
8 | from sqlalchemy.orm import relationship
9 | from sqlalchemy.ext.declarative import declarative_base
10 |
11 | Base = declarative_base()
12 | metadata = Base.metadata
13 |
14 |
15 | class AuthGroup(Base):
16 | __tablename__ = 'auth_group'
17 |
18 | id = Column(INTEGER(11), primary_key=True)
19 | name = Column(String(80), nullable=False, unique=True)
20 |
21 |
22 | class AuthUser(Base):
23 | __tablename__ = 'auth_user'
24 |
25 | id = Column(INTEGER(11), primary_key=True)
26 | password = Column(String(128), nullable=False)
27 | last_login = Column(DATETIME(fsp=6))
28 | is_superuser = Column(TINYINT(1), nullable=False)
29 | username = Column(String(150), nullable=False, unique=True)
30 | first_name = Column(String(30), nullable=False)
31 | last_name = Column(String(150), nullable=False)
32 | email = Column(String(254), nullable=False)
33 | is_staff = Column(TINYINT(1), nullable=False)
34 | is_active = Column(TINYINT(1), nullable=False)
35 | date_joined = Column(DATETIME(fsp=6), nullable=False)
36 |
37 |
38 | class DjangoContentType(Base):
39 | __tablename__ = 'django_content_type'
40 | __table_args__ = (
41 | Index('django_content_type_app_label_model_76bd3d3b_uniq', 'app_label', 'model', unique=True),
42 | )
43 |
44 | id = Column(INTEGER(11), primary_key=True)
45 | app_label = Column(String(100), nullable=False)
46 | model = Column(String(100), nullable=False)
47 |
48 |
49 | class DjangoMigration(Base):
50 | __tablename__ = 'django_migrations'
51 |
52 | id = Column(INTEGER(11), primary_key=True)
53 | app = Column(String(255), nullable=False)
54 | name = Column(String(255), nullable=False)
55 | applied = Column(DATETIME(fsp=6), nullable=False)
56 |
57 |
58 | class DjangoSession(Base):
59 | __tablename__ = 'django_session'
60 |
61 | session_key = Column(String(40), primary_key=True)
62 | session_data = Column(LONGTEXT, nullable=False)
63 | expire_date = Column(DATETIME(fsp=6), nullable=False, index=True)
64 |
65 |
66 | class WebsiteDatum(Base):
67 | __tablename__ = 'website_data'
68 |
69 | id = Column(INTEGER(11), primary_key=True)
70 | data = Column(String(10), nullable=False)
71 | date = Column(DATETIME(fsp=6), nullable=False)
72 |
73 |
74 | class WebsiteDatastream(Base):
75 | __tablename__ = 'website_datastream'
76 |
77 | id = Column(INTEGER(11), primary_key=True)
78 | name = Column(VARCHAR(32), nullable=False)
79 | min = Column(INTEGER(11))
80 | max = Column(INTEGER(11))
81 | qos = Column(INTEGER(11), nullable=False)
82 | unit = Column(VARCHAR(32))
83 | unit_symbol = Column(VARCHAR(32))
84 | trigger = Column(TINYINT(1), nullable=False)
85 |
86 |
87 | class WebsiteDevice(Base):
88 | __tablename__ = 'website_device'
89 |
90 | id = Column(INTEGER(11), primary_key=True)
91 | device_id = Column(INTEGER(11), nullable=False, unique=True)
92 | device_key = Column(String(32))
93 | device_name = Column(VARCHAR(32), nullable=False)
94 | dev_status = Column(TINYINT(1), nullable=False)
95 | apiKey = Column(String(32))
96 | date = Column(DATETIME(fsp=6), nullable=False)
97 | dev_introduce = Column(LONGTEXT)
98 | tag = Column(VARCHAR(32))
99 |
100 |
101 | class WebsiteUserinfo(Base):
102 | __tablename__ = 'website_userinfo'
103 |
104 | id = Column(INTEGER(11), primary_key=True)
105 | username = Column(VARCHAR(32), nullable=False, unique=True)
106 | user_id = Column(INTEGER(11), nullable=False, unique=True)
107 | password = Column(VARCHAR(64), nullable=False)
108 | weixin_id = Column(VARCHAR(64), index=True)
109 | sex = Column(VARCHAR(16))
110 | birthday = Column(VARCHAR(64))
111 | tel = Column(VARCHAR(64))
112 | email = Column(VARCHAR(64))
113 | address = Column(VARCHAR(64))
114 | introduction = Column(VARCHAR(255))
115 | token = Column(VARCHAR(255))
116 |
117 |
118 | class AuthPermission(Base):
119 | __tablename__ = 'auth_permission'
120 | __table_args__ = (
121 | Index('auth_permission_content_type_id_codename_01ab375a_uniq', 'content_type_id', 'codename', unique=True),
122 | )
123 |
124 | id = Column(INTEGER(11), primary_key=True)
125 | name = Column(String(255), nullable=False)
126 | content_type_id = Column(ForeignKey('django_content_type.id'), nullable=False)
127 | codename = Column(String(100), nullable=False)
128 |
129 | content_type = relationship('DjangoContentType')
130 |
131 |
132 | class AuthUserGroup(Base):
133 | __tablename__ = 'auth_user_groups'
134 | __table_args__ = (
135 | Index('auth_user_groups_user_id_group_id_94350c0c_uniq', 'user_id', 'group_id', unique=True),
136 | )
137 |
138 | id = Column(INTEGER(11), primary_key=True)
139 | user_id = Column(ForeignKey('auth_user.id'), nullable=False)
140 | group_id = Column(ForeignKey('auth_group.id'), nullable=False, index=True)
141 |
142 | group = relationship('AuthGroup')
143 | user = relationship('AuthUser')
144 |
145 |
146 | class DjangoAdminLog(Base):
147 | __tablename__ = 'django_admin_log'
148 |
149 | id = Column(INTEGER(11), primary_key=True)
150 | action_time = Column(DATETIME(fsp=6), nullable=False)
151 | object_id = Column(LONGTEXT)
152 | object_repr = Column(String(200), nullable=False)
153 | action_flag = Column(SMALLINT(5), nullable=False)
154 | change_message = Column(LONGTEXT, nullable=False)
155 | content_type_id = Column(ForeignKey('django_content_type.id'), index=True)
156 | user_id = Column(ForeignKey('auth_user.id'), nullable=False, index=True)
157 |
158 | content_type = relationship('DjangoContentType')
159 | user = relationship('AuthUser')
160 |
161 |
162 | class WebsiteDatastreamDatum(Base):
163 | __tablename__ = 'website_datastream_data'
164 | __table_args__ = (
165 | Index('website_datastream_data_datastream_id_data_id_3b3216eb_uniq', 'datastream_id', 'data_id', unique=True),
166 | )
167 |
168 | id = Column(INTEGER(11), primary_key=True)
169 | datastream_id = Column(ForeignKey('website_datastream.id'), nullable=False)
170 | data_id = Column(ForeignKey('website_data.id'), nullable=False, index=True)
171 |
172 | data = relationship('WebsiteDatum')
173 | datastream = relationship('WebsiteDatastream')
174 |
175 |
176 | class WebsiteDeviceDevStream(Base):
177 | __tablename__ = 'website_device_dev_stream'
178 | __table_args__ = (
179 | Index('website_device_dev_stream_device_id_datastream_id_6d32e5c0_uniq', 'device_id', 'datastream_id', unique=True),
180 | )
181 |
182 | id = Column(INTEGER(11), primary_key=True)
183 | device_id = Column(ForeignKey('website_device.id'), nullable=False)
184 | datastream_id = Column(ForeignKey('website_datastream.id'), nullable=False, index=True)
185 |
186 | datastream = relationship('WebsiteDatastream')
187 | device = relationship('WebsiteDevice')
188 |
189 |
190 | class WebsiteUserinfoDevice(Base):
191 | __tablename__ = 'website_userinfo_device'
192 | __table_args__ = (
193 | Index('website_userinfo_device_userinfo_id_device_id_e34001e8_uniq', 'userinfo_id', 'device_id', unique=True),
194 | )
195 |
196 | id = Column(INTEGER(11), primary_key=True)
197 | userinfo_id = Column(ForeignKey('website_userinfo.id'), nullable=False)
198 | device_id = Column(ForeignKey('website_device.id'), nullable=False, index=True)
199 |
200 | device = relationship('WebsiteDevice')
201 | userinfo = relationship('WebsiteUserinfo')
202 |
203 |
204 | class AuthGroupPermission(Base):
205 | __tablename__ = 'auth_group_permissions'
206 | __table_args__ = (
207 | Index('auth_group_permissions_group_id_permission_id_0cd325b0_uniq', 'group_id', 'permission_id', unique=True),
208 | )
209 |
210 | id = Column(INTEGER(11), primary_key=True)
211 | group_id = Column(ForeignKey('auth_group.id'), nullable=False)
212 | permission_id = Column(ForeignKey('auth_permission.id'), nullable=False, index=True)
213 |
214 | group = relationship('AuthGroup')
215 | permission = relationship('AuthPermission')
216 |
217 |
218 | class AuthUserUserPermission(Base):
219 | __tablename__ = 'auth_user_user_permissions'
220 | __table_args__ = (
221 | Index('auth_user_user_permissions_user_id_permission_id_14a6b632_uniq', 'user_id', 'permission_id', unique=True),
222 | )
223 |
224 | id = Column(INTEGER(11), primary_key=True)
225 | user_id = Column(ForeignKey('auth_user.id'), nullable=False)
226 | permission_id = Column(ForeignKey('auth_permission.id'), nullable=False, index=True)
227 |
228 | permission = relationship('AuthPermission')
229 | user = relationship('AuthUser')
230 |
--------------------------------------------------------------------------------
/IOTPlatform/utils/mqtt_client.py:
--------------------------------------------------------------------------------
1 | import paho.mqtt.client as client
2 | import threading
3 | from database import DB
4 |
5 | class MqClient(object):
6 | def __init__(self, client_id, username, password):
7 | self.client = client.Client(client_id=client_id,
8 | clean_session=True) # 初始化,clean_session为false的时候EMQ会保存订阅状态,可以不再次订阅
9 | self.client.username_pw_set(username, password) # 设置连接用户名
10 | self.client.on_connect = self.on_connect
11 | self.client.on_message = self.on_message
12 | self._client_status = False # 连接状态
13 | self._cloop = None
14 | self._connect() # 实例化会自动连接
15 | self.db = DB()
16 |
17 | def _connect(self, host="123.207.87.193", port=1883, keepalive=60):
18 | """连接服务器"""
19 | self.client.connect_async(host, port, keepalive)
20 | # self.client.loop_forever()
21 | # 开启线程执行
22 | self._cloop = threading.Thread(target=self.client.loop_start())
23 | self._cloop.start()
24 |
25 | def on_connect(self, client, userdata, flags, rc):
26 | """连接成功的回调函数"""
27 | # 订阅上下线消息
28 | self.client.subscribe("$SYS/brokers/emq@127.0.0.1/clients/#")
29 | # 修改客户端状态
30 | if rc == 0:
31 | self._client_status = True
32 |
33 | def init_sub(self):
34 |
35 | # 读取数据库中所有的已经注册过的topic并且订阅
36 | # for i in models.Device.objects.all():
37 | # for j in i.dev_stream.all():
38 | # self.client.subscribe(str(i.device_id) + '/' + j.name, j.qos)
39 | pass
40 |
41 | def on_message(self,client, userdata, msg):
42 | topic = msg.topic.split('/')
43 | client = topic[0]
44 | # 系统主题
45 | if client=='$SYS':
46 | status = 1 if topic[-1] == 'connected' else 0
47 | device_id = topic[-2]
48 | print(status,device_id)
49 | # 修改设备在线状态
50 | print(self.db.update_dev_stus(device_id, status))
51 | # print(status,id)
52 | # print(models.Device.objects.filter(device_id=id).update(dev_status=status))
53 |
54 | # else:
55 | # stream = topic[1]
56 | # data = msg.payload.decode()
57 | # # print(client_id,data_stream,data)
58 | # # 接收订阅信息写入到数据库中
59 | # models.DataStream.objects.filter(device__device_id=client).filter(name=stream).first().data.add(
60 | # models.Data.objects.create(data=data))
61 | # pass
62 |
63 | c = MqClient('System', '123', '123')
64 | while True:
65 | pass
66 |
67 |
--------------------------------------------------------------------------------
/IOTPlatform/utils/time_tools.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime, timedelta
2 | from calendar import monthrange
3 |
4 |
5 | def time_list(start_time, end_time):
6 | """
7 | 根据起始时间和截至时间生成一个这个时间段的时间列表
8 | :param start_time: 起始时间 YYYY-MM-DD
9 | :param end_time: 终止时间 YYYY-MM-DD
10 | :return: list ['YYYY-MM-DD',.....]
11 | """
12 | dates = []
13 | dt = datetime.strptime(start_time, "%Y-%m-%d")
14 | date = start_time[:]
15 | while date <= end_time:
16 | dates.append(date)
17 | dt += timedelta(days=1)
18 | date = dt.strftime("%Y-%m-%d")
19 | dates.reverse()
20 | return dates
21 |
22 |
23 | def day(time, days, method=1):
24 | """
25 | 返回起始时间之前或之后的日期(默认之前)
26 | :param time: 截止日期 YYYY-MM-DD
27 | :param days: 天数
28 | :param method: 大于0返回起始日期之前的时间,小于0返回起始日期之后的时间
29 | :return: str 'YYYY-MM-DD'
30 | """
31 | dt = datetime.strptime(time, "%Y-%m-%d")
32 | if method > 0:
33 | dt -= timedelta(days=days)
34 | else:
35 | dt += timedelta(days=days)
36 | date = dt.strftime("%Y-%m-%d")
37 | return date
38 |
39 |
40 | def apart(start_time, end_time):
41 | """
42 | 返回两个时间段相隔天数
43 | :param start_time: 起始时间 YYYY-MM-DD
44 | :param end_time: 终止时间 YYYY-MM-DD
45 | :return: 相隔天数 int
46 | """
47 | start_dt = datetime.strptime(start_time, "%Y-%m-%d")
48 | end_dt = datetime.strptime(end_time, "%Y-%m-%d")
49 | return (end_dt - start_dt).days
50 |
51 |
52 | def month(now, month):
53 | """
54 | 获取前几个月或后几个月第一天和最后一天
55 | :param now: 当前时间
56 | :param month: 所隔月数,大于0 返回之前月份,小于0返回之后月份
57 | :return: list [start,end]
58 | """
59 | dt = datetime.strptime(now, "%Y-%m-%d")
60 | start = datetime(dt.year, dt.month-month, 1).strftime("%Y-%m-%d")
61 | end = datetime(dt.year, dt.month-month, monthrange(dt.year, dt.month-month)[1]).strftime("%Y-%m-%d")
62 | return [start, end]
63 |
--------------------------------------------------------------------------------
/IOTPlatform/website/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/admin.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/admin.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/admin.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/admin.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/console.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/console.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/database.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/database.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/database.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/database.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/models.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/models.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/models.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/models.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/urls.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/urls.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/urls.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/urls.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/views.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/views.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/__pycache__/views.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/__pycache__/views.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/IOTPlatform/website/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class WebsiteConfig(AppConfig):
5 | name = 'website'
6 |
--------------------------------------------------------------------------------
/IOTPlatform/website/console.py:
--------------------------------------------------------------------------------
1 | import requests,json
2 | from requests.auth import HTTPBasicAuth
3 |
4 |
5 | def send(data):
6 | """
7 | 调用EMQ http接口发送消息
8 | :param data: 消息内容 dict
9 | :return: dict
10 | """
11 | try:
12 | data = json.dumps(data)
13 | auth = HTTPBasicAuth('admin', 'fml950826cs') # basicAuth认证
14 | res = requests.post(url="http://123.207.87.193:18083/api/v2/mqtt/publish", auth=auth,data=data)
15 | # success: {"code": 0, "result": []}
16 | if res.status_code==200:
17 | return json.loads(res.text)
18 | else:
19 | return {"code": 1, "result": []}
20 | except Exception as e:
21 | return {"code": 1, "result": []}
22 |
23 |
24 |
25 | # 测试
26 | # data = {
27 | # "topic" : "$client/123456",
28 | # "payload": "0",
29 | # "qos": 0,
30 | # "retain" : False,
31 | # "client_id": "mqttjs_b4b9e8e2c3"
32 | # }
33 | # data={'topic': '$client/123456', 'payload': '1', 'qos': 0}
34 | # print(send(data))
--------------------------------------------------------------------------------
/IOTPlatform/website/database.py:
--------------------------------------------------------------------------------
1 | from website import models
2 | from django.db import transaction
3 | from website.utils import create
4 | from utils.time_tools import time_list, day
5 | import time, datetime
6 |
7 |
8 | def login(username, password):
9 | """
10 | 登录验证
11 | :param username: 用户名
12 | :param password: 密码
13 | :return: {'code': 0, 'message': "", 'data': {'token': token}}
14 | """
15 | res = {'code': 0, 'message': "", 'data': {}}
16 | # 检查参数是否正确
17 | if not username or not password:
18 | res['code'] = 1
19 | res['message'] = '参数有误'
20 | return res
21 | try:
22 | # 获取用户对象
23 | userinfo = models.UserInfo.objects.filter(username=username).first()
24 | if userinfo:
25 | if password == userinfo.password:
26 | # 登陆成功生成token保存并返回(以后每次请求都需携带这个token验证)
27 | token = create.create_token(username)
28 | models.UserInfo.objects.filter(username=username).update(token=token)
29 | res['data']['token'] = token
30 | return res
31 | else:
32 | res['code'] = 2
33 | res['message'] = '密码错误'
34 | return res
35 | else:
36 | res['code'] = 3
37 | res['message'] = '当前用户不存在'
38 | return res
39 | except Exception as e:
40 | res['code'] = 1
41 | res['message'] = e.__repr__()
42 | return res
43 |
44 |
45 | def register(username, password, email):
46 | """
47 | 注册用户
48 | :param username: 用户名(唯一的)
49 | :param password: 密码
50 | :param email: 邮箱
51 | :return: {'code': 0, 'message': '', 'data': {'user_id': ""}}
52 | """
53 | res = {'code': 0, 'message': '', 'data': {}}
54 | # 检查参数是否正确
55 | if not username or not password or not email:
56 | res['code'] = 1
57 | res['message'] = '参数错误'
58 | return res
59 | # 检查用户名是否重复
60 | if models.UserInfo.objects.filter(username=username).first():
61 | res['code'] = 2
62 | res['message'] = "用户名已存在"
63 | return res
64 | # 生成user_id , user_id是唯一的防止重复
65 | user_id = hash(username + str(time.time())) % 10 ** 9
66 | while models.UserInfo.objects.filter(user_id=user_id).first():
67 | user_id = hash(username + str(time.time())) % 10 ** 9
68 | try:
69 | with transaction.atomic(): # 出错回滚
70 | models.UserInfo.objects.create(username=username, password=password, user_id=user_id, email=email)
71 | res['message'] = 'Succeed'
72 | res['data']['user_id'] = user_id
73 | except Exception as e:
74 | res['code'] = 3
75 | res['message'] = e.__repr__()
76 | return res
77 |
78 |
79 | def dashboard(username, start_time, end_time):
80 | res = {'code': 0, 'message': "",
81 | 'data': {
82 | 'card': {"dev_num": 0, "str_num": 0, "dp_num": 0, "trg_num": 0},
83 | 'chart': {'title': [], 'point': []}
84 | }
85 | }
86 | try:
87 | if not start_time or not end_time:
88 | end_time = datetime.datetime.now().strftime("%Y-%m-%d")
89 | start_time = day(end_time, 10)
90 | date_list = time_list(start_time, end_time)
91 | date_list.reverse()
92 | res['data']['chart']['title'] = date_list
93 | res['data']['chart']['point'] = [0 for i in date_list]
94 |
95 | user_obj = models.UserInfo.objects.filter(username=username).first()
96 | res['data']['card']['dev_num'] = user_obj.device.count()
97 | # print(device.first().dev_stream.count())
98 | for i in user_obj.device.all():
99 | res['data']['card']['str_num'] += i.dev_stream.count()
100 | for j in i.dev_stream.all():
101 | if j.trigger:
102 | res['data']['card']['trg_num'] += 1
103 | res['data']['card']['dp_num'] += j.data.count()
104 | for t in range(len(date_list)):
105 | res['data']['chart']['point'][t] += j.data.filter(date__startswith=date_list[t]).count()
106 | except Exception as e:
107 | res['code'] = 1
108 | res['message'] = e.__repr__()
109 | return res
110 |
111 |
112 | def charts(username, start_time, end_time):
113 | res = {'code': 0, 'message': "", 'data': {}}
114 | try:
115 |
116 | if not start_time or not end_time:
117 | end_time = datetime.datetime.now().strftime("%Y-%m-%d")
118 | start_time = day(end_time, 10)
119 | date_list = time_list(start_time, end_time)
120 | date_list.reverse()
121 |
122 | user_obj = models.UserInfo.objects.filter(username=username).first()
123 | for i in user_obj.device.all():
124 | res['data'][i.device_name] = {}
125 | for j in i.dev_stream.all():
126 |
127 | res['data'][i.device_name][j.name] = [[], []]
128 | for t in j.data.all():
129 | res['data'][i.device_name][j.name][0].append(str(t.date)[:19])
130 | res['data'][i.device_name][j.name][1].append(t.data)
131 |
132 | except Exception as e:
133 | res['code'] = 1
134 | res['message'] = e.__repr__()
135 | return res
136 |
137 |
138 | def get_device(username):
139 | res = {'code': 0, 'message': '', 'data': []}
140 | try:
141 | user_obj = models.UserInfo.objects.filter(username=username).first() # 获取用户对象
142 | if not user_obj:
143 | res['code'] = 1
144 | res['message'] = '无法找到用户信息'
145 | return res
146 | for i in user_obj.device.all(): # 遍历其下多有的设备信息
147 | buff = {'id': i.device_id, 'name': i.device_name, 'status': i.dev_status, 'create_time': str(i.date)[:16],
148 | 'introduce': i.dev_introduce, 'APIkey': i.apiKey, 'tag': i.tag, 'stream_num': i.dev_stream.count()}
149 | res['data'].append(buff)
150 |
151 | except Exception as e:
152 | res['code'] = 1
153 | res['message'] = e.__repr__()
154 | return res
155 |
156 |
157 | def update_device(username, id, name, introduce, tag):
158 | res = {'code': 0, 'message': "", 'data': {}}
159 | try:
160 | # 检查一下此用户下是否存在这个ID 的设备,防止其他人篡改
161 | dev_obj = models.UserInfo.objects.filter(username=username).device.filter(device_id=id)
162 | if dev_obj:
163 | dev_obj.update(device_name=name, tag=tag, dev_introduce=introduce)
164 | else:
165 | res['code'] = 1
166 | res['message'] = '抱歉你的账户下没有这个ID的设备,无法修改'
167 | except Exception as e:
168 | res['code'] = 1
169 | res['message'] = e.__repr__()
170 | return res
171 |
172 |
173 | def add_device(username, name, introduce, tag):
174 | res = {'code': 0, 'message': "", 'data': {}}
175 | try:
176 | # 生成唯一的设备ID
177 | device_id = hash(username + str(time.time())) % 10 ** 9
178 | while models.Device.objects.filter(device_id=device_id).first():
179 | device_id = hash(username + str(time.time())) % 10 ** 9
180 | # 生成设备鉴权信息
181 | apiKey = create.create_token(str(device_id) + username)
182 | # 创建设备对象
183 | dev_obj = models.Device.objects.create(device_id=device_id, device_name=name, dev_introduce=introduce, tag=tag,
184 | apiKey=apiKey)
185 | # 将创建的设备和用户关联起来
186 | models.UserInfo.objects.filter(username=username).first().device.add(dev_obj)
187 | except Exception as e:
188 | res['code'] = 1
189 | print(e.__repr__())
190 | res['message'] = e.__repr__()
191 | return res
192 |
193 |
194 | def del_device(username, id, apiKey):
195 | res = {'code': 0, 'message': "", 'data': {}}
196 | try:
197 | # 检查一下此用户下是否存在这个ID 的设备,防止其他人篡改
198 | dev_obj = models.UserInfo.objects.filter(username=username).first().device.filter(device_id=id)
199 | if dev_obj:
200 | # 这里再次判断设备鉴权信息是否正确
201 | obj = dev_obj.filter(apiKey=apiKey)
202 | if obj:
203 | for i in obj.first().dev_stream.all():
204 | for d in i.data.all():
205 | d.delete() # 删除数据点
206 | i.delete() # 删除数据流
207 | obj.delete() # 这里只是删除了关联,其下的数据流并没有删除, 所以还需要上面的两步删除干净
208 |
209 | else:
210 | res['code'] = 1
211 | res['message'] = '设备鉴权信息错误,无法删除'
212 | return res
213 | else:
214 | res['code'] = 1
215 | res['message'] = '抱歉你的账户下没有这个ID的设备,无法删除'
216 | return res
217 | except Exception as e:
218 | res['code'] = 1
219 | res['message'] = e.__repr__()
220 | return res
221 |
222 |
223 | def get_stream(username):
224 | res = {'code': 0, 'message': "", 'data': []}
225 | trigger_type = ['无','<','<=','==','>','>=','change','inout']
226 | try:
227 | user_obj = models.UserInfo.objects.filter(username=username).first()
228 | if not user_obj:
229 | res['code'] = 1
230 | res['message'] = '无法找到用户信息'
231 | return res
232 | for i in user_obj.device.all(): # 遍历其下多有的设备信息
233 | for j in i.dev_stream.all(): # 再遍历每个设备下的数据流
234 | buff = {'name': j.name, 'dev_id': i.device_id, 'dev_name': i.device_name, 'unit': j.unit,
235 | 'unit_symbol': j.unit_symbol, 'trigger': '是' if j.trigger else '否', 'qos': j.qos, 'max': j.max,
236 | 'min': j.min, 'trigger_type':trigger_type[j.min]}
237 | res['data'].append(buff)
238 | except Exception as e:
239 | res['code'] = 1
240 | res['message'] = e.__repr__()
241 | return res
242 |
243 |
244 | def update_stream(username, dev_id, name, unit, unit_symbol, max, min, qos):
245 | res = {'code': 0, 'message': "", 'data': {}}
246 | try:
247 | dev_obj = models.UserInfo.objects.filter(username=username).first().device.filter(device_id=dev_id).first()
248 | if dev_obj:
249 | dev_obj.dev_stream.filter(name=name).update(unit=unit, unit_symbol=unit_symbol, max=max, min=min, qos=qos)
250 | else:
251 | res['code'] = 1
252 | res['message'] = '抱歉你的账户下没有这个ID的设备,无法修改'
253 | except Exception as e:
254 | res['code'] = 1
255 | res['message'] = e.__repr__()
256 | return res
257 |
258 |
259 | def add_stream(username, dev_id, name, unit, unit_symbol, max, min, qos):
260 | res = {'code': 0, 'message': "", 'data': {}}
261 | try:
262 | dev_obj = models.UserInfo.objects.filter(username=username).first().device.filter(device_id=dev_id).first()
263 | if dev_obj:
264 | stream_obj = models.DataStream.objects.create(name=name,unit=unit,unit_symbol=unit_symbol,max=max,min=min,qos=qos)
265 | dev_obj.dev_stream.add(stream_obj)
266 | else:
267 | res['code'] = 1
268 | res['message'] = '抱歉你的账户下没有这个ID的设备,无法新建此数据流'
269 | except Exception as e:
270 | res['code'] = 1
271 | res['message'] = e.__repr__()
272 | return res
273 |
274 |
275 | def del_stream(username, dev_id, name):
276 | res = {'code': 0, 'message': "", 'data': {}}
277 | try:
278 | dev_obj = models.UserInfo.objects.filter(username=username).first().device.filter(device_id=dev_id).first()
279 | if dev_obj:
280 | str_obj = dev_obj.dev_stream.filter(name=name)
281 | for d in str_obj.first().data.all():
282 | d.delete() # 删除数据点
283 | str_obj.delete() # 删除数据流
284 |
285 | else:
286 | res['code'] = 1
287 | res['message'] = '抱歉你的账户下没有这个ID的设备,无法删除此数据流'
288 | except Exception as e:
289 | res['code'] = 1
290 | res['message'] = e.__repr__()
291 | return res
292 |
293 |
294 | def get_trigger(username):
295 | res = {'code': 0, 'message': "", 'data': []}
296 | try:
297 | user_obj = models.UserInfo.objects.filter(username=username).first()
298 | if not user_obj:
299 | res['code'] = 1
300 | res['message'] = '无法找到用户信息'
301 | return res
302 | for i in user_obj.device.all(): # 遍历其下多有的设备信息
303 | for j in i.dev_stream.all(): # 再遍历每个设备下的数据流
304 | if j.trigger:
305 | buff = {'name': j.name, 'dev_id': i.device_id, 'dev_name': i.device_name, 'unit': j.unit,
306 | 'unit_symbol': j.unit_symbol, 'trigger': '是' if j.trigger else '否', 'qos': j.qos, 'max': j.max,
307 | 'min': j.min}
308 | res['data'].append(buff)
309 | except Exception as e:
310 | res['code'] = 1
311 | res['message'] = e.__repr__()
312 | return res
313 |
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1.2 on 2018-11-06 19:36
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | initial = True
9 |
10 | dependencies = [
11 | ]
12 |
13 | operations = [
14 | migrations.CreateModel(
15 | name='Data',
16 | fields=[
17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18 | ('data', models.CharField(max_length=10)),
19 | ('date', models.DateTimeField(auto_now_add=True)),
20 | ],
21 | ),
22 | migrations.CreateModel(
23 | name='DataStream',
24 | fields=[
25 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
26 | ('name', models.CharField(max_length=32)),
27 | ('min', models.IntegerField(null=True)),
28 | ('max', models.IntegerField(null=True)),
29 | ('qos', models.IntegerField(default=0)),
30 | ('unit', models.CharField(max_length=32)),
31 | ('unit_symbol', models.CharField(max_length=32)),
32 | ('data', models.ManyToManyField(to='website.Data')),
33 | ],
34 | ),
35 | migrations.CreateModel(
36 | name='Device',
37 | fields=[
38 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
39 | ('device_id', models.IntegerField(unique=True)),
40 | ('device_key', models.CharField(max_length=32, null=True)),
41 | ('device_name', models.CharField(max_length=32)),
42 | ('dev_status', models.BooleanField(default=0)),
43 | ('dev_stream', models.ManyToManyField(to='website.DataStream')),
44 | ],
45 | ),
46 | migrations.CreateModel(
47 | name='UserInfo',
48 | fields=[
49 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
50 | ('username', models.CharField(db_index=True, max_length=32, unique=True)),
51 | ('user_id', models.IntegerField(db_index=True, unique=True)),
52 | ('password', models.CharField(max_length=64)),
53 | ('weixin_id', models.CharField(db_index=True, max_length=64, null=True)),
54 | ('sex', models.CharField(max_length=16, null=True)),
55 | ('birthday', models.CharField(max_length=64, null=True)),
56 | ('tel', models.CharField(max_length=64, null=True)),
57 | ('email', models.CharField(max_length=64, null=True)),
58 | ('address', models.CharField(max_length=64, null=True)),
59 | ('introduction', models.CharField(max_length=255, null=True)),
60 | ('token', models.CharField(max_length=255, null=True)),
61 | ('device', models.ManyToManyField(to='website.Device')),
62 | ],
63 | ),
64 | ]
65 |
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/0002_auto_20181110_0221.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1.2 on 2018-11-10 02:21
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('website', '0001_initial'),
10 | ]
11 |
12 | operations = [
13 |
14 | migrations.AlterField(
15 | model_name='datastream',
16 | name='unit',
17 | field=models.CharField(max_length=32, null=True),
18 | ),
19 | migrations.AlterField(
20 | model_name='datastream',
21 | name='unit_symbol',
22 | field=models.CharField(max_length=32, null=True),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/0003_auto_20181114_0143.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1.2 on 2018-11-14 01:43
2 |
3 | from django.db import migrations, models
4 | import django.utils.timezone
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('website', '0002_auto_20181110_0221'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='device',
16 | name='apiKey',
17 | field=models.CharField(max_length=32, null=True),
18 | ),
19 | migrations.AddField(
20 | model_name='device',
21 | name='date',
22 | field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
23 | preserve_default=False,
24 | ),
25 | migrations.AddField(
26 | model_name='device',
27 | name='dev_introduce',
28 | field=models.TextField(null=True),
29 | ),
30 | migrations.AddField(
31 | model_name='device',
32 | name='tag',
33 | field=models.CharField(max_length=32, null=True),
34 | ),
35 | ]
36 |
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/0004_auto_20181114_0144.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1.2 on 2018-11-14 01:44
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('website', '0003_auto_20181114_0143'),
10 | ]
11 |
12 | operations = [
13 |
14 | ]
15 |
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/0005_auto_20181114_0148.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1.2 on 2018-11-14 01:48
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('website', '0004_auto_20181114_0144'),
10 | ]
11 |
12 | operations = [
13 |
14 | ]
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/0006_auto_20181118_1522.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1.2 on 2018-11-18 15:22
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('website', '0005_auto_20181114_0148'),
10 | ]
11 |
12 | operations = [
13 |
14 | migrations.AlterField(
15 | model_name='datastream',
16 | name='max',
17 | field=models.IntegerField(default=0, null=True),
18 | ),
19 | migrations.AlterField(
20 | model_name='datastream',
21 | name='min',
22 | field=models.IntegerField(default=0, null=True),
23 | ),
24 | ]
25 |
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/0007_auto_20181118_1618.py:
--------------------------------------------------------------------------------
1 | # Generated by Django 2.1.2 on 2018-11-18 16:18
2 |
3 | from django.db import migrations, models
4 |
5 |
6 | class Migration(migrations.Migration):
7 |
8 | dependencies = [
9 | ('website', '0006_auto_20181118_1522'),
10 | ]
11 |
12 | operations = [
13 | migrations.AlterField(
14 | model_name='datastream',
15 | name='qos',
16 | field=models.IntegerField(default=0, null=True),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__init__.py:
--------------------------------------------------------------------------------
1 | 2
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/0001_initial.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/0001_initial.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/0001_initial.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/0001_initial.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/0002_auto_20181110_0221.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/0002_auto_20181110_0221.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/0003_auto_20181114_0143.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/0003_auto_20181114_0143.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/0004_auto_20181114_0144.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/0004_auto_20181114_0144.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/0005_auto_20181114_0148.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/0005_auto_20181114_0148.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/0006_auto_20181118_1522.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/0006_auto_20181118_1522.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/0007_auto_20181118_1618.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/0007_auto_20181118_1618.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/migrations/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/migrations/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class Data(models.Model):
5 | data = models.CharField(max_length=10) # 限制在两位小数
6 | date = models.DateTimeField(auto_now_add=True) # 上传时间,自动保存时间
7 |
8 |
9 | class DataStream(models.Model):
10 | name = models.CharField(max_length=32, null=False) # 数据流名称
11 | min = models.IntegerField(null=True, default=0) # 判断类型 0: None 1: < 2:<= 3:== 4:> 5:>= 6:change 7:inout
12 | max = models.IntegerField(null=True, default=0) # 阈值数值
13 | qos = models.IntegerField(null=True, default=0) # 服务质量
14 | unit = models.CharField(max_length=32, null=True) # 单位名称
15 | unit_symbol = models.CharField(max_length=32, null=True) # 单位符号
16 | trigger = models.BooleanField(default=0) # 触发器 0:不需要 1:微信 2:邮箱 这两个都是使用userinfo表中绑定的信息 其他http请求(写入的时候需要需要验证URL格式)
17 | data = models.ManyToManyField(Data)
18 |
19 |
20 | class Device(models.Model):
21 | device_id = models.IntegerField(unique=True, null=False) # 设备号
22 | device_key = models.CharField(max_length=32, null=True) # 设备token
23 | device_name = models.CharField(max_length=32) # 设备名
24 | dev_status = models.BooleanField(default=0) # 在线状态
25 | dev_introduce = models.TextField(null=True) # 设备简介
26 | date = models.DateTimeField(auto_now_add=True) # 创建时间,自动保存时间
27 | tag = models.CharField(max_length=32,null=True) # 设备标签
28 | apiKey = models.CharField(max_length=32, null=True) # apiKey
29 | dev_stream = models.ManyToManyField(DataStream) # 传感器数据流
30 |
31 |
32 | class UserInfo(models.Model):
33 | username = models.CharField(max_length=32, null=False, unique=True, db_index=True) # 用户名
34 | user_id = models.IntegerField(unique=True, null=False, db_index=True) # 用户ID
35 | password = models.CharField(max_length=64, null=False) # 密码
36 | weixin_id = models.CharField(max_length=64, null=True, db_index=True) # 微信号
37 | # 个人信息
38 | sex = models.CharField(max_length=16, null=True) # 性别
39 | birthday = models.CharField(max_length=64, null=True) # 生日
40 | tel = models.CharField(max_length=64, null=True) # 联系方式
41 | email = models.CharField(max_length=64, null=True) # 邮箱
42 | address = models.CharField(max_length=64, null=True) # 地址
43 | introduction = models.CharField(max_length=255, null=True) # 个人简介
44 | token = models.CharField(max_length=255, null=True)
45 | # 绑定设备
46 | device = models.ManyToManyField(Device)
47 |
--------------------------------------------------------------------------------
/IOTPlatform/website/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/IOTPlatform/website/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from website import views
3 | urlpatterns = [
4 | url(r'^login$', views.Login.as_view()), # 登陆验证
5 | url(r'^register$', views.Register.as_view()), # 登陆验证
6 | url(r'^dashboard$', views.Dashboard.as_view()), # 登陆验证
7 | url(r'^charts$', views.Chart.as_view()), # 登陆验证
8 | url(r'^devices', views.Device.as_view()), # 登陆验证
9 | url(r'^streams', views.Stream.as_view()), # 登陆验证
10 | url(r'^console', views.Console.as_view()), # 登陆验证
11 | url(r'^triggers', views.Trigger.as_view()), # 登陆验证
12 |
13 | ]
14 |
--------------------------------------------------------------------------------
/IOTPlatform/website/utils/__pycache__/auth.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/utils/__pycache__/auth.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/utils/__pycache__/create.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/utils/__pycache__/create.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/utils/__pycache__/create.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/website/utils/__pycache__/create.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/website/utils/auth.py:
--------------------------------------------------------------------------------
1 | from rest_framework.authentication import BaseAuthentication
2 | from rest_framework import exceptions
3 | from website import models
4 |
5 |
6 | class Authtication(BaseAuthentication):
7 | def authenticate(self, request): # 如果执行到最后一个还是没有给user赋值,则会返回一个匿名用户
8 | token = request._request.META.get('HTTP_AUTHORIZATION')
9 | obj = models.UserInfo.objects.filter(token=token).first()
10 | if not token or not obj:
11 | raise exceptions.AuthenticationFailed({'code': 1, 'message': '没有登录!', 'data': {}})
12 | return obj.username, None
13 |
14 |
--------------------------------------------------------------------------------
/IOTPlatform/website/utils/create.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import time
3 |
4 | def create_dev_id(username):
5 | """
6 | 生成dev_id
7 | :param username: 用户名
8 | :return: dev_id
9 | """
10 | ctime = str(time.time())
11 | m = hashlib.md5(bytes(username, encoding='utf-8'))
12 | m.update(bytes(ctime, encoding='utf-8'))
13 | return m.hexdigest()
14 |
15 | def create_token(username):
16 | """
17 | 生成token,用户登录成功后返回token,下次访问需要携带token验证用户信息
18 | :param username: 用户名
19 | :return: token
20 | """
21 | ctime = str(time.time())
22 | m = hashlib.md5(bytes(username, encoding='utf-8'))
23 | m.update(bytes(ctime, encoding='utf-8'))
24 | return m.hexdigest()
--------------------------------------------------------------------------------
/IOTPlatform/website/views.py:
--------------------------------------------------------------------------------
1 | from django.http import JsonResponse
2 | # from django.shortcuts import render, HttpResponse
3 | from rest_framework.views import APIView
4 | from rest_framework.parsers import JSONParser, FormParser
5 | from website import database
6 | from website.console import send
7 |
8 | error_msg = {'code': 100, 'message': 'request parameter error'}
9 |
10 |
11 | class Login(APIView):
12 | parser_classes = [JSONParser, FormParser]
13 | authentication_classes = []
14 |
15 | def post(self, request):
16 | username = request.data.get('username', None)
17 | password = request.data.get('password', None)
18 | res = database.login(username, password)
19 | return JsonResponse(res)
20 |
21 |
22 | class Register(APIView):
23 | authentication_classes = []
24 |
25 | def post(self, request):
26 | username = request.POST.get('username', None)
27 | password = request.POST.get('password', None)
28 | email = request.POST.get('email', None)
29 | res = database.register(username, password, email)
30 | return JsonResponse(res)
31 |
32 |
33 | class Dashboard(APIView):
34 | def get(self, request):
35 | res = database.dashboard(request.user, None, None)
36 | return JsonResponse(res)
37 |
38 |
39 | class Chart(APIView):
40 | def get(self, request):
41 | res = database.charts(request.user, None, None)
42 | return JsonResponse(res)
43 |
44 |
45 | class Device(APIView):
46 | parser_classes = [JSONParser, FormParser]
47 |
48 | def get(self, request):
49 | """获取设备"""
50 | res = database.get_device(request.user)
51 | return JsonResponse(res)
52 |
53 | def post(self, request):
54 | """新建设备"""
55 | name = request.data.get('name', None)
56 | introduce = request.data.get('introduce', None)
57 | tag = request.data.get('tag', None)
58 | # print(name,introduce,tag)
59 | res = database.add_device(request.user, name, introduce, tag)
60 |
61 | return JsonResponse(res)
62 |
63 | def put(self, request):
64 | """修改设备信息"""
65 | id = request.data.get('id', None)
66 | name = request.data.get('name', None)
67 | introduce = request.data.get('introduce', None)
68 | tag = request.data.get('tag', None)
69 | res = database.update_device(request.user, id, name, introduce, tag)
70 | return JsonResponse(res)
71 |
72 | def delete(self, request):
73 | id = request.data.get('id', None)
74 | apiKey = request.data.get('apiKey', None)
75 | res = database.del_device(request.user, id, apiKey)
76 | return JsonResponse(res)
77 |
78 |
79 | class Stream(APIView):
80 | parser_classes = [JSONParser, FormParser]
81 |
82 | def get(self, request):
83 | """获取设备"""
84 | res = database.get_stream(request.user)
85 | return JsonResponse(res)
86 |
87 | def post(self, request):
88 | """
89 | 新建数据流
90 | :param request: name, dev_id, qos, min 都不能为空
91 | :return:
92 | """
93 | name = request.data.get('name', None)
94 | unit = request.data.get('unit', None)
95 | unit_symbol = request.data.get('unit_symbol', None)
96 | qos = request.data.get('qos', 0)
97 | dev_id = request.data.get('dev_id', None)
98 | max = request.data.get('max', 0)
99 | min = request.data.get('min', 0)
100 | if not dev_id or not name:
101 | return JsonResponse(error_msg)
102 | if qos not in [0, 1, 2, '0', '1', '2'] or \
103 | min not in [0, 1, 2, 3, 4, 5, 6, 7, '0', '1', '2', '3', '4', '5', '6','7']:
104 | return JsonResponse(error_msg)
105 | res = database.add_stream(request.user, dev_id, name, unit, unit_symbol, max, min, qos)
106 | return JsonResponse(res)
107 |
108 | def put(self, request):
109 | """修改数据流信息"""
110 | device_id = request.data.get('dev_id', None)
111 | name = request.data.get('name', None)
112 | unit = request.data.get('unit', None)
113 | unit_symbol = request.data.get('unit_symbol', None)
114 | max = request.data.get('max', None)
115 | min = request.data.get('min', None)
116 | qos = request.data.get('qos', None)
117 | if not device_id or not name:
118 | return JsonResponse(error_msg)
119 | if qos not in [0, 1, 2, '0', '1', '2'] or \
120 | min not in [0, 1, 2, 3, 4, 5, 6, 7, '0', '1', '2', '3', '4', '5', '6','7']:
121 | return JsonResponse(error_msg)
122 | res = database.update_stream(request.user, device_id, name, unit, unit_symbol, max, min, qos)
123 | return JsonResponse(res)
124 |
125 | def delete(self, request):
126 | dev_id = request.data.get('dev_id', None)
127 | name = request.data.get('name', None)
128 | res = database.del_stream(request.user, dev_id, name)
129 | return JsonResponse(res)
130 |
131 |
132 | class Console(APIView):
133 | parser_classes = [JSONParser, FormParser]
134 |
135 | def post(self, request):
136 | topic = request.data.get('topic')
137 | # topic 为必要参数必须要有
138 | if not topic:
139 | return JsonResponse(error_msg)
140 | # 此项参数允许为空
141 | payload = request.data.get('payload', None)
142 | qos = request.data.get('qos')
143 | # qos 参数只能为列表中的几个,否则无效
144 | if qos not in ['0', '1', '2', 1, 2, 0]:
145 | return JsonResponse(error_msg)
146 | data = {'topic': topic, 'payload': payload, 'qos': int(qos)}
147 | res = send(data)
148 | return JsonResponse(res)
149 |
150 |
151 | class Trigger(APIView):
152 | parser_classes = [JSONParser, FormParser]
153 |
154 | def get(self, request):
155 | res = database.get_trigger(request.user)
156 | print(res)
157 | return JsonResponse(res)
158 |
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__init__.py
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/admin.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/admin.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/admin.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/admin.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/models.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/models.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/models.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/models.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/urls.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/urls.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/urls.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/urls.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/views.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/views.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/__pycache__/views.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/__pycache__/views.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/IOTPlatform/weixin/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class WeixinConfig(AppConfig):
5 | name = 'weixin'
6 |
--------------------------------------------------------------------------------
/IOTPlatform/weixin/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/migrations/__init__.py
--------------------------------------------------------------------------------
/IOTPlatform/weixin/migrations/__pycache__/__init__.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/migrations/__pycache__/__init__.cpython-36.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/migrations/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/IOTPlatform/weixin/migrations/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/IOTPlatform/weixin/models.py:
--------------------------------------------------------------------------------
1 | # This is an auto-generated Django model module.
2 | # You'll have to do the following manually to clean this up:
3 | # * Rearrange models' order
4 | # * Make sure each model has one field with primary_key=True
5 | # * Make sure each ForeignKey has `on_delete` set to the desired behavior.
6 | # * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
7 | # Feel free to rename the models, but don't rename db_table values or field names.
8 | from django.db import models
9 |
10 |
--------------------------------------------------------------------------------
/IOTPlatform/weixin/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/IOTPlatform/weixin/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from weixin import views
3 | urlpatterns = [
4 | url(r'^login$', views.Login.as_view()), # 登陆验证
5 | ]
--------------------------------------------------------------------------------
/IOTPlatform/weixin/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render, HttpResponse
2 | from rest_framework.views import APIView
3 |
4 |
5 | # Create your views here.
6 |
7 | class Login(APIView):
8 | def get(self, requset):
9 | """
10 |
11 | :param requset:
12 | :return:
13 | """
14 | return HttpResponse('111k')
15 |
--------------------------------------------------------------------------------
/MQTT/.idea/MQTT.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MQTT/.idea/dictionaries/fml.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | pymysql
5 |
6 |
7 |
--------------------------------------------------------------------------------
/MQTT/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/MQTT/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MQTT/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/MQTT/__pycache__/database.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/MQTT/__pycache__/database.cpython-37.pyc
--------------------------------------------------------------------------------
/MQTT/__pycache__/models.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fanmlei/IOTPlatform/b137568d27d0a41fa25e66f51e4ffb83d74f36f6/MQTT/__pycache__/models.cpython-37.pyc
--------------------------------------------------------------------------------
/MQTT/database.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import create_engine
2 | from sqlalchemy.orm import sessionmaker
3 | from models import * # 导入生成的model
4 |
5 | from datetime import datetime
6 |
7 |
8 | class DB(object):
9 | def __init__(self, name, password, host, port, dbname):
10 | # 初始化的过程中直接连接数据库
11 | engine = create_engine('mysql+pymysql://' + name + ':' + password + '@' + host + ':' + port + '/' + dbname)
12 | self.Session = sessionmaker(bind=engine)
13 | self.session = self.Session()
14 |
15 | def reconnect(self):
16 | """"断开重连"""
17 | self.session = self.Session()
18 |
19 | def update_dev_stus(self, device_id, status):
20 | """
21 | 更改设备状态
22 | :param device_id: 设备ID
23 | :param status: 状态
24 | :return: True
25 | """
26 | try:
27 | self.session.query(Device).filter(Device.device_id == device_id).update(
28 | {Device.dev_status: status})
29 | self.session.flush()
30 | self.session.commit()
31 | return True
32 | except Exception as e:
33 | self.reconnect()
34 |
35 | def write_data(self, device_id, dev_stream, data):
36 | """
37 | 写入数据
38 | :param device_id: 设备ID
39 | :param dev_stream: 数据流名称
40 | :param data: 数据
41 | :return: True
42 | """
43 | try:
44 | new_data = Data(data=data,date=datetime.now())
45 | device_obj = self.session.query(Device).filter(Device.device_id==device_id).first()
46 | if device_obj:
47 | for i in device_obj.stream:
48 | if i.name == dev_stream:
49 | i.data.append(new_data)
50 | self.session.flush()
51 | self.session.commit()
52 | return True
53 | except Exception as e:
54 | self.reconnect()
55 |
56 |
57 | def get_subscribe(self):
58 | """
59 | 获取需要订阅的主题名
60 | :return: list
61 | """
62 | try:
63 | subscribe_list = []
64 | devive_objs = self.session.query(Device).all()
65 | for i in devive_objs:
66 | for j in i.stream:
67 | subscribe_list.append([str(i.device_id) + '/' + j.name, j.qos])
68 | return subscribe_list
69 | except Exception as e:
70 | self.reconnect()
71 |
72 |
73 |
74 |
75 | # db = DB('root', 'fml950826cs','123.207.87.193','3306','IOTPlatform')
76 |
77 | # db.update_dev_stus(123456,1)
78 | # db.write_data('123456', 'temp1', '213213123')
79 | # db.update_dev_stus('123456',1)
80 |
81 | # print(db.get_subscribe())
82 |
--------------------------------------------------------------------------------
/MQTT/models.py:
--------------------------------------------------------------------------------
1 | # sqlacodegen mysql+pymysql://root:fml950826cs@123.207.87.193:3306/IOTPlatform > models.py
2 | #
3 |
4 | # coding: utf-8
5 | from sqlalchemy import Column, ForeignKey, Index, String,Table,Integer
6 | from sqlalchemy.dialects.mysql import DATETIME, INTEGER, LONGTEXT, SMALLINT, TINYINT, VARCHAR
7 | from sqlalchemy.orm import relationship
8 | from sqlalchemy.ext.declarative import declarative_base
9 |
10 | Base = declarative_base()
11 | metadata = Base.metadata
12 |
13 | stream_data = Table(
14 | 'website_datastream_data', Base.metadata,
15 | Column('datastream_id', Integer, ForeignKey('website_datastream.id')),
16 | Column('data_id', Integer, ForeignKey('website_data.id'))
17 | )
18 |
19 | device_stream = Table(
20 | 'website_device_dev_stream', Base.metadata,
21 | Column('device_id', Integer, ForeignKey('website_device.id')),
22 | Column('datastream_id', Integer, ForeignKey('website_datastream.id'))
23 | )
24 |
25 | class Data(Base):
26 | __tablename__ = 'website_data'
27 | id = Column(INTEGER(11), primary_key=True)
28 | data = Column(String(10), nullable=False)
29 | date = Column(DATETIME(fsp=6), nullable=False)
30 |
31 | class Stream(Base):
32 | __tablename__ = 'website_datastream'
33 |
34 | id = Column(INTEGER(11), primary_key=True)
35 | name = Column(VARCHAR(32), nullable=False)
36 | min = Column(INTEGER(11))
37 | max = Column(INTEGER(11))
38 | qos = Column(INTEGER(11), nullable=False)
39 | unit = Column(VARCHAR(32))
40 | unit_symbol = Column(VARCHAR(32))
41 | trigger = Column(TINYINT(1), nullable=False)
42 | data = relationship('Data', secondary=stream_data)
43 |
44 | class Device(Base):
45 | __tablename__ = 'website_device'
46 |
47 | id = Column(INTEGER(11), primary_key=True)
48 | device_id = Column(INTEGER(11), nullable=False, unique=True)
49 | device_key = Column(String(32))
50 | device_name = Column(VARCHAR(32), nullable=False)
51 | dev_status = Column(TINYINT(1), nullable=False)
52 | apiKey = Column(String(32))
53 | date = Column(DATETIME(fsp=6), nullable=False)
54 | dev_introduce = Column(LONGTEXT)
55 | tag = Column(VARCHAR(32))
56 | stream = relationship('Stream', secondary=device_stream)
57 |
58 | # class WebsiteData(Base):
59 | # __tablename__ = 'website_data'
60 | #
61 | # id = Column(INTEGER(11), primary_key=True)
62 | # data = Column(String(10), nullable=False)
63 | # date = Column(DATETIME(fsp=6), nullable=False)
64 |
65 |
66 | # class WebsiteDatastream(Base):
67 | # __tablename__ = 'website_datastream'
68 | #
69 | # id = Column(INTEGER(11), primary_key=True)
70 | # name = Column(VARCHAR(32), nullable=False)
71 | # min = Column(INTEGER(11))
72 | # max = Column(INTEGER(11))
73 | # qos = Column(INTEGER(11), nullable=False)
74 | # unit = Column(VARCHAR(32))
75 | # unit_symbol = Column(VARCHAR(32))
76 | # trigger = Column(TINYINT(1), nullable=False)
77 |
78 |
79 | # class WebsiteDevice(Base):
80 | # __tablename__ = 'website_device'
81 | #
82 | # id = Column(INTEGER(11), primary_key=True)
83 | # device_id = Column(INTEGER(11), nullable=False, unique=True)
84 | # device_key = Column(String(32))
85 | # device_name = Column(VARCHAR(32), nullable=False)
86 | # dev_status = Column(TINYINT(1), nullable=False)
87 | # apiKey = Column(String(32))
88 | # date = Column(DATETIME(fsp=6), nullable=False)
89 | # dev_introduce = Column(LONGTEXT)
90 | # tag = Column(VARCHAR(32))
91 |
92 |
93 | # class WebsiteUserinfo(Base):
94 | # __tablename__ = 'website_userinfo'
95 | #
96 | # id = Column(INTEGER(11), primary_key=True)
97 | # username = Column(VARCHAR(32), nullable=False, unique=True)
98 | # user_id = Column(INTEGER(11), nullable=False, unique=True)
99 | # password = Column(VARCHAR(64), nullable=False)
100 | # weixin_id = Column(VARCHAR(64), index=True)
101 | # sex = Column(VARCHAR(16))
102 | # birthday = Column(VARCHAR(64))
103 | # tel = Column(VARCHAR(64))
104 | # email = Column(VARCHAR(64))
105 | # address = Column(VARCHAR(64))
106 | # introduction = Column(VARCHAR(255))
107 | # token = Column(VARCHAR(255))
108 |
109 |
110 | # class WebsiteDatastreamData(Base):
111 | # __tablename__ = 'website_datastream_data'
112 | # __table_args__ = (
113 | # Index('website_datastream_data_datastream_id_data_id_3b3216eb_uniq', 'datastream_id', 'data_id', unique=True),
114 | # )
115 | #
116 | # id = Column(INTEGER(11), primary_key=True)
117 | # datastream_id = Column(ForeignKey('website_datastream.id'), nullable=False)
118 | # data_id = Column(ForeignKey('website_data.id'), nullable=False, index=True)
119 | #
120 | # data = relationship('WebsiteData')
121 | # datastream = relationship('WebsiteDatastream')
122 |
123 |
124 | # class WebsiteDeviceDevStream(Base):
125 | # __tablename__ = 'website_device_dev_stream'
126 | # __table_args__ = (
127 | # Index('website_device_dev_stream_device_id_datastream_id_6d32e5c0_uniq', 'device_id', 'datastream_id', unique=True),
128 | # )
129 | #
130 | # id = Column(INTEGER(11), primary_key=True)
131 | # device_id = Column(ForeignKey('website_device.id'), nullable=False)
132 | # datastream_id = Column(ForeignKey('website_datastream.id'), nullable=False, index=True)
133 | #
134 | # datastream = relationship('WebsiteDatastream')
135 | # device = relationship('WebsiteDevice')
136 |
137 |
138 | # class WebsiteUserinfoDevice(Base):
139 | # __tablename__ = 'website_userinfo_device'
140 | # __table_args__ = (
141 | # Index('website_userinfo_device_userinfo_id_device_id_e34001e8_uniq', 'userinfo_id', 'device_id', unique=True),
142 | # )
143 | #
144 | # id = Column(INTEGER(11), primary_key=True)
145 | # userinfo_id = Column(ForeignKey('website_userinfo.id'), nullable=False)
146 | # device_id = Column(ForeignKey('website_device.id'), nullable=False, index=True)
147 | #
148 | # device = relationship('WebsiteDevice')
149 | # userinfo = relationship('WebsiteUserinfo')
150 |
--------------------------------------------------------------------------------
/MQTT/mqtt_client.py:
--------------------------------------------------------------------------------
1 | import paho.mqtt.client as client
2 | from database import DB
3 | import threading
4 |
5 |
6 | class MqClient(object):
7 | def __init__(self, client_id, username, password):
8 | self.client = client.Client(client_id=client_id,
9 | clean_session=False) # 初始化,clean_session为false的时候EMQ会保存订阅状态,可以不再次订阅
10 | self.client.username_pw_set(username, password) # 设置连接用户名
11 | self.client.on_connect = self.on_connect
12 | self.client.on_message = self.on_message
13 | self._client_status = False # 连接状态
14 | self._cloop = None
15 | self._connect()
16 | self.db = DB('root', 'fml950826cs', '123.207.87.193', '3306', 'IOTPlatform')
17 |
18 | def _connect(self, host="123.207.87.193", port=1883, keepalive=60):
19 | """连接服务器"""
20 | self.client.connect_async(host, port, keepalive)
21 | # self.client.loop_forever()
22 | # 开启线程执行
23 | self._cloop = threading.Thread(target=self.client.loop_start())
24 | self._cloop.start()
25 |
26 | def on_connect(self, client, userdata, flags, rc):
27 | """连接成功的回调函数"""
28 | # 订阅上下线消息
29 | self.client.subscribe("$SYS/brokers/emq@127.0.0.1/clients/#")
30 |
31 | # 读取数据库中所有的已经注册过的topic并且订阅
32 | sub_list = self.db.get_subscribe()
33 | # 防止没有获取到订阅列表
34 | while not sub_list:
35 | sub_list = self.db.get_subscribe()
36 | for i in sub_list:
37 | print(i[0],i[1])
38 | self.client.subscribe(i[0], i[1])
39 | # 修改客户端状态
40 | if rc == 0:
41 | self._client_status = True
42 |
43 | def on_message(self, client, userdata, msg):
44 | topic = msg.topic.split('/')
45 | client_id = topic[0]
46 | # 系统主题
47 | if client_id == '$SYS':
48 | status = 1 if topic[-1] == 'connected' else 0
49 | device_id = topic[-2]
50 | while not self.db.update_dev_stus(device_id, status):
51 | pass
52 | # 设备消息
53 | else:
54 | stream = topic[1]
55 | data = msg.payload.decode()
56 | while not self.db.write_data(client_id, stream, data):
57 | pass
58 |
59 |
60 |
61 |
62 |
63 | c = MqClient('System', '123', '123')
64 | while True:
65 | pass
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ### 项目简介
2 | 项目基于MQTT协议,采用EMQ消息服务器实现MQTT通信功能。设备接入需完成auth认证,如果需要对消息进行持久化处理还需要在后台注册你的设备和设备流信息,除此之外还可用于组件自己的网络,自定义主题收发消息即可。在后台可直接对已注册的设备发送指令,默认发送主题为$system/clientID,也可自定义发送主题(系统主题除外)。后台提供对设备、数据流、触发器的管理、查看历史上传数据、下发指令等功能。
3 | ### 开发环境
4 | * 后端:
5 | * Django 2.1.2
6 | * django-cors-headers 2.4.0
7 | * djangorestframework 3.9.0
8 | * requests 2.20.0
9 | * PyMySQL 0.9.2
10 | * 前端:
11 | * axios 0.18.0
12 | * echarts 4.2.0
13 | * element-ui 2.4.9
14 | * vue 2.5.2
15 | * vue-router 3.0.1
16 | * vuex 3.0.1
17 | * 硬件:
18 | * pubsubclient
19 | * 消息持久化服务:
20 | * paho-mqtt 1.4.0
21 | * SQLAlchemy 1.2.14
22 | * 数据库:
23 | * MySQL 5.7.0
24 | * EMQ:
25 | * emqx 2.3.0
26 |
27 | ### 项目整体架构
28 | 由EMQ服务器管理设备接入认证、消息分发,项目基本没有对EMQ服务做出修改,主要是对EMQ的权限认证、访问控制规则做了相应的变化,具体的修改方法请查看博客连载https://blog.csdn.net/FanMLei
29 |
30 | 消息持久化服务使用paho-mqtt实现mqtt通信对注册数据流进行监听,并将收到的消息写入数据库中。服务独立于后端项目独运行方便日后的扩展,每隔一分钟会刷新订阅列表,防止新注册的数据流无法接收消息。
31 |
32 | 后端提供设备信息、数据流信息、触发器信息、历史数据的管理接口以及网站的常规接口,接口使用rest Framework框架实现,同时通过API接口获取EMQ服务的状态信息和下发指令
33 |
34 | 前端负责数据展示,界面使用elementUI,图表使用echarts进行渲染,通过axios获取数据内容
35 |
36 | ### 项目结构简介
37 | APPFont: 前端项目
38 | Hardware: 硬件连接测试代码
39 | IOTPlatform: 后端项目
40 | MQTT: 消息持久化服务
41 |
42 | ### 更新计划
43 | >>>手机端页面适配(网页或者微信小程序)
44 | >>>完善触发器通知
45 | >>>完善接入指南、增加更多的硬件连接示例
46 | >>>API接口
47 |
48 | ### 联系方式
49 | Email : 15638515832@163.com
50 | QQ: 1193589986
51 | 博客: https://blog.csdn.net/FanMLei
52 |
--------------------------------------------------------------------------------