├── README.MD ├── Serve ├── .gitignore ├── README.MD ├── api_router.js ├── app.js ├── bin │ └── www ├── config.js ├── controller │ ├── device.js │ └── sensor_value.js ├── models │ ├── device.js │ ├── index.js │ ├── sensor_value.js │ └── test_data.js ├── package.json └── redis.js ├── angular ├── .bowerrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .yo-rc.json ├── README.MD ├── bower.json ├── e2e │ ├── .eslintrc │ ├── main.po.js │ └── main.spec.js ├── gulp │ ├── .eslintrc │ ├── build.js │ ├── conf.js │ ├── e2e-tests.js │ ├── inject.js │ ├── scripts.js │ ├── server.js │ ├── styles.js │ ├── unit-tests.js │ └── watch.js ├── gulpfile.js ├── karma.conf.js ├── package.json ├── protractor.conf.js └── src │ ├── Cyborg.scss │ ├── app │ ├── app.js │ ├── app.resource.js │ ├── app.route.js │ ├── components │ │ └── navbar │ │ │ └── navbar.html │ ├── dashboard │ │ ├── dashboard.ctrl.js │ │ ├── dashboard.html │ │ └── dashboard.scss │ ├── index.scss │ └── my-device │ │ ├── my-device.ctrl.js │ │ ├── my-device.html │ │ └── my-device.scss │ ├── assets │ └── images │ │ └── temperature.png │ ├── favicon.ico │ └── index.html ├── doc ├── README.MD ├── img │ ├── dashboard.png │ ├── devices.png │ └── system.png ├── 答辩Slide show.key ├── 答辩Slide show.pdf ├── 论文.docx ├── 论文.pdf └── 论文草稿.png └── hardware ├── .gitignore ├── Makefile ├── Makefile-user.mk ├── README.MD ├── app ├── application.cpp └── led.cpp └── include ├── led.h └── user_config.h /README.MD: -------------------------------------------------------------------------------- 1 | # myIot 2 | 我的毕业设计,一个基于物联网的温度采集系统。ESP8266 WIFI芯片采集温度信息,服务器端使用Node.js 的Express框架编程实现,浏览器端展示温度曲线,使用Angular Js框架实现。 3 | 4 | ### 目录结构 5 | 6 | ``` 7 | . 8 | ├── README.md 9 | ├── server // 服务端目录 10 | ├── angular // angular端目录 11 | ├── doc // 毕设相关文档 12 | ├── hardware // ESP8266硬件端目录 13 | . 14 | ``` 15 | ## 系统概述 16 | ### 框图: 17 | ![Image of system page](doc/img/system.png) 18 | ### [硬件端](https://github.com/nieheyong/myIot/tree/master/hardware) 19 | 温度信息采集主要使用 ESP8266 WIFI 芯片通过 DHT 22 传感器采集环境温度信息,通过WIFI将温度信息发往后台服务器。 20 | 21 | ### [服务端](https://github.com/nieheyong/myIot/tree/master/Serve) 22 | 23 | 后台服务器采用 Node.js 编程,使用Express框架,MongoDB和Redis数据库。为前端和温度信息采集硬件端提供 REST API 服务。 24 | 25 | ### [前端](https://github.com/nieheyong/myIot/tree/master/angular) 26 | 前端使用 AngularJS ,Chart.js 图表库可视化温 度数据,Bootstrap 作为样式库并提供响应式布局。通过 HTTP 协议获取后台的温度数据绘制温度曲线。支持实时温度曲线和历史温度查看。 27 | 28 | 29 | ## 界面效果 30 | ![Image of devices page](doc/img/devices.png) 31 | ![Image of dashboard page](doc/img/dashboard.png) 32 | -------------------------------------------------------------------------------- /Serve/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | DB/ 3 | dump.rdb 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /Serve/README.MD: -------------------------------------------------------------------------------- 1 | # Node.js服务端 2 | 服务端使用基于Node.js的Express框架,[MongoDB](https://www.mongodb.com/)以及[Redis](http://redis.io/)数据库。 3 | ### 开发 4 | 5 | ##### 安装项目及依赖 6 | ``` 7 | $ git clone https://github.com/nieheyong/myIot.git 8 | $ cd myIot/Serve 9 | $ npm install 10 | ``` 11 | ##### 运行 12 | 需要先运行[MongoDB](https://www.mongodb.com/)以及[Redis](http://redis.io/). 13 | ``` 14 | $ npm start 15 | ``` 16 | -------------------------------------------------------------------------------- /Serve/api_router.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var deviceController = require('./controller/device'); 3 | var sensorValueController = require('./controller/sensor_value'); 4 | var config = require('./config'); 5 | var router = express.Router(); 6 | 7 | // 传感器 8 | router.get('/devices', deviceController.get); 9 | router.post('/devices', deviceController.creat); 10 | 11 | router.get('/sensor/:sensor_id/value/history', sensorValueController.getHistory); 12 | router.get('/sensor/:sensor_id/value/realtime', sensorValueController.realTime); 13 | router.post('/sensor/:sensor_id/value', sensorValueController.post); 14 | 15 | 16 | module.exports = router; 17 | -------------------------------------------------------------------------------- /Serve/app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var logger = require('morgan'); 4 | var bodyParser = require('body-parser'); 5 | var models=require('./models'); 6 | var apiRoute = require('./api_router'); 7 | 8 | var app = express(); 9 | 10 | app.use(logger('dev')); 11 | app.use(bodyParser.json()); 12 | app.use(bodyParser.urlencoded({ extended: false })); 13 | 14 | app.use(express.static(path.join(__dirname, '../angular/dist'))); 15 | 16 | 17 | app.all('*', function(req, res, next) { 18 | res.set('Access-Control-Allow-Origin', '*'); 19 | res.set('Access-Control-Allow-Credentials', true); 20 | res.set('Access-Control-Allow-Methods', 'GET, POST, DELETE, PUT'); 21 | res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization'); 22 | if ('OPTIONS' == req.method) return res.send(200); 23 | next(); 24 | }); 25 | 26 | 27 | app.use('/api', apiRoute); 28 | 29 | // catch 404 and forward to error handler 30 | app.use(function(req, res, next) { 31 | var err = new Error('Not Found'); 32 | err.status = 404; 33 | next(err); 34 | }); 35 | 36 | // error handlers 37 | 38 | // development error handler 39 | // will print stacktrace 40 | if (app.get('env') === 'development') { 41 | app.use(function(err, req, res, next) { 42 | res.status(err.status || 500); 43 | res.render('error', { 44 | message: err.message, 45 | error: err 46 | }); 47 | }); 48 | } 49 | 50 | // production error handler 51 | // no stacktraces leaked to user 52 | app.use(function(err, req, res, next) { 53 | res.status(err.status || 500); 54 | res.json({ 55 | message: err.message, 56 | error: {} 57 | }); 58 | }); 59 | 60 | module.exports = app; 61 | -------------------------------------------------------------------------------- /Serve/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('myIot:server'); 9 | var http = require('http'); 10 | var logger = require('morgan'); 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | server.listen(port); 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | console.log(''); 91 | console.log('API is starting on http://localhost:3000'); 92 | console.log(''); 93 | } 94 | -------------------------------------------------------------------------------- /Serve/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * config 3 | */ 4 | 5 | 6 | var config = { 7 | // debug 为 true 时,用于本地调试 8 | debug: true, 9 | 10 | host: 'localhost', 11 | // mongodb 配置 12 | mongodb: 'mongodb://127.0.0.1/myIot', 13 | port: 3000 14 | }; 15 | 16 | module.exports = config; 17 | -------------------------------------------------------------------------------- /Serve/controller/device.js: -------------------------------------------------------------------------------- 1 | var Device=require('../models').Device; 2 | 3 | exports.get = function (req, res, next) { 4 | Device.find(function(err,devices){ 5 | if (err) throw err; 6 | res.json(devices); 7 | }); 8 | }; 9 | 10 | exports.creat = function (req, res, next) { 11 | Device.create(req.body.device,function(err,sensors){ 12 | if (err) throw err; 13 | res.json(sensors); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /Serve/controller/sensor_value.js: -------------------------------------------------------------------------------- 1 | var SensorValue = require('../models').SensorValue; 2 | var redisClient = require('../redis').redisClient; 3 | var _ = require('lodash'); 4 | 5 | 6 | exports.get = function(req, res, next) { 7 | 8 | }; 9 | 10 | 11 | exports.getHistory = function(req, res, next) { 12 | var sensor_id = req.params.sensor_id; 13 | var start = req.query.start || 0; 14 | var end = req.query.end || 0; 15 | 16 | SensorValue.find({ 17 | sensor_id: sensor_id 18 | }) 19 | //.limit(336) 20 | .select('value timestamp') 21 | .where('timestamp').gte(start).lte(end) 22 | .sort('timestamp') 23 | .exec(function(err, sensorValues) { 24 | if (err) { 25 | return false; 26 | } 27 | res.json(sensorValues); 28 | }); 29 | 30 | }; 31 | 32 | var forever = 4100688000000; //2099-12-12 33 | 34 | exports.post = function(req, res, next) { 35 | var sensor_id = Number(req.params.sensor_id); 36 | var value = req.body.value; 37 | 38 | 39 | var timestamp = new Date().getTime(); 40 | 41 | redisClient.zadd(sensor_id, timestamp, (timestamp * 10000) + value, function(err, response) { 42 | if (err) throw err; 43 | console.log('added ' + response + ' items.'); 44 | }); 45 | 46 | redisClient.zremrangebyscore(sensor_id, 0, timestamp - tenMin, function(err, response) { 47 | if (err) throw err; 48 | console.log('removeAll ' + response + ' items.'); 49 | }); 50 | 51 | if (req.body.save) { 52 | SensorValue.create({ 53 | sensor_id: sensor_id, 54 | value: value 55 | }, function(err, sensors) { 56 | if (err) { 57 | return false; 58 | } 59 | res.json(sensors); 60 | }); 61 | } else { 62 | res.send({ 63 | success: true 64 | }); 65 | } 66 | }; 67 | 68 | 69 | var tenMin = 60*10 * 1000; 70 | exports.realTime = function(req, res, next) { 71 | var sensor_id = Number(req.params.sensor_id);//获取传感器ID 72 | var latsTimestamp = Number(req.query.latsTimestamp) || 0;//上次获取数据的时间戳 73 | var timestamp = new Date().getTime();//当前时间戳 74 | //移除十分钟之前的数据 75 | redisClient.zremrangebyscore(sensor_id, 0, timestamp - tenMin, function(err, response) { 76 | if (err) throw err; 77 | console.log('removeAll ' + response + ' items.'); 78 | //获取最新的数据 79 | redisClient.zrangebyscore(sensor_id, latsTimestamp + 1, forever, function(err, response) { 80 | if (err) throw err; 81 | 82 | var timestamp = parseInt(_.last(response) / 10000); 83 | _.each(response, function(data, index) { 84 | response[index] = response[index] % 10000; 85 | }); 86 | res.json({ 87 | data: response, 88 | latsTimestamp: timestamp 89 | }); 90 | }); 91 | }); 92 | 93 | }; 94 | -------------------------------------------------------------------------------- /Serve/models/device.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var Schema = mongoose.Schema; 3 | 4 | var SensorSchema = new Schema({ 5 | sensor_id: { type: Number }, 6 | name: { type: String,default:'temperature sensor'}, 7 | sensor_type: { type: String } 8 | }); 9 | 10 | var DeviceSchema = new Schema({ 11 | device_id:{type:Number,index:true,unique:true}, 12 | name:{type:String}, 13 | profile:{type: String,default:''}, 14 | create_at: { type: Number, default: new Date().getTime() }, 15 | sensors:[SensorSchema] 16 | }); 17 | 18 | mongoose.model('Device', DeviceSchema); 19 | -------------------------------------------------------------------------------- /Serve/models/index.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var config = require('../config'); 3 | 4 | mongoose.connect(config.mongodb, { 5 | server: {poolSize: 20} 6 | }, function (err) { 7 | if (err) { 8 | console.log('connect to %s error: ', config.db, err.message); 9 | process.exit(1); 10 | }else { 11 | console.log('connect to mongodb success'); 12 | require('./test_data'); 13 | } 14 | }); 15 | 16 | // models 17 | require('./device'); 18 | require('./sensor_value'); 19 | 20 | exports.Device = mongoose.model('Device'); 21 | exports.SensorValue = mongoose.model('SensorValue'); 22 | -------------------------------------------------------------------------------- /Serve/models/sensor_value.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var Schema = mongoose.Schema; 3 | 4 | var SensorValueSchema = new Schema({ 5 | sensor_id: { type: Number }, 6 | value: { type: Number}, 7 | timestamp:{type: Number, default: new Date().getTime()} 8 | }); 9 | 10 | mongoose.model('SensorValue', SensorValueSchema); -------------------------------------------------------------------------------- /Serve/models/test_data.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose'); 2 | var _ = require('lodash'); 3 | 4 | mongoose.model('Device').find({ 5 | device_id: 1 6 | }, function(err, devices) { 7 | if (err) throw err; 8 | if (!devices.length) { 9 | insertTestData(); 10 | } 11 | }); 12 | 13 | function insertTestData() { 14 | 15 | //插入四个测试设备 16 | var device1 = { 17 | device_id: 1, 18 | name: "教室的传感器", 19 | profile: "测量教室的温度", 20 | sensors: [{ 21 | sensor_id: 11, 22 | name: "wendu", 23 | sensor_type: "温度传感器" 24 | }] 25 | }; 26 | var device2 = { 27 | device_id: 2, 28 | name: "宿舍的传感器", 29 | profile: "测量宿舍的温度", 30 | sensors: { 31 | sensor_id: 21, 32 | name: "wendu", 33 | sensor_type: "温度传感器" 34 | } 35 | }; 36 | var device3 = { 37 | device_id: 3, 38 | name: "仓库的传感器", 39 | profile: "测量仓库的温度", 40 | sensors: { 41 | sensor_id: 31, 42 | name: "wendu", 43 | sensor_type: "温度传感器" 44 | } 45 | }; 46 | var device4 = { 47 | device_id: 4, 48 | name: "车间的传感器", 49 | profile: "测量车间的温度", 50 | sensors: { 51 | sensor_id: 41, 52 | name: "wendu", 53 | sensor_type: "温度传感器" 54 | } 55 | }; 56 | mongoose.model('Device').create([device1, device2, device3, device4]); 57 | 58 | // 插入四个传感器的历史数据,传感器数值随机生成,历史日期为2016-7-1前10天 59 | var sensorIDs = [11, 21, 31, 41]; 60 | _.each(sensorIDs, function(id) { 61 | var timestamp = 1467302400 * 1000; // 2016/7/1 0:0:0 0ms 62 | var count = 24 * 10; //10天的数据 63 | for (var i = 0; i < count; i++) { 64 | mongoose.model('SensorValue').create({ 65 | sensor_id: id, 66 | value: _.random(-10, 42.2), 67 | timestamp: timestamp 68 | }, function(err, sensors) { 69 | if (err) { 70 | return false; 71 | } 72 | }); 73 | timestamp = timestamp - 3600 * 1000; //一小时一个数据点 74 | } 75 | }); 76 | 77 | } 78 | -------------------------------------------------------------------------------- /Serve/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myIot", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www", 7 | "dev": "supervisor debug ./bin/www", 8 | "mongo": "mongod --dbpath ./DB" 9 | }, 10 | "dependencies": { 11 | "body-parser": "~1.13.2", 12 | "debug": "~2.2.0", 13 | "express": "^4.13.4", 14 | "lodash": "^4.6.1", 15 | "mongoose": "^4.4.4", 16 | "morgan": "~1.6.1", 17 | "redis": "^2.5.3", 18 | "serve-favicon": "~2.3.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Serve/redis.js: -------------------------------------------------------------------------------- 1 | var redis = require('redis'); 2 | var redisClient = redis.createClient(6379); 3 | 4 | redisClient.on('error', function (err) { 5 | console.log('Error ' + err); 6 | }); 7 | 8 | redisClient.on('connect', function () { 9 | console.log('Redis is ready'); 10 | }); 11 | 12 | exports.redis = redis; 13 | exports.redisClient = redisClient; 14 | -------------------------------------------------------------------------------- /angular/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /angular/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "plugins": ["angular"], 4 | "env": { 5 | "browser": true, 6 | "jasmine": true 7 | }, 8 | "globals": { 9 | "angular": true, 10 | "module": true, 11 | "inject": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /angular/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | coverage/ 4 | .sass-cache/ 5 | .idea/ 6 | .tmp/ 7 | dist/ 8 | -------------------------------------------------------------------------------- /angular/.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-gulp-angular": { 3 | "version": "1.0.2", 4 | "props": { 5 | "angularVersion": "~1.4.2", 6 | "angularModules": [], 7 | "jQuery": { 8 | "key": "jquery2" 9 | }, 10 | "resource": { 11 | "key": "angular-resource", 12 | "module": "ngResource" 13 | }, 14 | "router": { 15 | "key": "ui-router", 16 | "module": "ui.router" 17 | }, 18 | "ui": { 19 | "key": "bootstrap", 20 | "module": null 21 | }, 22 | "bootstrapComponents": { 23 | "key": "angular-strap", 24 | "module": "mgcrea.ngStrap" 25 | }, 26 | "cssPreprocessor": { 27 | "key": "node-sass", 28 | "extension": "scss" 29 | }, 30 | "jsPreprocessor": { 31 | "key": "noJsPrepro", 32 | "extension": "js", 33 | "srcExtension": "js" 34 | }, 35 | "htmlPreprocessor": { 36 | "key": "noHtmlPrepro", 37 | "extension": "html" 38 | }, 39 | "foundationComponents": { 40 | "name": null, 41 | "version": null, 42 | "key": null, 43 | "module": null 44 | }, 45 | "paths": { 46 | "src": "src", 47 | "dist": "dist", 48 | "e2e": "e2e", 49 | "tmp": ".tmp" 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /angular/README.MD: -------------------------------------------------------------------------------- 1 | # 前端 2 | 前端使用AngularJS框架,UI-Router路由控制,ng-resource与后台API交互,Bootstrap的[Cyborg主题](https://bootswatch.com/cyborg/)作为样式库, 3 | [AngularStrap](http://mgcrea.github.io/angular-strap/)作为控件库, 4 | [Angular Chart图表库](http://jtblin.github.io/angular-chart.js/)显示曲线图. 5 | ### 开发 6 | 7 | ##### 先安装工具 `gulp` 和 `bower`: 8 | ``` 9 | $ npm install -g gulp bower 10 | ``` 11 | ##### 安装项目及依赖 12 | ``` 13 | $ git clone https://github.com/nieheyong/myIot.git 14 | $ cd myIot/angular 15 | $ npm install 16 | $ bower install 17 | ``` 18 | ##### 运行 19 | ``` 20 | $ gulp serve 21 | ``` 22 | 会在浏览器中自动打开 http://localhost:3000 23 | 24 | ## 生产环境构建 25 | 26 | ``` 27 | $ gulp build 28 | ``` 29 | ## 界面效果 30 | ![Image of devices page](../doc/img/devices.png) 31 | ![Image of dashboard page](../doc/img/dashboard.png) 32 | -------------------------------------------------------------------------------- /angular/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myIot", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "jquery": "~2.1.4", 6 | "angular-resource": "~1.4.2", 7 | "angular-ui-router": "~0.2.15", 8 | "bootstrap-sass": "~3.3.5", 9 | "angular-strap": "~2.3.1", 10 | "animate.css": "~3.4.0", 11 | "angular": "~1.4.2", 12 | "angular-chart.js": "^0.9.0", 13 | "font-awesome": "^4.5.0" 14 | }, 15 | "devDependencies": { 16 | "angular-mocks": "~1.4.2" 17 | }, 18 | "overrides": { 19 | "bootstrap-sass": { 20 | "main": [ 21 | "assets/stylesheets/_bootstrap.scss", 22 | "assets/fonts/bootstrap/glyphicons-halflings-regular.eot", 23 | "assets/fonts/bootstrap/glyphicons-halflings-regular.svg", 24 | "assets/fonts/bootstrap/glyphicons-halflings-regular.ttf", 25 | "assets/fonts/bootstrap/glyphicons-halflings-regular.woff", 26 | "assets/fonts/bootstrap/glyphicons-halflings-regular.woff2" 27 | ] 28 | }, 29 | "font-awesome": { 30 | "main": [ 31 | "css/font-awesome.css", 32 | "fonts/FontAwesome.otf", 33 | "fonts/fontawesome-webfont.eot", 34 | "fonts/fontawesome-webfont.svg", 35 | "fonts/fontawesome-webfont.ttf", 36 | "fonts/fontawesome-webfont.woff", 37 | "fonts/fontawesome-webfont.woff2" 38 | ] 39 | } 40 | }, 41 | "resolutions": { 42 | "jquery": "~2.1.4", 43 | "angular": "~1.4.2" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /angular/e2e/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "browser": false, 4 | "element": false, 5 | "by": false, 6 | "$": false, 7 | "$$": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /angular/e2e/main.po.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file uses the Page Object pattern to define the main page for tests 3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var MainPage = function() { 9 | this.jumbEl = element(by.css('.jumbotron')); 10 | this.h1El = this.jumbEl.element(by.css('h1')); 11 | this.imgEl = this.jumbEl.element(by.css('img')); 12 | this.thumbnailEls = element(by.css('body')).all(by.repeater('awesomeThing in main.awesomeThings')); 13 | }; 14 | 15 | module.exports = new MainPage(); 16 | -------------------------------------------------------------------------------- /angular/e2e/main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('The main view', function () { 4 | var page; 5 | 6 | beforeEach(function () { 7 | browser.get('/index.html'); 8 | page = require('./main.po'); 9 | }); 10 | 11 | it('should include jumbotron with correct data', function() { 12 | expect(page.h1El.getText()).toBe('\'Allo, \'Allo!'); 13 | expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); 14 | expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); 15 | }); 16 | 17 | it('should list more than 5 awesome things', function () { 18 | expect(page.thumbnailEls.count()).toBeGreaterThan(5); 19 | }); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /angular/gulp/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /angular/gulp/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var $ = require('gulp-load-plugins')({ 8 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] 9 | }); 10 | 11 | gulp.task('partials', function () { 12 | return gulp.src([ 13 | path.join(conf.paths.src, '/app/**/*.html'), 14 | path.join(conf.paths.tmp, '/serve/app/**/*.html') 15 | ]) 16 | .pipe($.minifyHtml({ 17 | empty: true, 18 | spare: true, 19 | quotes: true 20 | })) 21 | .pipe($.angularTemplatecache('templateCacheHtml.js', { 22 | module: 'myIot', 23 | root: 'app' 24 | })) 25 | .pipe(gulp.dest(conf.paths.tmp + '/partials/')); 26 | }); 27 | 28 | gulp.task('html', ['inject', 'partials'], function () { 29 | var partialsInjectFile = gulp.src(path.join(conf.paths.tmp, '/partials/templateCacheHtml.js'), { read: false }); 30 | var partialsInjectOptions = { 31 | starttag: '', 32 | ignorePath: path.join(conf.paths.tmp, '/partials'), 33 | addRootSlash: false 34 | }; 35 | 36 | var htmlFilter = $.filter('*.html', { restore: true }); 37 | var jsFilter = $.filter('**/*.js', { restore: true }); 38 | var cssFilter = $.filter('**/*.css', { restore: true }); 39 | var assets; 40 | 41 | return gulp.src(path.join(conf.paths.tmp, '/serve/*.html')) 42 | .pipe($.inject(partialsInjectFile, partialsInjectOptions)) 43 | .pipe(assets = $.useref.assets()) 44 | .pipe($.rev()) 45 | .pipe(jsFilter) 46 | .pipe($.sourcemaps.init()) 47 | .pipe($.ngAnnotate()) 48 | .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', conf.errorHandler('Uglify')) 49 | .pipe($.sourcemaps.write('maps')) 50 | .pipe(jsFilter.restore) 51 | .pipe(cssFilter) 52 | .pipe($.sourcemaps.init()) 53 | .pipe($.replace('../../bower_components/bootstrap-sass/assets/fonts/bootstrap/', '../fonts/')) 54 | .pipe($.replace('../../bower_components/font-awesome/fonts/', '../fonts/')) 55 | .pipe($.minifyCss({ processImport: false })) 56 | .pipe($.sourcemaps.write('maps')) 57 | .pipe(cssFilter.restore) 58 | .pipe(assets.restore()) 59 | .pipe($.useref()) 60 | .pipe($.revReplace()) 61 | .pipe(htmlFilter) 62 | .pipe($.minifyHtml({ 63 | empty: true, 64 | spare: true, 65 | quotes: true, 66 | conditionals: true 67 | })) 68 | .pipe(htmlFilter.restore) 69 | .pipe(gulp.dest(path.join(conf.paths.dist, '/'))) 70 | .pipe($.size({ title: path.join(conf.paths.dist, '/'), showFiles: true })); 71 | }); 72 | 73 | // Only applies for fonts from bower dependencies 74 | // Custom fonts are handled by the "other" task 75 | gulp.task('fonts', function () { 76 | return gulp.src($.mainBowerFiles()) 77 | .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}')) 78 | .pipe($.flatten()) 79 | .pipe(gulp.dest(path.join(conf.paths.dist, '/fonts/'))); 80 | }); 81 | 82 | gulp.task('other', function () { 83 | var fileFilter = $.filter(function (file) { 84 | return file.stat.isFile(); 85 | }); 86 | 87 | return gulp.src([ 88 | path.join(conf.paths.src, '/**/*'), 89 | path.join('!' + conf.paths.src, '/**/*.{html,css,js,scss}') 90 | ]) 91 | .pipe(fileFilter) 92 | .pipe(gulp.dest(path.join(conf.paths.dist, '/'))); 93 | }); 94 | 95 | gulp.task('clean', function () { 96 | return $.del([path.join(conf.paths.dist, '/'), path.join(conf.paths.tmp, '/')]); 97 | }); 98 | 99 | gulp.task('build', ['html', 'fonts', 'other']); 100 | -------------------------------------------------------------------------------- /angular/gulp/conf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file contains the variables used in other gulp files 3 | * which defines tasks 4 | * By design, we only put there very generic config values 5 | * which are used in several places to keep good readability 6 | * of the tasks 7 | */ 8 | 9 | var gutil = require('gulp-util'); 10 | 11 | /** 12 | * The main paths of your project handle these with care 13 | */ 14 | exports.paths = { 15 | src: 'src', 16 | dist: 'dist', 17 | tmp: '.tmp', 18 | e2e: 'e2e' 19 | }; 20 | 21 | /** 22 | * Wiredep is the lib which inject bower dependencies in your project 23 | * Mainly used to inject script tags in the index.html but also used 24 | * to inject css preprocessor deps and js files in karma 25 | */ 26 | exports.wiredep = { 27 | exclude: [/\/bootstrap\.js$/, /\/bootstrap-sass\/.*\.js/, /\/bootstrap\.css/], 28 | directory: 'bower_components' 29 | }; 30 | 31 | /** 32 | * Common implementation for an error handler of a Gulp plugin 33 | */ 34 | exports.errorHandler = function(title) { 35 | 'use strict'; 36 | 37 | return function(err) { 38 | gutil.log(gutil.colors.red('[' + title + ']'), err.toString()); 39 | this.emit('end'); 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /angular/gulp/e2e-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | // Downloads the selenium webdriver 12 | gulp.task('webdriver-update', $.protractor.webdriver_update); 13 | 14 | gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); 15 | 16 | function runProtractor (done) { 17 | var params = process.argv; 18 | var args = params.length > 3 ? [params[3], params[4]] : []; 19 | 20 | gulp.src(path.join(conf.paths.e2e, '/**/*.js')) 21 | .pipe($.protractor.protractor({ 22 | configFile: 'protractor.conf.js', 23 | args: args 24 | })) 25 | .on('error', function (err) { 26 | // Make sure failed tests cause gulp to exit non-zero 27 | throw err; 28 | }) 29 | .on('end', function () { 30 | // Close browser sync server 31 | browserSync.exit(); 32 | done(); 33 | }); 34 | } 35 | 36 | gulp.task('protractor', ['protractor:src']); 37 | gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor); 38 | gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor); 39 | -------------------------------------------------------------------------------- /angular/gulp/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var $ = require('gulp-load-plugins')(); 8 | 9 | var wiredep = require('wiredep').stream; 10 | var _ = require('lodash'); 11 | 12 | var browserSync = require('browser-sync'); 13 | 14 | gulp.task('inject-reload', ['inject'], function() { 15 | browserSync.reload(); 16 | }); 17 | 18 | gulp.task('inject', ['scripts', 'styles'], function () { 19 | var injectStyles = gulp.src([ 20 | path.join(conf.paths.tmp, '/serve/app/**/*.css'), 21 | path.join('!' + conf.paths.tmp, '/serve/app/vendor.css') 22 | ], { read: false }); 23 | 24 | var injectScripts = gulp.src([ 25 | path.join(conf.paths.src, '/app/**/*.module.js'), 26 | path.join(conf.paths.src, '/app/**/*.js'), 27 | path.join('!' + conf.paths.src, '/app/**/*.spec.js'), 28 | path.join('!' + conf.paths.src, '/app/**/*.mock.js'), 29 | ]) 30 | .pipe($.angularFilesort()).on('error', conf.errorHandler('AngularFilesort')); 31 | 32 | var injectOptions = { 33 | ignorePath: [conf.paths.src, path.join(conf.paths.tmp, '/serve')], 34 | addRootSlash: false 35 | }; 36 | 37 | return gulp.src(path.join(conf.paths.src, '/*.html')) 38 | .pipe($.inject(injectStyles, injectOptions)) 39 | .pipe($.inject(injectScripts, injectOptions)) 40 | .pipe(wiredep(_.extend({}, conf.wiredep))) 41 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve'))); 42 | }); 43 | -------------------------------------------------------------------------------- /angular/gulp/scripts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | 12 | gulp.task('scripts-reload', function() { 13 | return buildScripts() 14 | .pipe(browserSync.stream()); 15 | }); 16 | 17 | gulp.task('scripts', function() { 18 | return buildScripts(); 19 | }); 20 | 21 | function buildScripts() { 22 | return gulp.src(path.join(conf.paths.src, '/app/**/*.js')) 23 | .pipe($.eslint()) 24 | .pipe($.eslint.format()) 25 | .pipe($.size()) 26 | }; 27 | -------------------------------------------------------------------------------- /angular/gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | var browserSyncSpa = require('browser-sync-spa'); 9 | 10 | var util = require('util'); 11 | 12 | var proxyMiddleware = require('http-proxy-middleware'); 13 | 14 | function browserSyncInit(baseDir, browser) { 15 | browser = browser === undefined ? 'default' : browser; 16 | 17 | var routes = null; 18 | if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) { 19 | routes = { 20 | '/bower_components': 'bower_components' 21 | }; 22 | } 23 | 24 | var server = { 25 | baseDir: baseDir, 26 | routes: routes 27 | }; 28 | 29 | /* 30 | * You can add a proxy to your backend by uncommenting the line below. 31 | * You just have to configure a context which will we redirected and the target url. 32 | * Example: $http.get('/users') requests will be automatically proxified. 33 | * 34 | * For more details and option, https://github.com/chimurai/http-proxy-middleware/blob/v0.9.0/README.md 35 | */ 36 | // server.middleware = proxyMiddleware('/users', {target: 'http://jsonplaceholder.typicode.com', changeOrigin: true}); 37 | 38 | browserSync.instance = browserSync.init({ 39 | startPath: '/', 40 | server: server, 41 | browser: browser 42 | }); 43 | } 44 | 45 | browserSync.use(browserSyncSpa({ 46 | selector: '[ng-app]'// Only needed for angular apps 47 | })); 48 | 49 | gulp.task('serve', ['watch'], function () { 50 | browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]); 51 | }); 52 | 53 | gulp.task('serve:dist', ['build'], function () { 54 | browserSyncInit(conf.paths.dist); 55 | }); 56 | 57 | gulp.task('serve:e2e', ['inject'], function () { 58 | browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []); 59 | }); 60 | 61 | gulp.task('serve:e2e-dist', ['build'], function () { 62 | browserSyncInit(conf.paths.dist, []); 63 | }); 64 | -------------------------------------------------------------------------------- /angular/gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | var $ = require('gulp-load-plugins')(); 10 | 11 | var wiredep = require('wiredep').stream; 12 | var _ = require('lodash'); 13 | 14 | gulp.task('styles-reload', ['styles'], function() { 15 | return buildStyles() 16 | .pipe(browserSync.stream()); 17 | }); 18 | 19 | gulp.task('styles', function() { 20 | return buildStyles(); 21 | }); 22 | 23 | var buildStyles = function() { 24 | var sassOptions = { 25 | style: 'expanded' 26 | }; 27 | 28 | var injectFiles = gulp.src([ 29 | path.join(conf.paths.src, '/app/**/*.scss'), 30 | path.join('!' + conf.paths.src, '/app/index.scss') 31 | ], { read: false }); 32 | 33 | var injectOptions = { 34 | transform: function(filePath) { 35 | filePath = filePath.replace(conf.paths.src + '/app/', ''); 36 | return '@import "' + filePath + '";'; 37 | }, 38 | starttag: '// injector', 39 | endtag: '// endinjector', 40 | addRootSlash: false 41 | }; 42 | 43 | 44 | return gulp.src([ 45 | path.join(conf.paths.src, '/app/index.scss') 46 | ]) 47 | .pipe($.inject(injectFiles, injectOptions)) 48 | .pipe(wiredep(_.extend({}, conf.wiredep))) 49 | .pipe($.sourcemaps.init()) 50 | .pipe($.sass(sassOptions)).on('error', conf.errorHandler('Sass')) 51 | .pipe($.autoprefixer()).on('error', conf.errorHandler('Autoprefixer')) 52 | .pipe($.sourcemaps.write()) 53 | .pipe(gulp.dest(path.join(conf.paths.tmp, '/serve/app/'))); 54 | }; 55 | -------------------------------------------------------------------------------- /angular/gulp/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var karma = require('karma'); 8 | 9 | var pathSrcHtml = [ 10 | path.join(conf.paths.src, '/**/*.html') 11 | ]; 12 | 13 | var pathSrcJs = [ 14 | path.join(conf.paths.src, '/**/!(*.spec).js') 15 | ]; 16 | 17 | function runTests (singleRun, done) { 18 | var reporters = ['progress']; 19 | var preprocessors = {}; 20 | 21 | pathSrcHtml.forEach(function(path) { 22 | preprocessors[path] = ['ng-html2js']; 23 | }); 24 | 25 | if (singleRun) { 26 | pathSrcJs.forEach(function(path) { 27 | preprocessors[path] = ['coverage']; 28 | }); 29 | reporters.push('coverage') 30 | } 31 | 32 | var localConfig = { 33 | configFile: path.join(__dirname, '/../karma.conf.js'), 34 | singleRun: singleRun, 35 | autoWatch: !singleRun, 36 | reporters: reporters, 37 | preprocessors: preprocessors 38 | }; 39 | 40 | var server = new karma.Server(localConfig, function(failCount) { 41 | done(failCount ? new Error("Failed " + failCount + " tests.") : null); 42 | }) 43 | server.start(); 44 | } 45 | 46 | gulp.task('test', ['scripts'], function(done) { 47 | runTests(true, done); 48 | }); 49 | 50 | gulp.task('test:auto', ['watch'], function(done) { 51 | runTests(false, done); 52 | }); 53 | -------------------------------------------------------------------------------- /angular/gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp'); 5 | var conf = require('./conf'); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | function isOnlyChange(event) { 10 | return event.type === 'changed'; 11 | } 12 | 13 | gulp.task('watch', ['inject'], function () { 14 | 15 | gulp.watch([path.join(conf.paths.src, '/*.html'), 'bower.json'], ['inject-reload']); 16 | 17 | gulp.watch([ 18 | path.join(conf.paths.src, '/app/**/*.css'), 19 | path.join(conf.paths.src, '/app/**/*.scss') 20 | ], function(event) { 21 | if(isOnlyChange(event)) { 22 | gulp.start('styles-reload'); 23 | } else { 24 | gulp.start('inject-reload'); 25 | } 26 | }); 27 | 28 | gulp.watch(path.join(conf.paths.src, '/app/**/*.js'), function(event) { 29 | if(isOnlyChange(event)) { 30 | gulp.start('scripts-reload'); 31 | } else { 32 | gulp.start('inject-reload'); 33 | } 34 | }); 35 | 36 | gulp.watch(path.join(conf.paths.src, '/app/**/*.html'), function(event) { 37 | browserSync.reload(event.path); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /angular/gulpfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your gulpfile! 3 | * The gulp tasks are splitted in several files in the gulp directory 4 | * because putting all here was really too long 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var gulp = require('gulp'); 10 | var wrench = require('wrench'); 11 | 12 | /** 13 | * This will load all js or coffee files in the gulp directory 14 | * in order to load all gulp tasks 15 | */ 16 | wrench.readdirSyncRecursive('./gulp').filter(function(file) { 17 | return (/\.(js|coffee)$/i).test(file); 18 | }).map(function(file) { 19 | require('./gulp/' + file); 20 | }); 21 | 22 | 23 | /** 24 | * Default task clean temporaries directories and launch the 25 | * main optimization build task 26 | */ 27 | gulp.task('default', ['clean'], function () { 28 | gulp.start('build'); 29 | }); 30 | -------------------------------------------------------------------------------- /angular/karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var conf = require('./gulp/conf'); 5 | 6 | var _ = require('lodash'); 7 | var wiredep = require('wiredep'); 8 | 9 | var pathSrcHtml = [ 10 | path.join(conf.paths.src, '/**/*.html') 11 | ]; 12 | 13 | function listFiles() { 14 | var wiredepOptions = _.extend({}, conf.wiredep, { 15 | dependencies: true, 16 | devDependencies: true 17 | }); 18 | 19 | var patterns = wiredep(wiredepOptions).js 20 | .concat([ 21 | path.join(conf.paths.src, '/app/**/*.module.js'), 22 | path.join(conf.paths.src, '/app/**/*.js'), 23 | path.join(conf.paths.src, '/**/*.spec.js'), 24 | path.join(conf.paths.src, '/**/*.mock.js'), 25 | ]) 26 | .concat(pathSrcHtml); 27 | 28 | var files = patterns.map(function(pattern) { 29 | return { 30 | pattern: pattern 31 | }; 32 | }); 33 | files.push({ 34 | pattern: path.join(conf.paths.src, '/assets/**/*'), 35 | included: false, 36 | served: true, 37 | watched: false 38 | }); 39 | return files; 40 | } 41 | 42 | module.exports = function(config) { 43 | 44 | var configuration = { 45 | files: listFiles(), 46 | 47 | singleRun: true, 48 | 49 | autoWatch: false, 50 | 51 | ngHtml2JsPreprocessor: { 52 | stripPrefix: conf.paths.src + '/', 53 | moduleName: 'myIot' 54 | }, 55 | 56 | logLevel: 'WARN', 57 | 58 | frameworks: ['jasmine', 'angular-filesort'], 59 | 60 | angularFilesort: { 61 | whitelist: [path.join(conf.paths.src, '/**/!(*.html|*.spec|*.mock).js')] 62 | }, 63 | 64 | browsers : ['PhantomJS'], 65 | 66 | plugins : [ 67 | 'karma-phantomjs-launcher', 68 | 'karma-angular-filesort', 69 | 'karma-coverage', 70 | 'karma-jasmine', 71 | 'karma-ng-html2js-preprocessor' 72 | ], 73 | 74 | coverageReporter: { 75 | type : 'html', 76 | dir : 'coverage/' 77 | }, 78 | 79 | reporters: ['progress'], 80 | 81 | proxies: { 82 | '/assets/': path.join('/base/', conf.paths.src, '/assets/') 83 | } 84 | }; 85 | 86 | // This is the default preprocessors configuration for a usage with Karma cli 87 | // The coverage preprocessor is added in gulp/unit-test.js only for single tests 88 | // It was not possible to do it there because karma doesn't let us now if we are 89 | // running a single test or not 90 | configuration.preprocessors = {}; 91 | pathSrcHtml.forEach(function(path) { 92 | configuration.preprocessors[path] = ['ng-html2js']; 93 | }); 94 | 95 | // This block is needed to execute Chrome on Travis 96 | // If you ever plan to use Chrome and Travis, you can keep it 97 | // If not, you can safely remove it 98 | // https://github.com/karma-runner/karma/issues/1144#issuecomment-53633076 99 | if(configuration.browsers[0] === 'Chrome' && process.env.TRAVIS) { 100 | configuration.customLaunchers = { 101 | 'chrome-travis-ci': { 102 | base: 'Chrome', 103 | flags: ['--no-sandbox'] 104 | } 105 | }; 106 | configuration.browsers = ['chrome-travis-ci']; 107 | } 108 | 109 | config.set(configuration); 110 | }; 111 | -------------------------------------------------------------------------------- /angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myIot", 3 | "version": "0.0.0", 4 | "dependencies": {}, 5 | "scripts": { 6 | "test": "gulp test" 7 | }, 8 | "devDependencies": { 9 | "estraverse": "~4.1.0", 10 | "gulp": "~3.9.0", 11 | "gulp-autoprefixer": "~3.0.2", 12 | "gulp-angular-templatecache": "~1.8.0", 13 | "del": "~2.0.2", 14 | "lodash": "~3.10.1", 15 | "gulp-minify-css": "~1.2.1", 16 | "gulp-filter": "~3.0.1", 17 | "gulp-flatten": "~0.2.0", 18 | "gulp-eslint": "~1.0.0", 19 | "eslint-plugin-angular": "~0.12.0", 20 | "gulp-load-plugins": "~0.10.0", 21 | "gulp-size": "~2.0.0", 22 | "gulp-uglify": "~1.4.1", 23 | "gulp-useref": "~1.3.0", 24 | "gulp-util": "~3.0.6", 25 | "gulp-ng-annotate": "~1.1.0", 26 | "gulp-replace": "~0.5.4", 27 | "gulp-rename": "~1.2.2", 28 | "gulp-rev": "~6.0.1", 29 | "gulp-rev-replace": "~0.4.2", 30 | "gulp-minify-html": "~1.0.4", 31 | "gulp-inject": "~3.0.0", 32 | "gulp-protractor": "~1.0.0", 33 | "gulp-sourcemaps": "~1.6.0", 34 | "gulp-sass": "~2.0.4", 35 | "gulp-angular-filesort": "~1.1.1", 36 | "main-bower-files": "~2.9.0", 37 | "wiredep": "~2.2.2", 38 | "karma": "~0.13.10", 39 | "karma-jasmine": "~0.3.6", 40 | "karma-phantomjs-launcher": "~0.2.1", 41 | "phantomjs": "~1.9.18", 42 | "karma-angular-filesort": "~1.0.0", 43 | "karma-coverage": "~0.5.2", 44 | "karma-ng-html2js-preprocessor": "~0.2.0", 45 | "browser-sync": "~2.9.11", 46 | "browser-sync-spa": "~1.0.3", 47 | "http-proxy-middleware": "~0.9.0", 48 | "chalk": "~1.1.1", 49 | "uglify-save-license": "~0.4.1", 50 | "wrench": "~1.5.8" 51 | }, 52 | "engines": { 53 | "node": ">=0.10.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /angular/protractor.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths; 4 | 5 | // An example configuration file. 6 | exports.config = { 7 | // The address of a running selenium server. 8 | //seleniumAddress: 'http://localhost:4444/wd/hub', 9 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json 10 | 11 | // Capabilities to be passed to the webdriver instance. 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | 16 | baseUrl: 'http://localhost:3000', 17 | 18 | // Spec patterns are relative to the current working directory when 19 | // protractor is called. 20 | specs: [paths.e2e + '/**/*.js'], 21 | 22 | // Options to be passed to Jasmine-node. 23 | jasmineNodeOpts: { 24 | showColors: true, 25 | defaultTimeoutInterval: 30000 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /angular/src/Cyborg.scss: -------------------------------------------------------------------------------- 1 | $bootstrap-sass-asset-helper: false !default; 2 | // Cyborg 3.3.6 3 | // Variables 4 | // -------------------------------------------------- 5 | 6 | 7 | //== Colors 8 | // 9 | //## Gray and brand colors for use across Bootstrap. 10 | 11 | $gray-base: #000 !default; 12 | $gray-darker: #222 !default; // #222 13 | $gray-dark: #282828 !default; // #333 14 | $gray: #555 !default; // #555 15 | $gray-light: #888 !default; // #999 16 | $gray-lighter: #ADAFAE !default; // #eee 17 | 18 | $brand-primary: #2A9FD6 !default; 19 | $brand-success: #77B300 !default; 20 | $brand-info: #9933CC !default; 21 | $brand-warning: #FF8800 !default; 22 | $brand-danger: #CC0000 !default; 23 | 24 | 25 | //== Scaffolding 26 | // 27 | //## Settings for some of the most global styles. 28 | 29 | //** Background color for ``. 30 | $body-bg: #060606 !default; 31 | //** Global text color on ``. 32 | $text-color: $gray-light !default; 33 | 34 | //** Global textual link color. 35 | $link-color: $brand-primary !default; 36 | //** Link hover color set via `darken()` function. 37 | $link-hover-color: $link-color !default; 38 | //** Link hover decoration. 39 | $link-hover-decoration: underline !default; 40 | 41 | 42 | //== Typography 43 | // 44 | //## Font, line-height, and color for body text, headings, and more. 45 | 46 | $font-family-sans-serif: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif !default; 47 | $font-family-serif: Georgia, "Times New Roman", Times, serif !default; 48 | //** Default monospace fonts for ``, ``, and `
`.
 49 | $font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace !default;
 50 | $font-family-base:        $font-family-sans-serif !default;
 51 | 
 52 | $font-size-base:          14px !default;
 53 | $font-size-large:         ceil(($font-size-base * 1.25)) !default; // ~18px
 54 | $font-size-small:         ceil(($font-size-base * 0.85)) !default; // ~12px
 55 | 
 56 | $font-size-h1:            56px !default;
 57 | $font-size-h2:            45px !default;
 58 | $font-size-h3:            34px !default;
 59 | $font-size-h4:            24px !default;
 60 | $font-size-h5:            20px !default;
 61 | $font-size-h6:            16px !default;
 62 | 
 63 | //** Unit-less `line-height` for use in components like buttons.
 64 | $line-height-base:        1.428571429 !default; // 20/14
 65 | //** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
 66 | $line-height-computed:    floor(($font-size-base * $line-height-base)) !default; // ~20px
 67 | 
 68 | //** By default, this inherits from the ``.
 69 | $headings-font-family:    $font-family-base !default;
 70 | $headings-font-weight:    500 !default;
 71 | $headings-line-height:    1.1 !default;
 72 | $headings-color:          #fff !default;
 73 | 
 74 | 
 75 | //== Iconography
 76 | //
 77 | //## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
 78 | 
 79 | //** Load fonts from this directory.
 80 | $icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
 81 | //** File name for all font files.
 82 | $icon-font-name:          "glyphicons-halflings-regular" !default;
 83 | //** Element ID within SVG icon file.
 84 | $icon-font-svg-id:        "glyphicons_halflingsregular" !default;
 85 | 
 86 | 
 87 | //== Components
 88 | //
 89 | //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
 90 | 
 91 | $padding-base-vertical:     8px !default;
 92 | $padding-base-horizontal:   12px !default;
 93 | 
 94 | $padding-large-vertical:    14px !default;
 95 | $padding-large-horizontal:  16px !default;
 96 | 
 97 | $padding-small-vertical:    5px !default;
 98 | $padding-small-horizontal:  10px !default;
 99 | 
100 | $padding-xs-vertical:       1px !default;
101 | $padding-xs-horizontal:     5px !default;
102 | 
103 | $line-height-large:         1.3333333 !default; // extra decimals for Win 8.1 Chrome
104 | $line-height-small:         1.5 !default;
105 | 
106 | $border-radius-base:        4px !default;
107 | $border-radius-large:       6px !default;
108 | $border-radius-small:       3px !default;
109 | 
110 | //** Global color for active items (e.g., navs or dropdowns).
111 | $component-active-color:    #fff !default;
112 | //** Global background color for active items (e.g., navs or dropdowns).
113 | $component-active-bg:       $brand-primary !default;
114 | 
115 | //** Width of the `border` for generating carets that indicator dropdowns.
116 | $caret-width-base:          4px !default;
117 | //** Carets increase slightly in size for larger components.
118 | $caret-width-large:         5px !default;
119 | 
120 | 
121 | //== Tables
122 | //
123 | //## Customizes the `.table` component with basic values, each used across all table variations.
124 | 
125 | //** Padding for ``s and ``s.
126 | $table-cell-padding:            8px !default;
127 | //** Padding for cells in `.table-condensed`.
128 | $table-condensed-cell-padding:  5px !default;
129 | 
130 | //** Default background color used for all tables.
131 | $table-bg:                      darken($gray-darker, 4%) !default;
132 | //** Background color used for `.table-striped`.
133 | $table-bg-accent:               darken($table-bg, 6%) !default;
134 | //** Background color used for `.table-hover`.
135 | $table-bg-hover:                $gray-dark !default;
136 | $table-bg-active:               $table-bg-hover !default;
137 | 
138 | //** Border color for table and cell borders.
139 | $table-border-color:            $gray-dark !default;
140 | 
141 | 
142 | //== Buttons
143 | //
144 | //## For each of Bootstrap's buttons, define text, background and border color.
145 | 
146 | $btn-font-weight:                normal !default;
147 | 
148 | $btn-default-color:              #fff !default;
149 | $btn-default-bg:                 lighten($gray-dark, 10%) !default;
150 | $btn-default-border:             $btn-default-bg !default;
151 | 
152 | $btn-primary-color:              $btn-default-color !default;
153 | $btn-primary-bg:                 $brand-primary !default;
154 | $btn-primary-border:             $btn-primary-bg !default;
155 | 
156 | $btn-success-color:              $btn-default-color !default;
157 | $btn-success-bg:                 $brand-success !default;
158 | $btn-success-border:             $btn-success-bg !default;
159 | 
160 | $btn-info-color:                 $btn-default-color !default;
161 | $btn-info-bg:                    $brand-info !default;
162 | $btn-info-border:                $btn-info-bg !default;
163 | 
164 | $btn-warning-color:              $btn-default-color !default;
165 | $btn-warning-bg:                 $brand-warning !default;
166 | $btn-warning-border:             $btn-warning-bg !default;
167 | 
168 | $btn-danger-color:               $btn-default-color !default;
169 | $btn-danger-bg:                  $brand-danger !default;
170 | $btn-danger-border:              $btn-danger-bg !default;
171 | 
172 | $btn-link-disabled-color:        $gray-light !default;
173 | 
174 | // Allows for customizing button radius independently from global border radius
175 | $btn-border-radius-base:         $border-radius-base !default;
176 | $btn-border-radius-large:        $border-radius-large !default;
177 | $btn-border-radius-small:        $border-radius-small !default;
178 | 
179 | 
180 | //== Forms
181 | //
182 | //##
183 | 
184 | //** `` background color
185 | $input-bg:                       #fff !default;
186 | //** `` background color
187 | $input-bg-disabled:              $gray-lighter !default;
188 | 
189 | //** Text color for ``s
190 | $input-color:                    $text-color !default;
191 | //** `` border color
192 | $input-border:                   $gray-dark !default;
193 | 
194 | // TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
195 | //** Default `.form-control` border radius
196 | // This has no effect on ``s in CSS.
197 | $input-border-radius:            $border-radius-base !default;
198 | //** Large `.form-control` border radius
199 | $input-border-radius-large:      $border-radius-large !default;
200 | //** Small `.form-control` border radius
201 | $input-border-radius-small:      $border-radius-small !default;
202 | 
203 | //** Border color for inputs on focus
204 | $input-border-focus:             #66afe9 !default;
205 | 
206 | //** Placeholder text color
207 | $input-color-placeholder:        $gray-light !default;
208 | 
209 | //** Default `.form-control` height
210 | $input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
211 | //** Large `.form-control` height
212 | $input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
213 | //** Small `.form-control` height
214 | $input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
215 | 
216 | //** `.form-group` margin
217 | $form-group-margin-bottom:       15px !default;
218 | 
219 | $legend-color:                   $text-color !default;
220 | $legend-border-color:            $gray-dark !default;
221 | 
222 | //** Background color for textual input addons
223 | $input-group-addon-bg:           $gray-lighter !default;
224 | //** Border color for textual input addons
225 | $input-group-addon-border-color: $input-border !default;
226 | 
227 | //** Disabled cursor for form controls and buttons.
228 | $cursor-disabled:                not-allowed !default;
229 | 
230 | 
231 | //== Dropdowns
232 | //
233 | //## Dropdown menu container and contents.
234 | 
235 | //** Background for the dropdown menu.
236 | $dropdown-bg:                    $gray-darker !default;
237 | //** Dropdown menu `border-color`.
238 | $dropdown-border:                rgba(255,255,255,0.1) !default;
239 | //** Dropdown menu `border-color` **for IE8**.
240 | $dropdown-fallback-border:       #444 !default;
241 | //** Divider color for between dropdown items.
242 | $dropdown-divider-bg:            rgba(255,255,255,0.1) !default;
243 | 
244 | //** Dropdown link text color.
245 | $dropdown-link-color:            #fff !default;
246 | //** Hover color for dropdown links.
247 | $dropdown-link-hover-color:      #fff !default;
248 | //** Hover background for dropdown links.
249 | $dropdown-link-hover-bg:         $component-active-bg !default;
250 | 
251 | //** Active dropdown menu item text color.
252 | $dropdown-link-active-color:     #fff !default;
253 | //** Active dropdown menu item background color.
254 | $dropdown-link-active-bg:        $component-active-bg !default;
255 | 
256 | //** Disabled dropdown menu item background color.
257 | $dropdown-link-disabled-color:   $gray-light !default;
258 | 
259 | //** Text color for headers within dropdown menus.
260 | $dropdown-header-color:          $gray-light !default;
261 | 
262 | //** Deprecated `$dropdown-caret-color` as of v3.1.0
263 | $dropdown-caret-color:           #000 !default;
264 | 
265 | 
266 | //-- Z-index master list
267 | //
268 | // Warning: Avoid customizing these values. They're used for a bird's eye view
269 | // of components dependent on the z-axis and are designed to all work together.
270 | //
271 | // Note: These variables are not generated into the Customizer.
272 | 
273 | $zindex-navbar:            1000 !default;
274 | $zindex-dropdown:          1000 !default;
275 | $zindex-popover:           1060 !default;
276 | $zindex-tooltip:           1070 !default;
277 | $zindex-navbar-fixed:      1030 !default;
278 | $zindex-modal-background:  1040 !default;
279 | $zindex-modal:             1050 !default;
280 | 
281 | 
282 | //== Media queries breakpoints
283 | //
284 | //## Define the breakpoints at which your layout will change, adapting to different screen sizes.
285 | 
286 | // Extra small screen / phone
287 | //** Deprecated `$screen-xs` as of v3.0.1
288 | $screen-xs:                  480px !default;
289 | //** Deprecated `$screen-xs-min` as of v3.2.0
290 | $screen-xs-min:              $screen-xs !default;
291 | //** Deprecated `$screen-phone` as of v3.0.1
292 | $screen-phone:               $screen-xs-min !default;
293 | 
294 | // Small screen / tablet
295 | //** Deprecated `$screen-sm` as of v3.0.1
296 | $screen-sm:                  768px !default;
297 | $screen-sm-min:              $screen-sm !default;
298 | //** Deprecated `$screen-tablet` as of v3.0.1
299 | $screen-tablet:              $screen-sm-min !default;
300 | 
301 | // Medium screen / desktop
302 | //** Deprecated `$screen-md` as of v3.0.1
303 | $screen-md:                  992px !default;
304 | $screen-md-min:              $screen-md !default;
305 | //** Deprecated `$screen-desktop` as of v3.0.1
306 | $screen-desktop:             $screen-md-min !default;
307 | 
308 | // Large screen / wide desktop
309 | //** Deprecated `$screen-lg` as of v3.0.1
310 | $screen-lg:                  1200px !default;
311 | $screen-lg-min:              $screen-lg !default;
312 | //** Deprecated `$screen-lg-desktop` as of v3.0.1
313 | $screen-lg-desktop:          $screen-lg-min !default;
314 | 
315 | // So media queries don't overlap when required, provide a maximum
316 | $screen-xs-max:              ($screen-sm-min - 1) !default;
317 | $screen-sm-max:              ($screen-md-min - 1) !default;
318 | $screen-md-max:              ($screen-lg-min - 1) !default;
319 | 
320 | 
321 | //== Grid system
322 | //
323 | //## Define your custom responsive grid.
324 | 
325 | //** Number of columns in the grid.
326 | $grid-columns:              12 !default;
327 | //** Padding between columns. Gets divided in half for the left and right.
328 | $grid-gutter-width:         30px !default;
329 | // Navbar collapse
330 | //** Point at which the navbar becomes uncollapsed.
331 | $grid-float-breakpoint:     $screen-sm-min !default;
332 | //** Point at which the navbar begins collapsing.
333 | $grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
334 | 
335 | 
336 | //== Container sizes
337 | //
338 | //## Define the maximum width of `.container` for different screen sizes.
339 | 
340 | // Small screen / tablet
341 | $container-tablet:             (720px + $grid-gutter-width) !default;
342 | //** For `$screen-sm-min` and up.
343 | $container-sm:                 $container-tablet !default;
344 | 
345 | // Medium screen / desktop
346 | $container-desktop:            (940px + $grid-gutter-width) !default;
347 | //** For `$screen-md-min` and up.
348 | $container-md:                 $container-desktop !default;
349 | 
350 | // Large screen / wide desktop
351 | $container-large-desktop:      (1140px + $grid-gutter-width) !default;
352 | //** For `$screen-lg-min` and up.
353 | $container-lg:                 $container-large-desktop !default;
354 | 
355 | 
356 | //== Navbar
357 | //
358 | //##
359 | 
360 | // Basics of a navbar
361 | $navbar-height:                    50px !default;
362 | $navbar-margin-bottom:             $line-height-computed !default;
363 | $navbar-border-radius:             $border-radius-base !default;
364 | $navbar-padding-horizontal:        floor(($grid-gutter-width / 2)) !default;
365 | $navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2) !default;
366 | $navbar-collapse-max-height:       340px !default;
367 | 
368 | $navbar-default-color:             $text-color !default;
369 | $navbar-default-bg:                $body-bg !default;
370 | $navbar-default-border:            $gray-dark !default;
371 | 
372 | // Navbar links
373 | $navbar-default-link-color:                $text-color !default;
374 | $navbar-default-link-hover-color:          #fff !default;
375 | $navbar-default-link-hover-bg:             transparent !default;
376 | $navbar-default-link-active-color:         #fff !default;
377 | $navbar-default-link-active-bg:            transparent !default;
378 | $navbar-default-link-disabled-color:       $gray-light !default;
379 | $navbar-default-link-disabled-bg:          transparent !default;
380 | 
381 | // Navbar brand label
382 | $navbar-default-brand-color:               #fff !default;
383 | $navbar-default-brand-hover-color:         #fff !default;
384 | $navbar-default-brand-hover-bg:            transparent !default;
385 | 
386 | // Navbar toggle
387 | $navbar-default-toggle-hover-bg:           $gray-dark !default;
388 | $navbar-default-toggle-icon-bar-bg:        #ccc !default;
389 | $navbar-default-toggle-border-color:       $gray-dark !default;
390 | 
391 | 
392 | //=== Inverted navbar
393 | // Reset inverted navbar basics
394 | $navbar-inverse-color:                      $gray-light !default;
395 | $navbar-inverse-bg:                         $gray-darker !default;
396 | $navbar-inverse-border:                     darken($navbar-inverse-bg, 10%) !default;
397 | 
398 | // Inverted navbar links
399 | $navbar-inverse-link-color:                 $gray-light !default;
400 | $navbar-inverse-link-hover-color:           #fff !default;
401 | $navbar-inverse-link-hover-bg:              transparent !default;
402 | $navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color !default;
403 | $navbar-inverse-link-active-bg:             transparent !default;
404 | $navbar-inverse-link-disabled-color:        #aaa !default;
405 | $navbar-inverse-link-disabled-bg:           transparent !default;
406 | 
407 | // Inverted navbar brand label
408 | $navbar-inverse-brand-color:                #fff !default;
409 | $navbar-inverse-brand-hover-color:          #fff !default;
410 | $navbar-inverse-brand-hover-bg:             transparent !default;
411 | 
412 | // Inverted navbar toggle
413 | $navbar-inverse-toggle-hover-bg:            #333 !default;
414 | $navbar-inverse-toggle-icon-bar-bg:         #fff !default;
415 | $navbar-inverse-toggle-border-color:        #333 !default;
416 | 
417 | 
418 | //== Navs
419 | //
420 | //##
421 | 
422 | //=== Shared nav styles
423 | $nav-link-padding:                          10px 15px !default;
424 | $nav-link-hover-bg:                         $gray-darker !default;
425 | 
426 | $nav-disabled-link-color:                   $gray-light !default;
427 | $nav-disabled-link-hover-color:             $gray-light !default;
428 | 
429 | //== Tabs
430 | $nav-tabs-border-color:                     $gray-dark !default;
431 | 
432 | $nav-tabs-link-hover-border-color:          transparent !default;
433 | 
434 | $nav-tabs-active-link-hover-bg:             $brand-primary !default;
435 | $nav-tabs-active-link-hover-color:          #fff !default;
436 | $nav-tabs-active-link-hover-border-color:   $gray-dark !default;
437 | 
438 | $nav-tabs-justified-link-border-color:            #ddd !default;
439 | $nav-tabs-justified-active-link-border-color:     $body-bg !default;
440 | 
441 | //== Pills
442 | $nav-pills-border-radius:                   $border-radius-base !default;
443 | $nav-pills-active-link-hover-bg:            $component-active-bg !default;
444 | $nav-pills-active-link-hover-color:         $component-active-color !default;
445 | 
446 | 
447 | //== Pagination
448 | //
449 | //##
450 | 
451 | $pagination-color:                     #fff !default;
452 | $pagination-bg:                        $gray-darker !default;
453 | $pagination-border:                    $gray-dark !default;
454 | 
455 | $pagination-hover-color:               #fff !default;
456 | $pagination-hover-bg:                  $component-active-bg !default;
457 | $pagination-hover-border:              transparent !default;
458 | 
459 | $pagination-active-color:              #fff !default;
460 | $pagination-active-bg:                 $brand-primary !default;
461 | $pagination-active-border:             transparent !default;
462 | 
463 | $pagination-disabled-color:            $gray-light !default;
464 | $pagination-disabled-bg:               $gray-darker !default;
465 | $pagination-disabled-border:           $gray-dark !default;
466 | 
467 | 
468 | //== Pager
469 | //
470 | //##
471 | 
472 | $pager-bg:                             $pagination-bg !default;
473 | $pager-border:                         $pagination-border !default;
474 | $pager-border-radius:                  15px !default;
475 | 
476 | $pager-hover-bg:                       $pagination-hover-bg !default;
477 | 
478 | $pager-active-bg:                      $pagination-active-bg !default;
479 | $pager-active-color:                   $pagination-active-color !default;
480 | 
481 | $pager-disabled-color:                 $gray-light !default;
482 | 
483 | 
484 | //== Jumbotron
485 | //
486 | //##
487 | 
488 | $jumbotron-padding:              30px !default;
489 | $jumbotron-color:                inherit !default;
490 | $jumbotron-bg:                   darken($gray-darker, 5%) !default;
491 | $jumbotron-heading-color:        inherit !default;
492 | $jumbotron-font-size:            ceil(($font-size-base * 1.5)) !default;
493 | $jumbotron-heading-font-size:    ceil(($font-size-base * 4.5)) !default;
494 | 
495 | 
496 | //== Form states and alerts
497 | //
498 | //## Define colors for form feedback states and, by default, alerts.
499 | 
500 | $state-success-text:             #fff !default;
501 | $state-success-bg:               $brand-success !default;
502 | $state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%) !default;
503 | 
504 | $state-info-text:                #fff !default;
505 | $state-info-bg:                  $brand-info !default;
506 | $state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%) !default;
507 | 
508 | $state-warning-text:             #fff !default;
509 | $state-warning-bg:               $brand-warning !default;
510 | $state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 3%) !default;
511 | 
512 | $state-danger-text:              #fff !default;
513 | $state-danger-bg:                $brand-danger !default;
514 | $state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 3%) !default;
515 | 
516 | 
517 | //== Tooltips
518 | //
519 | //##
520 | 
521 | //** Tooltip max width
522 | $tooltip-max-width:           200px !default;
523 | //** Tooltip text color
524 | $tooltip-color:               #fff !default;
525 | //** Tooltip background color
526 | $tooltip-bg:                  #000 !default;
527 | $tooltip-opacity:             .9 !default;
528 | 
529 | //** Tooltip arrow width
530 | $tooltip-arrow-width:         5px !default;
531 | //** Tooltip arrow color
532 | $tooltip-arrow-color:         $tooltip-bg !default;
533 | 
534 | 
535 | //== Popovers
536 | //
537 | //##
538 | 
539 | //** Popover body background color
540 | $popover-bg:                          lighten($body-bg, 10%) !default;
541 | //** Popover maximum width
542 | $popover-max-width:                   276px !default;
543 | //** Popover border color
544 | $popover-border-color:                rgba(0,0,0,.2) !default;
545 | //** Popover fallback border color
546 | $popover-fallback-border-color:       #999 !default;
547 | 
548 | //** Popover title background color
549 | $popover-title-bg:                    darken($popover-bg, 3%) !default;
550 | 
551 | //** Popover arrow width
552 | $popover-arrow-width:                 10px !default;
553 | //** Popover arrow color
554 | $popover-arrow-color:                 $popover-bg !default;
555 | 
556 | //** Popover outer arrow width
557 | $popover-arrow-outer-width:           ($popover-arrow-width + 1) !default;
558 | //** Popover outer arrow color
559 | $popover-arrow-outer-color:           fadein($popover-border-color, 5%) !default;
560 | //** Popover outer arrow fallback color
561 | $popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%) !default;
562 | 
563 | 
564 | //== Labels
565 | //
566 | //##
567 | 
568 | //** Default label background color
569 | $label-default-bg:            $btn-default-bg !default;
570 | //** Primary label background color
571 | $label-primary-bg:            $brand-primary !default;
572 | //** Success label background color
573 | $label-success-bg:            $brand-success !default;
574 | //** Info label background color
575 | $label-info-bg:               $brand-info !default;
576 | //** Warning label background color
577 | $label-warning-bg:            $brand-warning !default;
578 | //** Danger label background color
579 | $label-danger-bg:             $brand-danger !default;
580 | 
581 | //** Default label text color
582 | $label-color:                 #fff !default;
583 | //** Default text color of a linked label
584 | $label-link-hover-color:      #fff !default;
585 | 
586 | 
587 | //== Modals
588 | //
589 | //##
590 | 
591 | //** Padding applied to the modal body
592 | $modal-inner-padding:         20px !default;
593 | 
594 | //** Padding applied to the modal title
595 | $modal-title-padding:         15px !default;
596 | //** Modal title line-height
597 | $modal-title-line-height:     $line-height-base !default;
598 | 
599 | //** Background color of modal content area
600 | $modal-content-bg:                             lighten($body-bg, 10%) !default;
601 | //** Modal content border color
602 | $modal-content-border-color:                   rgba(0,0,0,.2) !default;
603 | //** Modal content border color **for IE8**
604 | $modal-content-fallback-border-color:          #999 !default;
605 | 
606 | //** Modal backdrop background color
607 | $modal-backdrop-bg:           #000 !default;
608 | //** Modal backdrop opacity
609 | $modal-backdrop-opacity:      .5 !default;
610 | //** Modal header border color
611 | $modal-header-border-color:   $gray-dark !default;
612 | //** Modal footer border color
613 | $modal-footer-border-color:   $modal-header-border-color !default;
614 | 
615 | $modal-lg:                    900px !default;
616 | $modal-md:                    600px !default;
617 | $modal-sm:                    300px !default;
618 | 
619 | 
620 | //== Alerts
621 | //
622 | //## Define alert colors, border radius, and padding.
623 | 
624 | $alert-padding:               15px !default;
625 | $alert-border-radius:         $border-radius-base !default;
626 | $alert-link-font-weight:      bold !default;
627 | 
628 | $alert-success-bg:            $state-success-bg !default;
629 | $alert-success-text:          $state-success-text !default;
630 | $alert-success-border:        $state-success-border !default;
631 | 
632 | $alert-info-bg:               $state-info-bg !default;
633 | $alert-info-text:             $state-info-text !default;
634 | $alert-info-border:           $state-info-border !default;
635 | 
636 | $alert-warning-bg:            $state-warning-bg !default;
637 | $alert-warning-text:          $state-warning-text !default;
638 | $alert-warning-border:        $state-warning-border !default;
639 | 
640 | $alert-danger-bg:             $state-danger-bg !default;
641 | $alert-danger-text:           $state-danger-text !default;
642 | $alert-danger-border:         $state-danger-border !default;
643 | 
644 | 
645 | //== Progress bars
646 | //
647 | //##
648 | 
649 | //** Background color of the whole progress component
650 | $progress-bg:                 $gray-darker !default;
651 | //** Progress bar text color
652 | $progress-bar-color:          #fff !default;
653 | //** Variable for setting rounded corners on progress bar.
654 | $progress-border-radius:      $border-radius-base !default;
655 | 
656 | //** Default progress bar color
657 | $progress-bar-bg:             $brand-primary !default;
658 | //** Success progress bar color
659 | $progress-bar-success-bg:     $brand-success !default;
660 | //** Warning progress bar color
661 | $progress-bar-warning-bg:     $brand-warning !default;
662 | //** Danger progress bar color
663 | $progress-bar-danger-bg:      $brand-danger !default;
664 | //** Info progress bar color
665 | $progress-bar-info-bg:        $brand-info !default;
666 | 
667 | 
668 | //== List group
669 | //
670 | //##
671 | 
672 | //** Background color on `.list-group-item`
673 | $list-group-bg:                 $gray-darker !default;
674 | //** `.list-group-item` border color
675 | $list-group-border:             $gray-dark !default;
676 | //** List group border radius
677 | $list-group-border-radius:      $border-radius-base !default;
678 | 
679 | //** Background color of single list items on hover
680 | $list-group-hover-bg:           lighten($list-group-bg, 15%) !default;
681 | //** Text color of active list items
682 | $list-group-active-color:       $component-active-color !default;
683 | //** Background color of active list items
684 | $list-group-active-bg:          $component-active-bg !default;
685 | //** Border color of active list elements
686 | $list-group-active-border:      $list-group-active-bg !default;
687 | //** Text color for content within active list items
688 | $list-group-active-text-color:  lighten($list-group-active-bg, 40%) !default;
689 | 
690 | //** Text color of disabled list items
691 | $list-group-disabled-color:      $gray-light !default;
692 | //** Background color of disabled list items
693 | $list-group-disabled-bg:         $gray-lighter !default;
694 | //** Text color for content within disabled list items
695 | $list-group-disabled-text-color: $list-group-disabled-color !default;
696 | 
697 | $list-group-link-color:         $text-color !default;
698 | $list-group-link-hover-color:   $list-group-link-color !default;
699 | $list-group-link-heading-color: #fff !default;
700 | 
701 | 
702 | //== Panels
703 | //
704 | //##
705 | 
706 | $panel-bg:                    $gray-darker !default;
707 | $panel-body-padding:          15px !default;
708 | $panel-heading-padding:       10px 15px !default;
709 | $panel-footer-padding:        $panel-heading-padding !default;
710 | $panel-border-radius:         $border-radius-base !default;
711 | 
712 | //** Border color for elements within panels
713 | $panel-inner-border:          $gray-dark !default;
714 | $panel-footer-bg:             lighten($gray-darker, 10%) !default;
715 | 
716 | $panel-default-text:          $text-color !default;
717 | $panel-default-border:        $panel-inner-border !default;
718 | $panel-default-heading-bg:    $panel-footer-bg !default;
719 | 
720 | $panel-primary-text:          #fff !default;
721 | $panel-primary-border:        $brand-primary !default;
722 | $panel-primary-heading-bg:    $brand-primary !default;
723 | 
724 | $panel-success-text:          $state-success-text !default;
725 | $panel-success-border:        $state-success-border !default;
726 | $panel-success-heading-bg:    $state-success-bg !default;
727 | 
728 | $panel-info-text:             $state-info-text !default;
729 | $panel-info-border:           $state-info-border !default;
730 | $panel-info-heading-bg:       $state-info-bg !default;
731 | 
732 | $panel-warning-text:          $state-warning-text !default;
733 | $panel-warning-border:        $state-warning-border !default;
734 | $panel-warning-heading-bg:    $state-warning-bg !default;
735 | 
736 | $panel-danger-text:           $state-danger-text !default;
737 | $panel-danger-border:         $state-danger-border !default;
738 | $panel-danger-heading-bg:     $state-danger-bg !default;
739 | 
740 | 
741 | //== Thumbnails
742 | //
743 | //##
744 | 
745 | //** Padding around the thumbnail image
746 | $thumbnail-padding:           4px !default;
747 | //** Thumbnail background color
748 | $thumbnail-bg:                $gray-dark !default;
749 | //** Thumbnail border color
750 | $thumbnail-border:            $gray-dark !default;
751 | //** Thumbnail border radius
752 | $thumbnail-border-radius:     $border-radius-base !default;
753 | 
754 | //** Custom text color for thumbnail captions
755 | $thumbnail-caption-color:     $text-color !default;
756 | //** Padding around the thumbnail caption
757 | $thumbnail-caption-padding:   9px !default;
758 | 
759 | 
760 | //== Wells
761 | //
762 | //##
763 | 
764 | $well-bg:                     darken($gray-darker, 5%) !default;
765 | $well-border:                 darken($well-bg, 7%) !default;
766 | 
767 | 
768 | //== Badges
769 | //
770 | //##
771 | 
772 | $badge-color:                 #fff !default;
773 | //** Linked badge text color on hover
774 | $badge-link-hover-color:      #fff !default;
775 | $badge-bg:                    $brand-primary !default;
776 | 
777 | //** Badge text color in active nav link
778 | $badge-active-color:          $brand-primary !default;
779 | //** Badge background color in active nav link
780 | $badge-active-bg:             #fff !default;
781 | 
782 | $badge-font-weight:           bold !default;
783 | $badge-line-height:           1 !default;
784 | $badge-border-radius:         10px !default;
785 | 
786 | 
787 | //== Breadcrumbs
788 | //
789 | //##
790 | 
791 | $breadcrumb-padding-vertical:   8px !default;
792 | $breadcrumb-padding-horizontal: 15px !default;
793 | //** Breadcrumb background color
794 | $breadcrumb-bg:                 $gray-darker !default;
795 | //** Breadcrumb text color
796 | $breadcrumb-color:              #fff !default;
797 | //** Text color of current page in the breadcrumb
798 | $breadcrumb-active-color:       $text-color !default;
799 | //** Textual separator for between breadcrumb elements
800 | $breadcrumb-separator:          "/" !default;
801 | 
802 | 
803 | //== Carousel
804 | //
805 | //##
806 | 
807 | $carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6) !default;
808 | 
809 | $carousel-control-color:                      #fff !default;
810 | $carousel-control-width:                      15% !default;
811 | $carousel-control-opacity:                    .5 !default;
812 | $carousel-control-font-size:                  20px !default;
813 | 
814 | $carousel-indicator-active-bg:                #fff !default;
815 | $carousel-indicator-border-color:             #fff !default;
816 | 
817 | $carousel-caption-color:                      #fff !default;
818 | 
819 | 
820 | //== Close
821 | //
822 | //##
823 | 
824 | $close-font-weight:           bold !default;
825 | $close-color:                 #000 !default;
826 | $close-text-shadow:           0 1px 0 #fff !default;
827 | 
828 | 
829 | //== Code
830 | //
831 | //##
832 | 
833 | $code-color:                  #c7254e !default;
834 | $code-bg:                     #f9f2f4 !default;
835 | 
836 | $kbd-color:                   #fff !default;
837 | $kbd-bg:                      #333 !default;
838 | 
839 | $pre-bg:                      #f5f5f5 !default;
840 | $pre-color:                   $gray-dark !default;
841 | $pre-border-color:            #ccc !default;
842 | $pre-scrollable-max-height:   340px !default;
843 | 
844 | 
845 | //== Type
846 | //
847 | //##
848 | 
849 | //** Horizontal offset for forms and lists.
850 | $component-offset-horizontal: 180px !default;
851 | //** Text muted color
852 | $text-muted:                  $gray-light !default;
853 | //** Abbreviations and acronyms border color
854 | $abbr-border-color:           $gray-light !default;
855 | //** Headings small color
856 | $headings-small-color:        $gray-light !default;
857 | //** Blockquote small color
858 | $blockquote-small-color:      $gray !default;
859 | //** Blockquote font size
860 | $blockquote-font-size:        ($font-size-base * 1.25) !default;
861 | //** Blockquote border color
862 | $blockquote-border-color:     $gray-dark !default;
863 | //** Page header border color
864 | $page-header-border-color:    $gray-dark !default;
865 | //** Width of horizontal description list titles
866 | $dl-horizontal-offset:        $component-offset-horizontal !default;
867 | //** Point at which .dl-horizontal becomes horizontal
868 | $dl-horizontal-breakpoint:    $grid-float-breakpoint !default;
869 | //** Horizontal line color.
870 | $hr-border:                   $gray-dark !default;
871 | 


--------------------------------------------------------------------------------
/angular/src/app/app.js:
--------------------------------------------------------------------------------
 1 | (function() {
 2 |   'use strict';
 3 | 
 4 |   angular
 5 |     .module('myIot', ['ngResource', 'ui.router', 'mgcrea.ngStrap', 'chart.js'])
 6 |     .constant('ApiUrl', "http://localhost:3000/api/")
 7 |     .config(config)
 8 |     .run(runBlock);
 9 | 
10 |   /** @ngInject */
11 |   function config(ChartJsProvider, $logProvider) {
12 |     // Configure all charts
13 |     ChartJsProvider.setOptions({
14 |       colours: ['#41A5F4', '#DCDCDC', '#F7464A', '#46BFBD', '#FDB45C', '#949FB1', '#4D5360'],
15 |       animationSteps: 15,
16 |       pointDot: false,
17 |       showTooltips: false,
18 |       scaleGridLineColor: "#292929",
19 |       scaleGridLineWidth: 1,
20 |       scaleShowVerticalLines: false,
21 |       responsive: true
22 |     });
23 |     // Configure all doughnut charts
24 |     ChartJsProvider.setOptions('Doughnut', {
25 |       animateScale: true
26 |     });
27 | 
28 |     // Enable log
29 |     $logProvider.debugEnabled(true);
30 | 
31 |   }
32 | 
33 | 
34 |   /** @ngInject */
35 |   function runBlock($log) {
36 | 
37 |     $log.debug('runBlock end');
38 |   }
39 | 
40 | 
41 | 
42 | })();
43 | 


--------------------------------------------------------------------------------
/angular/src/app/app.resource.js:
--------------------------------------------------------------------------------
 1 | (function() {
 2 |   'use strict';
 3 | 
 4 |   angular
 5 |     .module('myIot')
 6 |     .factory('resource',resource);
 7 | 
 8 |   /** @ngInject */
 9 |   function resource($resource,ApiUrl) {
10 |     return {
11 |       device:$resource(ApiUrl+'devices'),
12 |       sensorValue:{
13 |         history:$resource(ApiUrl+'sensor/:sensor_id/value/history', { sensor_id: '@sensor_id' }),
14 |         realtime:$resource(ApiUrl+'sensor/:sensor_id/value/realtime', { sensor_id: '@sensor_id' })
15 |       }
16 |     };
17 |   }
18 | 
19 | })();
20 | 


--------------------------------------------------------------------------------
/angular/src/app/app.route.js:
--------------------------------------------------------------------------------
 1 | (function() {
 2 |   'use strict';
 3 | 
 4 |   angular
 5 |     .module('myIot')
 6 |     .config(routerConfig);
 7 | 
 8 |   /** @ngInject */
 9 |   function routerConfig($stateProvider, $urlRouterProvider) {
10 |     // For any unmatched url, redirect to /
11 |     $urlRouterProvider.otherwise("/devices");
12 |     $urlRouterProvider.when("", "/");
13 | 
14 |     $stateProvider
15 |       .state('myDevice', {
16 |         url: '/devices',
17 |         templateUrl: 'app/my-device/my-device.html',
18 |         controller: 'MyDeviceController',
19 |         controllerAs: 'myDevice'
20 |       }).state('dashboard', {
21 |         url: '/dashboard/',
22 |         templateUrl: 'app/dashboard/dashboard.html',
23 |         controller: 'DashboardController',
24 |         controllerAs: 'dashboard',
25 |         params: {'device':null,'sensor': null}
26 |       });
27 |   }
28 | 
29 | })();
30 | 


--------------------------------------------------------------------------------
/angular/src/app/components/navbar/navbar.html:
--------------------------------------------------------------------------------
 1 | 
21 | 


--------------------------------------------------------------------------------
/angular/src/app/dashboard/dashboard.ctrl.js:
--------------------------------------------------------------------------------
  1 | (function() {
  2 |   'use strict';
  3 | 
  4 |   angular
  5 |     .module('myIot')
  6 |     .controller('DashboardController', DashboardController);
  7 | 
  8 |   /** @ngInject */
  9 |   function DashboardController($scope, $stateParams, $state, resource, $timeout, $log, $interval) {
 10 |     $log.debug('DashboardController init');
 11 |     var vm = this;
 12 | 
 13 |     vm.device = $stateParams.device;
 14 |     vm.sensor = $stateParams.sensor;
 15 |     vm.showHistory = showHistory;
 16 |     vm.realTimeChart = {
 17 |       labels: [],
 18 |       data: [
 19 |         []
 20 |       ],
 21 |       option: {
 22 |         animation: false,
 23 |         datasetFill: true,
 24 |         scaleOverride: true, //是否用硬编码重写y轴网格线
 25 |         scaleSteps: 4, //y轴刻度的个数
 26 |         scaleStepWidth: 10, //y轴每个刻度的宽度
 27 |         scaleStartValue: 0, //y轴的起始值
 28 |         responsive: true,
 29 |         scaleLabel: "<%=value%> ℃"
 30 |       }
 31 |     };
 32 |     vm.chart = {
 33 |       series: ['22'],
 34 |       option: {
 35 |         pointDot: true,
 36 |         scaleOverride: true, //是否用硬编码重写y轴网格线
 37 |         scaleSteps: 6, //y轴刻度的个数
 38 |         scaleStepWidth: 10, //y轴每个刻度的宽度
 39 |         scaleStartValue: -15, //y轴的起始值
 40 |         responsive: true,
 41 |         scaleLabel: "<%=value%> ℃",
 42 |         tooltipTemplate: "<%= value %>℃"
 43 |       }
 44 |     };
 45 | 
 46 |     vm.histryChart = {
 47 |       labels: [],
 48 |       data: []
 49 |     };
 50 | 
 51 |     activate();
 52 |     
 53 |     function activate() {
 54 |       vm.historyDay = new Date(2016, 5, 25).getTime();
 55 |       vm.showHistory();
 56 |       var latsTimestamp = 0;
 57 |       var realTimer = $interval(function() {
 58 |         resource.sensorValue.realtime.get({
 59 |           sensor_id: $stateParams.sensor.sensor_id,
 60 |           latsTimestamp: latsTimestamp
 61 |         }, function(data) {
 62 |           if (data.data.length) {
 63 |             latsTimestamp = data.latsTimestamp;
 64 |             angular.forEach(data.data, function(data) {
 65 |               vm.realTimeChart.labels.push('');
 66 |               vm.realTimeChart.data[0].push(data);
 67 |             });
 68 | 
 69 |             if (vm.realTimeChart.labels.length > 60) {
 70 |               vm.realTimeChart.labels.splice(0, vm.realTimeChart.labels.length - 60);
 71 |               vm.realTimeChart.data[0].splice(0, vm.realTimeChart.data[0].length - 60);
 72 |             }
 73 |           }
 74 |         });
 75 |       }, 500);
 76 | 
 77 |       $scope.$on('$stateChangeStart', function() {
 78 |         $interval.cancel(realTimer); //页面切换后停止获取实时数据
 79 |       });
 80 | 
 81 |     }
 82 | 
 83 |     function showHistory() {
 84 |       resource.sensorValue.history.query({
 85 |         sensor_id: $stateParams.sensor.sensor_id,
 86 |         start: vm.historyDay + 1,
 87 |         end: vm.historyDay + 86400000
 88 |       }, function(data) {
 89 |         vm.histryChart.labels = [];
 90 |         vm.histryChart.data[0] = [];
 91 |         angular.forEach(data, function(obj, index) {
 92 |           vm.histryChart.labels.push(index + '时');
 93 |           vm.histryChart.data[0].push(obj.value.toFixed(1));
 94 |         });
 95 |       });
 96 |     }
 97 | 
 98 |   }
 99 | })();
100 | 


--------------------------------------------------------------------------------
/angular/src/app/dashboard/dashboard.html:
--------------------------------------------------------------------------------
 1 | 
2 | 3 |
4 |
5 |
6 |

7 |  {{dashboard.device.name}} 8 |

9 |
10 | 11 |
12 |

13 | 备注:{{dashboard.device.profile}}
14 | 15 |

16 |
17 | 18 | 设备类型:{{dashboard.sensor.sensor_type}}
19 | 设备 ID: {{dashboard.sensor.sensor_id}} 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 |
45 | 选择历史日期: 46 | 48 | 49 | 50 | 51 |
52 |
53 | 54 |
55 | 56 |
57 | -------------------------------------------------------------------------------- /angular/src/app/dashboard/dashboard.scss: -------------------------------------------------------------------------------- 1 | .dashboard{ 2 | .date-picker{ 3 | width: 200px; 4 | display: inline; 5 | margin-right: 60px; 6 | } 7 | .device-profile { 8 | padding: 10px 20px; 9 | font-size: 14px; 10 | border-left: 5px solid #888888; 11 | } 12 | .logo { 13 | display: block; 14 | margin: 0 auto; 15 | padding-top: 15px; 16 | padding-bottom: 20px; 17 | width: 83px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /angular/src/app/index.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * If you want to override some bootstrap variables, you have to change values here. 3 | * The list of variables are listed here bower_components/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss 4 | */ 5 | @import "../Cyborg"; 6 | 7 | $navbar-inverse-link-color: #5AADBB; 8 | $icon-font-path: "../../bower_components/bootstrap-sass/assets/fonts/bootstrap/"; 9 | 10 | $fa-font-path: "../../bower_components/font-awesome/fonts"; 11 | @import "../../bower_components/font-awesome/scss/font-awesome.scss"; 12 | /** 13 | * Do not remove the comments below. It's the markers used by wiredep to inject 14 | * sass dependencies when defined in the bower.json of your dependencies 15 | */ 16 | // bower:scss 17 | // endbower 18 | 19 | .browsehappy { 20 | margin: 0.2em 0; 21 | background: #ccc; 22 | color: #000; 23 | padding: 0.2em 0; 24 | } 25 | 26 | .thumbnail { 27 | height: 200px; 28 | 29 | img.pull-right { 30 | width: 50px; 31 | } 32 | } 33 | 34 | /** 35 | * Do not remove the comments below. It's the markers used by gulp-inject to inject 36 | * all your sass files automatically 37 | */ 38 | // injector 39 | // endinjector 40 | -------------------------------------------------------------------------------- /angular/src/app/my-device/my-device.ctrl.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | angular 5 | .module('myIot') 6 | .controller('MyDeviceController', MyDeviceController); 7 | 8 | /** @ngInject */ 9 | function MyDeviceController($state, resource, $timeout, $log) { 10 | 11 | $log.debug('MyDeviceController init'); 12 | var vm = this; 13 | 14 | vm.getTheme=getTheme; 15 | vm.goDashboard = goDashboard; 16 | 17 | activate(); 18 | 19 | function activate() { 20 | resource.device.query(function(data) { 21 | vm.devices = data; 22 | }); 23 | } 24 | 25 | function getTheme(index){ 26 | var themes=['primary','success','warning','danger','info']; 27 | return themes[index%5]; 28 | } 29 | 30 | function goDashboard(device,sensor) { 31 | $state.go('dashboard', { 32 | device:device, 33 | sensor: sensor 34 | }); 35 | } 36 | 37 | } 38 | })(); 39 | -------------------------------------------------------------------------------- /angular/src/app/my-device/my-device.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |  {{device.name}} 6 |
7 |
8 |
9 |

10 | 备注:{{device.profile}} 11 |
12 | 创建时间:{{device.create_at | date:'yyyy年MM月dd日'}} 13 |

14 |
15 |
16 | 17 |
18 | 设备类型:{{sensor.sensor_type}} 19 |
设备 ID: {{sensor.sensor_id}} 20 |
21 | 22 |
23 |
24 |
25 |
26 |
27 | -------------------------------------------------------------------------------- /angular/src/app/my-device/my-device.scss: -------------------------------------------------------------------------------- 1 | .my-device { 2 | margin-bottom: 60px; 3 | .device-name{ 4 | font-size: 20px; 5 | font-weight: bold; 6 | 7 | } 8 | .device-profile { 9 | padding: 10px 20px; 10 | font-size: 14px; 11 | border-left: 5px solid #888888; 12 | } 13 | .logo { 14 | display: block; 15 | margin: 0 auto; 16 | padding-top: 30px; 17 | padding-bottom: 40px; 18 | width: 140px; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /angular/src/assets/images/temperature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/angular/src/assets/images/temperature.png -------------------------------------------------------------------------------- /angular/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/angular/src/favicon.ico -------------------------------------------------------------------------------- /angular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | myIot 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 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 | -------------------------------------------------------------------------------- /doc/README.MD: -------------------------------------------------------------------------------- 1 | # 毕设相关文档 2 | 本目录下存放了毕设相关文档。包括论文的word格式以及PDF格式,答辩幻灯片的Keynote格式以及PDF格式,还有论文的草稿图(写论文照着这个图来的)。 3 | img 目录下放的是所有README.MD所引用的图片。 4 | 5 | ##### 草稿图 6 | ![Image of system page](论文草稿.png) 7 | -------------------------------------------------------------------------------- /doc/img/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/doc/img/dashboard.png -------------------------------------------------------------------------------- /doc/img/devices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/doc/img/devices.png -------------------------------------------------------------------------------- /doc/img/system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/doc/img/system.png -------------------------------------------------------------------------------- /doc/答辩Slide show.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/doc/答辩Slide show.key -------------------------------------------------------------------------------- /doc/答辩Slide show.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/doc/答辩Slide show.pdf -------------------------------------------------------------------------------- /doc/论文.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/doc/论文.docx -------------------------------------------------------------------------------- /doc/论文.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/doc/论文.pdf -------------------------------------------------------------------------------- /doc/论文草稿.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nieheyong/myIot/c60e4cf7b7eb51ff26d07e0a1e5d7b09a318ed97/doc/论文草稿.png -------------------------------------------------------------------------------- /hardware/.gitignore: -------------------------------------------------------------------------------- 1 | .tags 2 | out/ 3 | Sming/ 4 | -------------------------------------------------------------------------------- /hardware/Makefile: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | #### Please don't change this file. Use Makefile-user.mk instead #### 3 | ##################################################################### 4 | # Including user Makefile. 5 | # Should be used to set project-specific parameters 6 | include ./Makefile-user.mk 7 | 8 | # Important parameters check. 9 | # We need to make sure SMING_HOME and ESP_HOME variables are set. 10 | # You can use Makefile-user.mk in each project or use enviromental variables to set it globally. 11 | 12 | ifndef SMING_HOME 13 | $(error SMING_HOME is not set. Please configure it in Makefile-user.mk) 14 | endif 15 | ifndef ESP_HOME 16 | $(error ESP_HOME is not set. Please configure it in Makefile-user.mk) 17 | endif 18 | 19 | # Include main Sming Makefile 20 | ifeq ($(RBOOT_ENABLED), 1) 21 | include $(SMING_HOME)/Makefile-rboot.mk 22 | else 23 | include $(SMING_HOME)/Makefile-project.mk 24 | endif 25 | -------------------------------------------------------------------------------- /hardware/Makefile-user.mk: -------------------------------------------------------------------------------- 1 | ## Local build configuration 2 | ## Parameters configured here will override default and ENV values. 3 | ## Uncomment and change examples: 4 | 5 | ## Add your source directories here separated by space 6 | # MODULES = app 7 | # EXTRA_INCDIR = include 8 | 9 | ## ESP_HOME sets the path where ESP tools and SDK are located. 10 | ## Windows: 11 | # ESP_HOME = c:/Espressif 12 | 13 | ## MacOS / Linux: 14 | ESP_HOME = /opt/esp-open-sdk 15 | 16 | ## SMING_HOME sets the path where Sming framework is located. 17 | ## Windows: 18 | # SMING_HOME = c:/tools/sming/Sming 19 | 20 | ## MacOS / Linux 21 | SMING_HOME = /opt/Sming-REST/Sming 22 | 23 | ## COM port parameter is reqruied to flash firmware correctly. 24 | ## Windows: 25 | # COM_PORT = COM3 26 | 27 | ## MacOS / Linux: 28 | COM_PORT = /dev/tty.SLAB_USBtoUART 29 | 30 | ## Com port speed 31 | # Default COM port speed (used for flashing) 32 | COM_SPEED_ESPTOOL = 921600 33 | # Default COM port speed (used in code) 34 | COM_SPEED_SERIAL = 115200 35 | 36 | ## Configure flash parameters (for ESP12-E and other new boards): 37 | # SPI_MODE = dio 38 | 39 | ## SPIFFS options 40 | DISABLE_SPIFFS = 1 41 | # SPIFF_FILES = files 42 | 43 | SPI_SIZE = 4M 44 | SPI_SPEED = 80 45 | -------------------------------------------------------------------------------- /hardware/README.MD: -------------------------------------------------------------------------------- 1 | # ESP8266硬件端 2 | ### ESP8266简介 3 | 4 | ESP8266是[乐鑫espressif](http://espressif.com/)设计的wifi芯片,主要有以下特点: 5 | 6 | - 801.11 b/g/n 2.4G~2.5G 7 | - 32bit CPU Tensilica L106 8 | - 80M&160M 9 | - RAM 32K+80K 10 | - 10bit ADC 11 | - 电源管理,深度睡眠10uA,关断电流小于5mA 12 | - 天线分集 13 | - SDIO2.0 HSPI/SPI,UART,I2C,I2S,HW IR Remote,PWM,GPIO 14 | - 工作温度-40~125 15 | - 工作电压3.0~3.6V 16 | - GFN32 17 | 18 | ##### 使用的开发板--[NodeMCU](http://www.nodemcu.com/) 19 | 20 | ![NodeMCU](https://raw.githubusercontent.com/nodemcu/nodemcu-devkit-v1.0/master/Documents/NodeMCU_DEVKIT_1.0.jpg) 21 | ##### 使用的开发代码库--[Sming](https://github.com/SmingHub/Sming) 22 | > Sming - Open Source framework for high efficiency WiFi SoC ESP8266 native development with C++ language. 23 | 24 | ### 开发 25 | - 按照[Sming说明](https://github.com/SmingHub/Sming)搭建开发环境 26 | - 使用Sming fork 出来的一个分支作为SmingHome https://github.com/fcgdam/Sming (这个分支添加了对REST API的操作函数) 27 | - 根据安装结果配置hardware/Makefile-user.mk文件 28 | - 连接硬件到电脑(在hardware/Makefile-user.mk配置串口端口) 29 | 30 | ``` 31 | $ make flash //向硬件写入程序 32 | ``` 33 | -------------------------------------------------------------------------------- /hardware/app/application.cpp: -------------------------------------------------------------------------------- 1 | // Please configure your SSID, passwords and OW key on the user_config.h file 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | String postURL = "http://192.168.1.192:3000/api/sensor/"; 10 | 11 | HttpClient httpClient; 12 | Timer checkTimer; 13 | 14 | #define WORK_PIN 4 15 | DHT dht(WORK_PIN, 22); 16 | 17 | int currentMin = 0; 18 | // HTTP request callback. 19 | void onDataReceived(HttpClient &client, bool successful) { 20 | currentMin = client.getServerDate().Minute; 21 | if (successful) { 22 | Serial.println("发送成功"); 23 | } else { 24 | Serial.println("本次请求失败.."); 25 | } 26 | } 27 | 28 | 29 | //在每小时的59分时标记保存数据 30 | bool saved = false; 31 | bool getSaveStatus() { 32 | if (currentMin > 58) { 33 | if (!saved) { 34 | saved = true; 35 | return true; 36 | } else { 37 | return false; 38 | } 39 | } else { 40 | saved = false; 41 | return false; 42 | } 43 | } 44 | 45 | String getPostDate(){ 46 | float humidity = dht.readHumidity(); 47 | float temperature = dht.readTemperature(); 48 | float value; 49 | if (temperature > 0) { 50 | value = temperature; 51 | Serial.printf("检测到传感器,温度是: %f 湿度是: %f\n", temperature, 52 | humidity); 53 | } else { 54 | value = random(0, 40); 55 | Serial.printf("没有检测到传感器,发送随机值: %f \n", value); 56 | } 57 | String postString = 58 | "{\"value\":" + String(value) + ",\"save\":" + getSaveStatus() + "}"; 59 | return postString; 60 | } 61 | 62 | void postDate() { 63 | ledToggle(); 64 | httpClient.reset(); // Clear any data from previous requests. 65 | httpClient.setRequestContentType("application/json"); 66 | httpClient.setPostBody(getPostDate()); 67 | httpClient.doPost(postURL, onDataReceived); 68 | } 69 | 70 | void ShowInfo() { 71 | 72 | Serial.printf("设备信息:"); 73 | Serial.printf("\r\nSDK: v%s\r\n", system_get_sdk_version()); 74 | Serial.printf("Free Heap: %d\r\n", system_get_free_heap_size()); 75 | Serial.printf("CPU Frequency: %d MHz\r\n", system_get_cpu_freq()); 76 | Serial.printf("System Chip ID: 0x%x\r\n", system_get_chip_id()); 77 | Serial.printf("SPI Flash ID: 0x%x\r\n", spi_flash_get_id()); 78 | Serial.printf("SPI Flash Size: %d\r\n", 79 | (1 << ((spi_flash_get_id() >> 16) & 0xff))); 80 | } 81 | 82 | // Will be called when WiFi station is connected to AP 83 | void connectOk() { 84 | Serial.println("连接成功 :)"); 85 | Serial.println("设备IP地址为:"); 86 | Serial.println(WifiStation.getIP()); 87 | ShowInfo(); 88 | //将设备ID作为随机函数种子 89 | randomSeed(system_get_chip_id()); 90 | postURL = postURL + String(system_get_chip_id()) + "/value"; 91 | checkTimer.initializeMs(500, postDate).start(); 92 | } 93 | 94 | // Will be called when WiFi station timeout was reached 95 | void connectFail() { 96 | Serial.println("连接失败 :("); 97 | 98 | WifiStation.waitConnection( 99 | connectOk, 20, 100 | connectFail); // We recommend 20+ seconds for connection timeout at start 101 | } 102 | 103 | void sysReady() { Serial.println("System ready callback called...."); } 104 | 105 | // Standard init function. 106 | void init() { 107 | 108 | system_set_os_print(0); 109 | ledInit(); 110 | ledON(); 111 | Serial.begin(SERIAL_BAUD_RATE); // 115200 by default 112 | Serial.systemDebugOutput(false); // Disable debug output to serial 113 | 114 | // Connect to WIFI 115 | WifiStation.config(WIFI_SSID, WIFI_PWD); 116 | WifiStation.enable(true); 117 | WifiAccessPoint.enable(false); 118 | 119 | // Run our method when station was connected to AP (or not connected) 120 | WifiStation.waitConnection( 121 | connectOk, 20, 122 | connectFail); // We recommend 20+ seconds for connection timeout at start 123 | 124 | System.onReady(sysReady); 125 | } 126 | -------------------------------------------------------------------------------- /hardware/app/led.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define LED_PIN 16 5 | bool status = false; 6 | 7 | void ledInit() { 8 | pinMode(LED_PIN, OUTPUT); 9 | digitalWrite(LED_PIN, OFF); 10 | } 11 | 12 | void ledON() { 13 | digitalWrite(LED_PIN, ON); 14 | status = TRUE; 15 | } 16 | void ledToggle() { 17 | status = !status; 18 | digitalWrite(LED_PIN, status); 19 | } 20 | 21 | void ledOFF() { 22 | digitalWrite(LED_PIN, OFF); 23 | status = FALSE; 24 | } 25 | void ledSet(bool sta) { 26 | status = sta; 27 | digitalWrite(LED_PIN, !sta); 28 | } 29 | 30 | bool ledStatus() { return status; } 31 | -------------------------------------------------------------------------------- /hardware/include/led.h: -------------------------------------------------------------------------------- 1 | #ifndef __LED_H__ 2 | #define __LED_H__ 3 | 4 | #include 5 | 6 | #define ON false 7 | #define OFF true 8 | 9 | void ledInit(); 10 | void ledON(); 11 | void ledToggle(); 12 | void ledOFF(); 13 | void ledSet(bool sta); 14 | bool ledStatus(); 15 | #endif 16 | -------------------------------------------------------------------------------- /hardware/include/user_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_CONFIG_H__ 2 | #define __USER_CONFIG_H__ 3 | 4 | #ifndef WIFI_SSID 5 | #define WIFI_SSID "Android" // Put you SSID and Password here 6 | #define WIFI_PWD "zhrmghgws" 7 | #endif 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | // UART config 14 | #define SERIAL_BAUD_RATE 115200 15 | 16 | // ESP SDK config 17 | #define LWIP_OPEN_SRC 18 | #define USE_US_TIMER 19 | 20 | // Default types 21 | #define __CORRECT_ISO_CPP_STDLIB_H_PROTO 22 | #include 23 | #include 24 | 25 | // Override c_types.h include and remove buggy espconn 26 | #define _C_TYPES_H_ 27 | #define _NO_ESPCON_ 28 | 29 | // Updated, compatible version of c_types.h 30 | // Just removed types declared in 31 | #include 32 | 33 | // System API declarations 34 | #include 35 | 36 | // C++ Support 37 | #include 38 | // Extended string conversion for compatibility 39 | #include 40 | // Network base API 41 | #include 42 | 43 | // Beta boards 44 | #define BOARD_ESP01 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif 51 | --------------------------------------------------------------------------------