├── LICENSE ├── README.md ├── airmonitor_appplugin ├── app.js ├── app │ ├── page │ │ └── HomePage.js │ └── view │ │ └── Home.js ├── bone-config.json ├── package-lock.json └── package.json ├── airmonitor_dashboard ├── app.js ├── app │ ├── page │ │ └── home.js │ └── view │ │ ├── home │ │ ├── HistoryPanel.js │ │ ├── HistoryPanel.scss │ │ ├── SummaryPanel.js │ │ ├── SummaryPanel.scss │ │ ├── index.js │ │ └── index.scss │ │ └── not-found │ │ ├── index.js │ │ └── index.scss ├── bone-config.json ├── package.json └── public │ ├── drop.png │ ├── dust.png │ ├── index.html │ └── thermometer.png ├── airmonitor_device ├── lib │ ├── Crypto │ │ ├── .library.json │ │ ├── Crypto.cpp │ │ ├── Crypto.h │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── examples │ │ │ ├── aesSha256Hmac │ │ │ │ └── aesSha256Hmac.ino │ │ │ ├── sha256 │ │ │ │ └── sha256.ino │ │ │ └── sha256hmac │ │ │ │ └── sha256hmac.ino │ │ ├── keywords.txt │ │ └── library.properties │ ├── PubSubClient │ │ ├── .gitignore │ │ ├── .library.json │ │ ├── .travis.yml │ │ ├── CHANGES.txt │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── examples │ │ │ ├── mqtt_auth │ │ │ │ └── mqtt_auth.ino │ │ │ ├── mqtt_basic │ │ │ │ └── mqtt_basic.ino │ │ │ ├── mqtt_esp8266 │ │ │ │ └── mqtt_esp8266.ino │ │ │ ├── mqtt_publish_in_callback │ │ │ │ └── mqtt_publish_in_callback.ino │ │ │ ├── mqtt_reconnect_nonblocking │ │ │ │ └── mqtt_reconnect_nonblocking.ino │ │ │ └── mqtt_stream │ │ │ │ └── mqtt_stream.ino │ │ ├── keywords.txt │ │ ├── library.json │ │ ├── library.properties │ │ └── src │ │ │ ├── PubSubClient.cpp │ │ │ └── PubSubClient.h │ ├── WifiManager │ │ ├── .library.json │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── WiFiManager.cpp │ │ ├── WiFiManager.h │ │ ├── examples │ │ │ ├── AutoConnect │ │ │ │ └── AutoConnect.ino │ │ │ ├── AutoConnectWithFSParameters │ │ │ │ └── AutoConnectWithFSParameters.ino │ │ │ ├── AutoConnectWithFSParametersAndCustomIP │ │ │ │ └── AutoConnectWithFSParametersAndCustomIP.ino │ │ │ ├── AutoConnectWithFeedback │ │ │ │ └── AutoConnectWithFeedback.ino │ │ │ ├── AutoConnectWithFeedbackLED │ │ │ │ └── AutoConnectWithFeedbackLED.ino │ │ │ ├── AutoConnectWithReset │ │ │ │ └── AutoConnectWithReset.ino │ │ │ ├── AutoConnectWithStaticIP │ │ │ │ └── AutoConnectWithStaticIP.ino │ │ │ ├── AutoConnectWithTimeout │ │ │ │ └── AutoConnectWithTimeout.ino │ │ │ └── OnDemandConfigPortal │ │ │ │ └── OnDemandConfigPortal.ino │ │ ├── extras │ │ │ └── WiFiManager.template.html │ │ ├── keywords.txt │ │ ├── library.json │ │ ├── library.properties │ │ └── travis │ │ │ └── common.sh │ └── readme.txt ├── platformio.ini └── src │ ├── aliyun_iot.cpp │ ├── aliyun_iot.h │ ├── main.cpp │ ├── sensor.cpp │ └── sensor.h ├── airmonitor_ios ├── Podfile ├── airmonitor.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── airmonitor │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m └── yw_1222_07e8.jpg └── airmonitor_status-board ├── README.md ├── README.zh-CN.md ├── app ├── controller │ └── home.js ├── public │ └── img │ │ └── background.png ├── router.js ├── service │ └── apiclient.js └── view │ └── index.html ├── appveyor.yml ├── config ├── config.default.js └── plugin.js └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Aliyun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AirMonitor Demo for LinkDevelop 2 | 3 | 阿里云 IoT LinkDevelop 案例实战示例代码:空气监测站。 -------------------------------------------------------------------------------- /airmonitor_appplugin/app.js: -------------------------------------------------------------------------------- 1 | import Bone from '@bone/bone-mobile'; 2 | import HomePage from './app/page/HomePage'; 3 | 4 | const app = Bone.createApp({ 5 | appName: 'bone-demo', 6 | router: { 7 | routes: [ 8 | { 9 | path: '/', 10 | page: HomePage, 11 | initialProps: { 12 | title: 'Home', 13 | } 14 | } 15 | ] 16 | } 17 | }); 18 | 19 | app.start(); 20 | -------------------------------------------------------------------------------- /airmonitor_appplugin/app/page/HomePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Home from '../view/Home'; 3 | import { View } from 'react-native'; 4 | import { Navbar } from '@bone/bone-mobile-ui'; 5 | 6 | export default class HomePage extends Bone.Page { 7 | render() { 8 | const params = Bone.query; 9 | return 10 | 13 | 14 | ; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /airmonitor_appplugin/app/view/Home.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { StyleSheet, View, Text } from 'react-native'; 3 | import { Button, DataPanel } from '@bone/bone-mobile-ui'; 4 | import { APIGateway } from '@bone/sdk-base'; 5 | 6 | export default class Home extends Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = { PM10: 10, PM25Value: 12, CurrentTemperate: 25, RelativeHumidity: 50 }; 10 | } 11 | 12 | componentDidMount() { 13 | this.queryData(); 14 | setInterval(this.queryData.bind(this), 60000); 15 | } 16 | 17 | queryData() { 18 | const path = '/thing/device/properties/query'; 19 | const options = { 20 | protocol: 'https', 21 | gateway: 'api.link.aliyun.com', 22 | version: '1.1.0', 23 | data: { 24 | "productKey": this.props.ProductKey || '', 25 | "deviceName": this.props.DeviceName || '' 26 | } 27 | } 28 | APIGateway.request(path, options).then((res) => { 29 | let data = res.data.reduce((o, v) => { 30 | o[v.attribute] = v.value; 31 | return o; 32 | }, {}) 33 | this.setState({ ...data }); 34 | }); 35 | } 36 | 37 | render() { 38 | const { PM10, PM25Value, CurrentTemperate, RelativeHumidity } = this.state; 39 | 40 | return ( 41 | 72 | ); 73 | } 74 | } 75 | 76 | const styles = StyleSheet.create({ 77 | home: { 78 | flex: 1, 79 | justifyContent: 'center' 80 | } 81 | }); 82 | -------------------------------------------------------------------------------- /airmonitor_appplugin/bone-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "mobile", 3 | "APILevel": "1", 4 | "debug": { 5 | "param": { 6 | "uuid": "", 7 | "env": "test" 8 | }, 9 | "default": { 10 | "platform": "ios", 11 | "ip": "127.0.0.1" 12 | }, 13 | "router": "/" 14 | }, 15 | "release": { 16 | "ios": { 17 | "appVersion": "3.6.0", 18 | "runtimeVersion": "2.0.0" 19 | } 20 | }, 21 | "build": { 22 | "entry": { 23 | "app": "./app.js" 24 | } 25 | }, 26 | "bundleId": "__YOUR_MOBILE_PLUGIN_BUNDLE_ID__" 27 | } 28 | -------------------------------------------------------------------------------- /airmonitor_appplugin/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1 3 | } 4 | -------------------------------------------------------------------------------- /airmonitor_appplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "untitled", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "app.js", 7 | "scripts": { 8 | "pack": "bone build", 9 | "start": "bone start" 10 | }, 11 | "dependencies": { 12 | "@bone/bone-mobile": "^0.1.1", 13 | "@bone/bone-mv": "^0.1.13", 14 | "@bone/event-emitter": "^0.1.3", 15 | "@bone/logger": "^0.2.2", 16 | "@bone/bone-mobile-ui": "aep", 17 | "@bone/sdk-base": "^0.1.8", 18 | "core-js": "^2.5.1", 19 | "invariant": "^2.2.2", 20 | "koa-compose": "^4.0.0", 21 | "qs": "^6.5.1", 22 | "react": "~15.4.2", 23 | "react-dom": "~15.4.2", 24 | "react-native": "0.41.2", 25 | "react-router": "^4.1.1", 26 | "react-router-redux": "^5.0.0-alpha.9", 27 | "thunk-to-promise": "^1.0.1", 28 | "thunkify": "^2.1.2", 29 | "type-detect": "^4.0.8" 30 | }, 31 | "bnpm": { 32 | "mode": "yarn" 33 | }, 34 | "devDependencies": { 35 | "copy-dir": "^0.3.0", 36 | "rimraf": "^2.6.2" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /airmonitor_dashboard/app.js: -------------------------------------------------------------------------------- 1 | // 导入框架 构建成包后,直接安装引用 2 | import Bone from '@bone/bone-web-sdk'; 3 | // 导入页面 4 | import HomePage from './app/page/home'; 5 | import NotFound from './app/view/not-found'; 6 | 7 | // 函数式初始化 8 | const app = Bone.createApp({ 9 | id: "#__YOUR_WEB_APP_ID__", 10 | type: "app", 11 | // 是否自动启动 12 | autoStart: true, 13 | page: { 14 | // 路由配置 15 | routes: [ 16 | { 17 | path: "/", 18 | namespace: "home", 19 | classes: HomePage 20 | }, 21 | // 配置404页面 22 | { 23 | path: "*", 24 | classes: NotFound 25 | } 26 | ] 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /airmonitor_dashboard/app/page/home.js: -------------------------------------------------------------------------------- 1 | import { Page } from '@bone/bone-web-sdk'; 2 | import View from '../view/home'; 3 | 4 | class Model { 5 | add(state, step) { 6 | return { 7 | ...state, 8 | count: state.count + step 9 | }; 10 | } 11 | 12 | minus(state, step) { 13 | return { 14 | ...state, 15 | count: state.count - step 16 | }; 17 | } 18 | } 19 | 20 | export default class HomePage extends Page { 21 | constructor(namespace) { 22 | super(namespace); 23 | this.component = View; 24 | this.initWithAction({ count: 0 }, new Model()); 25 | } 26 | } -------------------------------------------------------------------------------- /airmonitor_dashboard/app/view/home/HistoryPanel.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Highcharts from 'highcharts'; 3 | import HighchartsMore from 'highcharts/highcharts-more'; 4 | HighchartsMore(Highcharts); 5 | import styles from "./HistoryPanel.scss"; 6 | import IotGatway from '@bone/iot-gateway'; 7 | 8 | export default class HistoryPanel extends Component { 9 | componentDidMount() { 10 | this.createChart(); 11 | this.queryStatusHistory(); 12 | window.setInterval(() => { 13 | this.queryStatusHistory(); 14 | }, 60000); 15 | } 16 | 17 | queryStatusHistory() { 18 | const { productKey, deviceName, showProp } = this.props; 19 | 20 | const options = { 21 | url: 'https://api.link.aliyun.com/thing/device/property/timeline/get', 22 | apiVer: '1.1.0', 23 | params: { 24 | "productKey": productKey, 25 | "deviceName": deviceName, 26 | "propertyIdentifier": showProp || "PM25Value", 27 | "start": new Date()*1-3600*24*1000, 28 | "end": new Date()*1, 29 | "pageSize": 1000, 30 | "ordered": true 31 | } 32 | }; 33 | IotGatway.post(options).then(res => { 34 | const data = res.data.items.map(item => [item.timestamp, item.data]); 35 | this.chart.series[0].setData(data); 36 | }) 37 | } 38 | 39 | createChart() { 40 | this.chart = Highcharts.chart(this.chartEl, { 41 | chart: { 42 | zoomType: 'x' 43 | }, 44 | title: { 45 | text: '' 46 | }, 47 | xAxis: { 48 | type: 'datetime' 49 | }, 50 | yAxis: { 51 | title: { 52 | text: 'μg/m³' 53 | }, 54 | min: 0 55 | }, 56 | legend: { 57 | enabled: false 58 | }, 59 | time: { 60 | useUTC: false, 61 | }, 62 | plotOptions: { 63 | area: { 64 | fillColor: { 65 | linearGradient: { 66 | x1: 0, 67 | y1: 0, 68 | x2: 0, 69 | y2: 1 70 | }, 71 | stops: [ 72 | [0, Highcharts.getOptions().colors[0]], 73 | [1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')] 74 | ] 75 | }, 76 | marker: { 77 | radius: 2 78 | }, 79 | lineWidth: 1, 80 | states: { 81 | hover: { 82 | lineWidth: 1 83 | } 84 | }, 85 | threshold: null 86 | } 87 | }, 88 | 89 | series: [{ 90 | type: 'area', 91 | name: 'PM2.5', 92 | data: [] 93 | }] 94 | }); 95 | } 96 | 97 | render() { 98 | return
99 |

{this.props.title}

100 |
{ this.chartEl = el }}>
101 |
102 | } 103 | } -------------------------------------------------------------------------------- /airmonitor_dashboard/app/view/home/HistoryPanel.scss: -------------------------------------------------------------------------------- 1 | .panel { 2 | margin-bottom: 10px; 3 | padding: 10px; 4 | background-color: white; 5 | box-shadow: 2px 2px 5px #aaa; 6 | display: flex; 7 | flex-direction: column; 8 | } 9 | 10 | .content { 11 | display: flex; 12 | flex-direction: column; 13 | } 14 | 15 | .chart { 16 | height: 150px; 17 | } -------------------------------------------------------------------------------- /airmonitor_dashboard/app/view/home/SummaryPanel.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import styles from "./SummaryPanel.scss"; 3 | import IotGatway from '@bone/iot-gateway'; 4 | import TimeAgo from 'javascript-time-ago'; 5 | import en from 'javascript-time-ago/locale/en' 6 | TimeAgo.locale(en); 7 | const timeAgo = new TimeAgo('en-US'); 8 | 9 | export default class SummaryPanel extends Component { 10 | constructor(props) { 11 | super(props); 12 | this.state = { props: [] }; 13 | } 14 | 15 | componentDidMount() { 16 | this.queryDeviceStatus(); 17 | window.setInterval(() => { 18 | this.queryDeviceStatus(); 19 | }, 60000); 20 | } 21 | 22 | queryDeviceStatus() { 23 | const { productKey, deviceName } = this.props; 24 | 25 | const options = { 26 | url: 'https://api.link.aliyun.com/thing/device/properties/query', 27 | apiVer: '1.1.0', 28 | params: {"productKey": productKey, "deviceName": deviceName } 29 | }; 30 | IotGatway.post(options).then(res => { 31 | this.setState({ props: res.data }); 32 | }) 33 | } 34 | 35 | render() { 36 | return
37 |

{this.props.title}

38 |
39 | { 40 | this.state.props.map((prop) => { 41 | switch(prop.attribute) { 42 | case 'PM25Value': 43 | case 'PM1': 44 | case 'PM10': 45 | return
46 | 47 | {prop.attribute}
{timeAgo.format(new Date(prop.gmtModified))}
48 | {prop.value}μg/m³ 49 |
50 | break; 51 | case 'CurrentTemperature': 52 | return
53 | 54 | 湿度
{timeAgo.format(new Date(prop.gmtModified))}
55 | {prop.value}°C 56 |
57 | break; 58 | case 'RelativeHumidity': 59 | return
60 | 61 | 湿度
{timeAgo.format(new Date(prop.gmtModified))}
62 | {prop.value}% 63 |
64 | break; 65 | } 66 | }) 67 | } 68 |
69 |
70 | } 71 | } -------------------------------------------------------------------------------- /airmonitor_dashboard/app/view/home/SummaryPanel.scss: -------------------------------------------------------------------------------- 1 | .panel { 2 | margin-bottom: 10px; 3 | margin-right: 15px; 4 | padding: 10px 15px; 5 | background-color: white; 6 | box-shadow: 2px 2px 5px #aaa; 7 | display: flex; 8 | flex-direction: column; 9 | } 10 | 11 | .content { 12 | display: flex; 13 | flex-direction: column; 14 | font-size: 14px; 15 | line-height: 2; 16 | } 17 | 18 | .content div { 19 | display: flex; 20 | flex-direction: row; 21 | height: 40px; 22 | margin: 6px 0; 23 | line-height: 1em; 24 | font-size: 16px; 25 | } 26 | 27 | .content div img { 28 | margin-right: 16px; 29 | } 30 | 31 | .content div span em { 32 | font-size: 9px; 33 | color: #ccc; 34 | } 35 | 36 | .content div span, .content div label { 37 | flex: 1 1 auto; 38 | } 39 | 40 | .content div span:last-child { 41 | text-align: right; 42 | } -------------------------------------------------------------------------------- /airmonitor_dashboard/app/view/home/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import SummaryPanel from './SummaryPanel'; 3 | import HistoryPanel from './HistoryPanel' 4 | import styles from "./index.scss"; 5 | 6 | const summaryPanels = [ 7 | { 'title': '客厅', 'productKey': '__YOUR_DEVICE_PRODUCT_KEY__', 'deviceName': '__YOUR_DEVICE_NAME__' }, 8 | { 'title': '主卧', 'productKey': '__YOUR_DEVICE_PRODUCT_KEY__', 'deviceName': '__YOUR_DEVICE_NAME__' }, 9 | { 'title': '次卧', 'productKey': '__YOUR_DEVICE_PRODUCT_KEY__', 'deviceName': '__YOUR_DEVICE_NAME__' }, 10 | ]; 11 | 12 | const historyPanels = [ 13 | { 'title': '客厅 PM2.5 历史', 'productKey': '__YOUR_DEVICE_PRODUCT_KEY__', 'deviceName': '__YOUR_DEVICE_NAME__', 'showProp': 'PM25Value' }, 14 | { 'title': '客厅 PM1.0 历史', 'productKey': '__YOUR_DEVICE_PRODUCT_KEY__', 'deviceName': '__YOUR_DEVICE_NAME__', 'showProp': 'PM1' }, 15 | { 'title': '客厅 PM10 历史', 'productKey': '__YOUR_DEVICE_PRODUCT_KEY__', 'deviceName': '__YOUR_DEVICE_NAME__', 'showProp': 'PM10' }, 16 | ] 17 | 18 | export default class Home extends Component { 19 | render() { 20 | return
21 |
22 | { 23 | summaryPanels.map(p => ) 24 | } 25 |
26 |
27 | { 28 | historyPanels.map(p => ) 29 | } 30 |
31 |
32 | } 33 | } 34 | -------------------------------------------------------------------------------- /airmonitor_dashboard/app/view/home/index.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | background-color: #e5e5e5; 3 | margin: 15px; 4 | display: flex; 5 | flex-direction: row; 6 | } 7 | 8 | .left { 9 | flex: 1; 10 | } 11 | 12 | .right { 13 | flex: 2; 14 | } -------------------------------------------------------------------------------- /airmonitor_dashboard/app/view/not-found/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Button } from '@bone/bone-web-ui'; 3 | import styles from './index.scss'; 4 | 5 | export default class NotFound extends Component { 6 | render() { 7 | return ( 8 |
9 |
10 |

你要找的页面不存在

11 | 14 |
15 | ); 16 | } 17 | } -------------------------------------------------------------------------------- /airmonitor_dashboard/app/view/not-found/index.scss: -------------------------------------------------------------------------------- 1 | .not-found { 2 | text-align: center; 3 | margin: 80px auto; 4 | 5 | p { 6 | margin: 16px 0; 7 | color: $color-text1-5; 8 | font-size: 14px; 9 | } 10 | } 11 | 12 | .not-found-img { 13 | width: 143px; 14 | height: 104px; 15 | background-size: cover; 16 | background-repeat: no-repeat; 17 | margin: 0 auto; 18 | } 19 | -------------------------------------------------------------------------------- /airmonitor_dashboard/bone-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "web", 3 | "bundleId": "a120BURLWBPOokpQ" 4 | } 5 | -------------------------------------------------------------------------------- /airmonitor_dashboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "airmonitor_dashboard", 3 | "version": "0.0.1", 4 | "description": "airmonitor_dashboard", 5 | "main": "app.js", 6 | "dependencies": { 7 | "@bone/bone-web-sdk": "^0.3.0", 8 | "@bone/bone-web-ui": "latest", 9 | "@bone/bone-web-ui-dpl": "latest", 10 | "@bone/iot-gateway": "^1.0.5", 11 | "@boneweb/iot-plugin-panel": "^1.0.21", 12 | "highcharts": "^6.0.6", 13 | "javascript-time-ago": "^1.0.28", 14 | "react": "^15.1.0", 15 | "react-dom": "^15.1.0" 16 | }, 17 | "bnpm": { 18 | "mode": "yarn" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /airmonitor_dashboard/public/drop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliyun-linkdevelop/airmonitor_demo/d94188994ec97df709e0a1e90ee32952183fb8d7/airmonitor_dashboard/public/drop.png -------------------------------------------------------------------------------- /airmonitor_dashboard/public/dust.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliyun-linkdevelop/airmonitor_demo/d94188994ec97df709e0a1e90ee32952183fb8d7/airmonitor_dashboard/public/dust.png -------------------------------------------------------------------------------- /airmonitor_dashboard/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | AirMonitor Dashboard 8 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /airmonitor_dashboard/public/thermometer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliyun-linkdevelop/airmonitor_demo/d94188994ec97df709e0a1e90ee32952183fb8d7/airmonitor_dashboard/public/thermometer.png -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/.library.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Very minimal crypto", 3 | "repository": { 4 | "url": "https://github.com/intrbiz/arduino-crypto", 5 | "type": "git" 6 | }, 7 | "platforms": [ 8 | "espressif32", 9 | "espressif8266" 10 | ], 11 | "export": { 12 | "exclude": [ 13 | "extras", 14 | "docs", 15 | "tests", 16 | "test", 17 | "*.doxyfile", 18 | "*.pdf" 19 | ], 20 | "include": null 21 | }, 22 | "authors": [ 23 | { 24 | "maintainer": true, 25 | "name": "Chris Ellis", 26 | "url": null, 27 | "email": null 28 | } 29 | ], 30 | "keywords": [ 31 | "other" 32 | ], 33 | "id": 2058, 34 | "name": "Crypto", 35 | "frameworks": [ 36 | "arduino" 37 | ], 38 | "version": "1.0.0", 39 | "homepage": null 40 | } -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/Crypto.h: -------------------------------------------------------------------------------- 1 | /** 2 | * An extremely minimal crypto library for Arduino devices. 3 | * 4 | * The SHA256 and AES implementations are derived from axTLS 5 | * (http://axtls.sourceforge.net/), Copyright (c) 2008, Cameron Rich. 6 | * 7 | * Ported and refactored by Chris Ellis 2016. 8 | * pkcs7 padding routines added by Mike Killewald Nov 26, 2017 (adopted from https://github.com/spaniakos/AES). 9 | * 10 | */ 11 | 12 | #ifndef CRYPTO_h 13 | #define CRYPTO_h 14 | 15 | #include 16 | 17 | #if defined ESP8266 18 | #include 19 | #endif 20 | 21 | #define SHA256_SIZE 32 22 | #define SHA256HMAC_SIZE 32 23 | #define SHA256HMAC_BLOCKSIZE 64 24 | #define AES_MAXROUNDS 14 25 | #define AES_BLOCKSIZE 16 26 | #define AES_IV_SIZE 16 27 | #define AES_IV_LENGTH 16 28 | #define AES_128_KEY_LENGTH 16 29 | #define AES_256_KEY_LENGTH 16 30 | 31 | /** 32 | * Compute a SHA256 hash 33 | */ 34 | class SHA256 35 | { 36 | public: 37 | SHA256(); 38 | /** 39 | * Update the hash with new data 40 | */ 41 | void doUpdate(const byte *msg, int len); 42 | void doUpdate(const char *msg, unsigned int len) { doUpdate((byte*) msg, len); } 43 | void doUpdate(const char *msg) { doUpdate((byte*) msg, strlen(msg)); } 44 | /** 45 | * Compute the final hash and store it in [digest], digest must be 46 | * at least 32 bytes 47 | */ 48 | void doFinal(byte *digest); 49 | /** 50 | * Compute the final hash and check it matches this given expected hash 51 | */ 52 | bool matches(const byte *expected); 53 | private: 54 | void SHA256_Process(const byte digest[64]); 55 | uint32_t total[2]; 56 | uint32_t state[8]; 57 | uint8_t buffer[64]; 58 | }; 59 | 60 | #define HMAC_OPAD 0x5C 61 | #define HMAC_IPAD 0x36 62 | 63 | /** 64 | * Compute a HMAC using SHA256 65 | */ 66 | class SHA256HMAC 67 | { 68 | public: 69 | /** 70 | * Compute a SHA256 HMAC with the given [key] key of [length] bytes 71 | * for authenticity 72 | */ 73 | SHA256HMAC(const byte *key, unsigned int keyLen); 74 | /** 75 | * Update the hash with new data 76 | */ 77 | void doUpdate(const byte *msg, unsigned int len); 78 | void doUpdate(const char *msg, unsigned int len) { doUpdate((byte*) msg, len); } 79 | void doUpdate(const char *msg) { doUpdate((byte*) msg, strlen(msg)); } 80 | /** 81 | * Compute the final hash and store it in [digest], digest must be 82 | * at least 32 bytes 83 | */ 84 | void doFinal(byte *digest); 85 | /** 86 | * Compute the final hash and check it matches this given expected hash 87 | */ 88 | bool matches(const byte *expected); 89 | private: 90 | void blockXor(const byte *in, byte *out, byte val, byte len); 91 | SHA256 _hash; 92 | byte _innerKey[SHA256HMAC_BLOCKSIZE]; 93 | byte _outerKey[SHA256HMAC_BLOCKSIZE]; 94 | }; 95 | 96 | /** 97 | * AES 128 and 256, based on code from axTLS 98 | */ 99 | class AES 100 | { 101 | public: 102 | typedef enum 103 | { 104 | AES_MODE_128, 105 | AES_MODE_256 106 | } AES_MODE; 107 | typedef enum 108 | { 109 | CIPHER_ENCRYPT = 0x01, 110 | CIPHER_DECRYPT = 0x02 111 | } CIPHER_MODE; 112 | 113 | /** 114 | * Create this cipher instance in either encrypt or decrypt mode 115 | * 116 | * Use the given [key] which must be 16 bytes long for AES 128 and 117 | * 32 bytes for AES 256 118 | * 119 | * Use the given [iv] initialistion vection which must be 16 bytes long 120 | * 121 | * Use the either AES 128 or AES 256 as specified by [mode] 122 | * 123 | * Either encrypt or decrypt as specified by [cipherMode] 124 | */ 125 | AES(const uint8_t *key, const uint8_t *iv, AES_MODE mode, CIPHER_MODE cipherMode); 126 | 127 | /** 128 | * Either encrypt or decrypt [in] and store into [out] for [length] bytes, applying no padding 129 | * 130 | * Note: the length must be a multiple of 16 bytes 131 | */ 132 | void processNoPad(const uint8_t *in, uint8_t *out, int length); 133 | 134 | /** 135 | * Either encrypt or decrypt [in] and store into [out] for [length] bytes, applying padding as needed 136 | * 137 | * Note: the length must be a multiple of 16 bytes 138 | */ 139 | void process(const uint8_t *in, uint8_t *out, int length); 140 | 141 | /** Getter method for size 142 | * 143 | * This function returns the size 144 | * @return an integer, that is the size of the of the padded plaintext, 145 | * thus, the size of the ciphertext. 146 | */ 147 | int getSize(); 148 | 149 | /** Setter method for size 150 | * 151 | * This function sets the size of the plaintext+pad 152 | * 153 | */ 154 | void setSize(int size); 155 | 156 | /** Calculates the size of the plaintext and the padding. 157 | * 158 | * Calculates the size of the plaintext with the size of the 159 | * padding needed. Moreover it stores them in their class variables. 160 | * 161 | * @param in_size the size of the byte array ex sizeof(plaintext) 162 | * @return an int the size of the plaintext plus the padding 163 | */ 164 | int calcSizeAndPad(int in_size); 165 | 166 | /** Pads the plaintext 167 | * 168 | * This function pads the plaintext and returns an char array with the 169 | * plaintext and the padding in order for the plaintext to be compatible with 170 | * 16bit size blocks required by AES 171 | * 172 | * @param in the string of the plaintext in a byte array 173 | * @param out The string of the out array. 174 | * @return no return, The padded plaintext is stored in the out pointer. 175 | */ 176 | void padPlaintext(const uint8_t* in, uint8_t* out); 177 | 178 | /** Check the if the padding is correct. 179 | * 180 | * This functions checks the padding of the plaintext. 181 | * 182 | * @param in the string of the plaintext in a byte array 183 | * @param size the size of the string 184 | * @return true if correct / false if not 185 | */ 186 | bool checkPad(uint8_t* in, int lsize); 187 | 188 | private: 189 | void encryptCBC(const uint8_t *in, uint8_t *out, int length); 190 | void decryptCBC(const uint8_t *in, uint8_t *out, int length); 191 | void convertKey(); 192 | void encrypt(uint32_t *data); 193 | void decrypt(uint32_t *data); 194 | uint16_t _rounds; 195 | uint16_t _key_size; 196 | uint32_t _ks[(AES_MAXROUNDS+1)*8]; 197 | uint8_t _iv[AES_IV_SIZE]; 198 | int _pad_size; // size of padding to add to plaintext 199 | int _size; // size of plaintext plus padding to be ciphered 200 | uint8_t _arr_pad[15]; 201 | 202 | CIPHER_MODE _cipherMode; 203 | }; 204 | 205 | #if defined ESP8266 || defined ESP32 206 | /** 207 | * ESP8266 and ESP32 specific true random number generator 208 | */ 209 | class RNG 210 | { 211 | public: 212 | /** 213 | * Fill the [dst] array with [length] random bytes 214 | */ 215 | static void fill(uint8_t *dst, unsigned int length); 216 | /** 217 | * Get a random byte 218 | */ 219 | static byte get(); 220 | /** 221 | * Get a 32bit random number 222 | */ 223 | static uint32_t getLong(); 224 | private: 225 | }; 226 | #endif 227 | 228 | 229 | #endif 230 | -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/LICENSE.md: -------------------------------------------------------------------------------- 1 | License 2 | ======= 3 | Balsa SCGI 4 | Copyright (c) 2012, Chris Ellis 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/README.md: -------------------------------------------------------------------------------- 1 | # ESP8266 Crypto 2 | 3 | This is a minimal, lightweight crypto library for the ESP8266 IOT device. It 4 | provides the following functions: 5 | 6 | * SHA256 7 | * AES 128 and 256 8 | * SHA256HMAC 9 | * RNG 10 | 11 | The SHA256 and AES implementations are based upon the implementations in axTLS 12 | except ported to the ESP8266 Arduino platform, credit to Cameron Rich for the 13 | axTLS project. 14 | 15 | ## Usage 16 | 17 | ### SHA256HMAC 18 | 19 | The following snippet demonstrates how to compute the SHA256 HMAC authentication 20 | code for a message. 21 | 22 | /* Include the crypto library into your project */ 23 | #include 24 | 25 | /* The length of the key we will use for this HMAC */ 26 | /* The key can be of any length, 16 and 32 are common */ 27 | #define KEY_LENGTH 16 28 | 29 | /* Define our */ 30 | byte key[KEY_LENGTH] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; 31 | 32 | /* Create the HMAC instance with our key */ 33 | SHA256HMAC hmac(key, KEY_LENGTH); 34 | 35 | /* Update the HMAC with just a plain string (null terminated) */ 36 | hmac.doUpdate("Hello World"); 37 | 38 | /* And or with a string and length */ 39 | const char *goodbye = "GoodBye World"; 40 | hmac.doUpdate(goodbye, strlen(goodbye)); 41 | 42 | /* And or with a binary message */ 43 | byte message[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 44 | hmac.doUpdate(message, sizeof(message)); 45 | 46 | /* Finish the HMAC calculation and return the authentication code */ 47 | byte authCode[SHA256HMAC_SIZE]; 48 | hmac.doFinal(authCode); 49 | 50 | /* authCode now contains our 32 byte authentication code */ 51 | for (byte i; i < SHA256HMAC_SIZE; i++) 52 | { 53 | Serial.print(authCode[i], HEX); 54 | } 55 | 56 | ### SHA256 57 | 58 | The following snippet demonstrates how to compute the SHA256 hash of a message. 59 | 60 | /* Create a SHA256 hash */ 61 | SHA256 hasher; 62 | 63 | /* Update the hash with your message, as many times as you like */ 64 | const char *hello = "Hello World"; 65 | hasher.doUpdate(hello, strlen(hello)); 66 | 67 | /* Update the hash with just a plain string*/ 68 | hasher.doUpdate("Goodbye World"); 69 | 70 | /* Update the hash with a binary message */ 71 | byte message[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 72 | hasher.doUpdate(message, sizeof(message)); 73 | 74 | /* Compute the final hash */ 75 | byte hash[SHA256_SIZE]; 76 | hasher.doFinal(hash); 77 | 78 | /* hash now contains our 32 byte hash */ 79 | for (byte i; i < SHA256_SIZE; i++) 80 | { 81 | Serial.print(hash[i], HEX); 82 | } 83 | 84 | ## License 85 | 86 | ESP8266 Crypto 87 | Copyright (c) 2016, Chris Ellis, with portions derived from axTLS 88 | All rights reserved. 89 | 90 | Redistribution and use in source and binary forms, with or without 91 | modification, are permitted provided that the following conditions are met: 92 | 93 | 1. Redistributions of source code must retain the above copyright notice, this 94 | list of conditions and the following disclaimer. 95 | 2. Redistributions in binary form must reproduce the above copyright notice, 96 | this list of conditions and the following disclaimer in the documentation 97 | and/or other materials provided with the distribution. 98 | 99 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 100 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 101 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 102 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 103 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 104 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 105 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 106 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 107 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 108 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 109 | 110 | ## Author 111 | 112 | Chris Ellis 113 | 114 | Twitter: @intrbiz 115 | 116 | Copyright (c) Chris Ellis 2016 117 | -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/examples/aesSha256Hmac/aesSha256Hmac.ino: -------------------------------------------------------------------------------- 1 | #include // AES 128 CBC with pkcs7, RNG, SHA256 and SHA256HMAC 2 | #include // Base64 encode and decode without line breaks https://github.com/Densaugeo/base64_arduino 3 | 4 | /* 5 | * AES encryption with SHA256HMAC on an ESP8266 6 | */ 7 | 8 | #define HMAC_KEY_LENGTH 16 9 | #define AES_KEY_LENGTH 16 10 | 11 | uint8_t* keyEncrypt; 12 | uint8_t* keyHmac; 13 | uint8_t keyHash[SHA256_SIZE]; 14 | uint8_t key[AES_KEY_LENGTH] = { 0x1C,0x3E,0x4B,0xAF,0x13,0x4A,0x89,0xC3,0xF3,0x87,0x4F,0xBC,0xD7,0xF3, 0x31, 0x31 }; 15 | uint8_t iv[AES_KEY_LENGTH]; 16 | 17 | SHA256 sha256; 18 | 19 | // prints given block of given length in HEX 20 | void printBlock(uint8_t* block, int length) { 21 | Serial.print(" { "); 22 | for (int i=0; i?-=[];'./,"; 48 | // char packet[] = "0123456789abcdef"; 49 | 50 | Serial.println("On the sending side:"); 51 | 52 | int packetSize = strlen(packet); 53 | Serial.printf("Packet (%d bytes):\n", packetSize); 54 | Serial.println(packet); 55 | 56 | Serial.print("Packet HEX"); 57 | printBlock((uint8_t*)packet, packetSize+1); //+1 to add null termination 58 | 59 | // random initialization vector 60 | RNG::fill(iv, AES_KEY_LENGTH); 61 | 62 | Serial.printf("Random IV (%d bytes)", AES_KEY_LENGTH); 63 | printBlock(iv, AES_KEY_LENGTH); 64 | 65 | AES aes(keyEncrypt, iv, AES::AES_MODE_128, AES::CIPHER_ENCRYPT); 66 | 67 | // create buffer for final message which will contain IV, encrypted message, and HMAC 68 | int encryptedSize = aes.calc_size_n_pad(packetSize); 69 | int ivEncryptedSize = encryptedSize + AES_KEY_LENGTH; 70 | int ivEncryptedHmacSize = ivEncryptedSize + SHA256HMAC_SIZE; 71 | uint8_t ivEncryptedHmac[ivEncryptedHmacSize]; 72 | 73 | // copy IV to our final message buffer 74 | memcpy(ivEncryptedHmac, iv, AES_KEY_LENGTH); 75 | 76 | // encrypted is a pointer that points to the encypted messages position in our final message buffer 77 | uint8_t* encrypted = ivEncryptedHmac + AES_KEY_LENGTH; 78 | 79 | // AES 128 CBC and pkcs7 padding 80 | aes.process((uint8_t*)packet, encrypted, packetSize); 81 | 82 | Serial.printf("Encrypted (%d bytes)", encryptedSize); 83 | printBlock(encrypted, encryptedSize); 84 | 85 | // computedHmac is a pointer which points to the HMAC position in our final message buffer 86 | uint8_t* computedHmac = encrypted + encryptedSize; 87 | 88 | // compute HMAC/SHA-256 with keyHmac 89 | SHA256HMAC hmac(keyHmac, HMAC_KEY_LENGTH); 90 | hmac.doUpdate(ivEncryptedHmac, ivEncryptedSize); 91 | hmac.doFinal(computedHmac); 92 | 93 | Serial.printf("Computed HMAC (%d bytes)", SHA256HMAC_SIZE); 94 | printBlock(computedHmac, SHA256HMAC_SIZE); 95 | 96 | Serial.printf("IV | encrypted | HMAC (%d bytes)", ivEncryptedHmacSize); 97 | printBlock(ivEncryptedHmac, ivEncryptedHmacSize); 98 | 99 | // base64 encode 100 | int encodedSize = encode_base64_length(ivEncryptedHmacSize); // get size needed for base64 encoded output 101 | uint8_t encoded[encodedSize]; 102 | encode_base64(ivEncryptedHmac, ivEncryptedHmacSize, encoded); 103 | 104 | Serial.printf("Base64 encoded to %d bytes\n", encodedSize); 105 | 106 | // Now on to the receiving side. This would normally be in a different skectch so we would 107 | // again SHA256 hash our secret key to obain keyEncrypt and KeyHmac on the remote side. 108 | // We would then recompute the HMAC using the received iv plus encrypted mesage and 109 | // compare the computed HMAC to the received HMAC. If they match, we can decrypt the message. 110 | 111 | Serial.printf("\nOn the receiving side:\n"); 112 | 113 | // base64 decode 114 | int decodedSize = decode_base64_length(encoded); 115 | uint8_t decoded[decodedSize]; 116 | decode_base64(encoded, decoded); 117 | 118 | Serial.printf("Received %d bytes\n", encodedSize); 119 | Serial.printf("Base64 decoded IV | encrypted | HMAC (%d bytes)", decodedSize); 120 | printBlock(decoded, decodedSize); 121 | 122 | // receivedHmac is a pointer which points to the received HMAC in our decoded message 123 | uint8_t* receivedHmac = decoded+decodedSize-SHA256HMAC_SIZE; 124 | 125 | Serial.printf("Received HMAC (%d bytes)", SHA256HMAC_SIZE); 126 | printBlock(receivedHmac, SHA256HMAC_SIZE); 127 | 128 | // compute HMAC/SHA-256 with keyHmac 129 | uint8_t remote_computedHmac[SHA256HMAC_SIZE]; 130 | SHA256HMAC remote_hmac(keyHmac, HMAC_KEY_LENGTH); 131 | remote_hmac.doUpdate(decoded, decodedSize-SHA256HMAC_SIZE); 132 | remote_hmac.doFinal(remote_computedHmac); 133 | 134 | Serial.printf("Computed HMAC (%d bytes)", SHA256HMAC_SIZE); 135 | printBlock(remote_computedHmac, SHA256HMAC_SIZE); 136 | 137 | if (*receivedHmac == *remote_computedHmac) { 138 | // extract IV 139 | memcpy(iv, decoded, AES_KEY_LENGTH); 140 | 141 | Serial.printf("Received IV (%d bytes)", AES_KEY_LENGTH); 142 | printBlock(iv, AES_KEY_LENGTH); 143 | 144 | // decrypt 145 | int decryptedSize = decodedSize - AES_KEY_LENGTH - SHA256HMAC_SIZE; 146 | char decrypted[decryptedSize]; 147 | AES aesDecryptor(keyEncrypt, iv, AES::AES_MODE_128, AES::CIPHER_DECRYPT); 148 | aesDecryptor.process((uint8_t*)decoded + AES_KEY_LENGTH, (uint8_t*)decrypted, decryptedSize); 149 | 150 | Serial.printf("Decrypted Packet HEX (%d bytes)", decryptedSize); 151 | printBlock((uint8_t*)decrypted, decryptedSize); 152 | 153 | Serial.printf("Decrypted Packet (%d bytes):\n", strlen(decrypted)); 154 | Serial.println(decrypted); 155 | } 156 | } 157 | 158 | void loop() { 159 | delay(1); 160 | } 161 | -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/examples/sha256/sha256.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * Compute the SHA256 hash of a message on an ESP8266 5 | */ 6 | 7 | void setup() 8 | { 9 | // Setup Serial 10 | Serial.begin(9600); 11 | Serial.println("SHA256 example"); 12 | 13 | /* Create a SHA256 hash */ 14 | SHA256 hasher; 15 | 16 | /* Update the hash with your message, as many times as you like */ 17 | const char *hello = "Hello World"; 18 | hasher.doUpdate(hello, strlen(hello)); 19 | 20 | /* Update the hash with just a plain string*/ 21 | hasher.doUpdate("Goodbye World"); 22 | 23 | /* Update the hash with a binary message */ 24 | byte message[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 25 | hasher.doUpdate(message, sizeof(message)); 26 | 27 | /* Compute the final hash */ 28 | byte hash[SHA256_SIZE]; 29 | hasher.doFinal(hash); 30 | 31 | /* hash now contains our 32 byte hash */ 32 | for (byte i=0; i < SHA256_SIZE; i++) 33 | { 34 | if (hash[i]<0x10) { Serial.print('0'); } 35 | Serial.print(hash[i], HEX); 36 | } 37 | } 38 | 39 | 40 | void loop() 41 | { 42 | 43 | } 44 | -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/examples/sha256hmac/sha256hmac.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | * Compute the SHA256HMAC of a message on an ESP8266 5 | */ 6 | 7 | /* The length of the key we will use for this HMAC */ 8 | /* The key can be of any length, 16 and 32 are common */ 9 | #define KEY_LENGTH 16 10 | 11 | void setup() 12 | { 13 | // Setup Serial 14 | Serial.begin(9600); 15 | Serial.println("SHA256HMAC example"); 16 | 17 | /* Define our */ 18 | byte key[KEY_LENGTH] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; 19 | 20 | /* Create the HMAC instance with our key */ 21 | SHA256HMAC hmac(key, KEY_LENGTH); 22 | 23 | /* Update the HMAC with just a plain string (null terminated) */ 24 | hmac.doUpdate("Hello World"); 25 | 26 | /* And or with a string and length */ 27 | const char *goodbye = "GoodBye World"; 28 | hmac.doUpdate(goodbye, strlen(goodbye)); 29 | 30 | /* And or with a binary message */ 31 | byte message[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 32 | hmac.doUpdate(message, sizeof(message)); 33 | 34 | /* Finish the HMAC calculation and return the authentication code */ 35 | byte authCode[SHA256HMAC_SIZE]; 36 | hmac.doFinal(authCode); 37 | 38 | /* authCode now contains our 32 byte authentication code */ 39 | for (byte i=0; i < SHA256HMAC_SIZE; i++) 40 | { 41 | if (authCode[i]<0x10) { Serial.print('0'); } 42 | Serial.print(authCode[i], HEX); 43 | } 44 | } 45 | 46 | 47 | void loop() 48 | { 49 | 50 | } 51 | -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Crypto 3 | ####################################### 4 | 5 | ####################################### 6 | # Library (KEYWORD3) 7 | ####################################### 8 | 9 | Crypto KEYWORD3 10 | 11 | ####################################### 12 | # Datatypes (KEYWORD1) 13 | ####################################### 14 | 15 | SHA256 KEYWORD1 16 | SHA256HMAC KEYWORD1 17 | AES KEYWORD1 18 | RNG KEYWORD1 19 | 20 | ####################################### 21 | # Methods and Functions (KEYWORD2) 22 | ####################################### 23 | 24 | doUpdate KEYWORD2 25 | doFinal KEYWORD2 26 | matches KEYWORD2 27 | AES KEYWORD2 28 | process KEYWORD2 29 | fill KEYWORD2 30 | get KEYWORD2 31 | getLong KEYWORD2 32 | 33 | ####################################### 34 | # Constants (LITERAL1) 35 | ####################################### 36 | 37 | SHA256_SIZE LITERAL1 38 | SHA256HMAC_SIZE LITERAL1 39 | SHA256HMAC_BLOCKSIZE LITERAL1 40 | AES_MAXROUNDS LITERAL1 41 | AES_BLOCKSIZE LITERAL1 42 | AES_IV_SIZE LITERAL1 43 | AES_IV_LENGTH LITERAL1 44 | AES_128_KEY_LENGTH LITERAL1 45 | AES_256_KEY_LENGTH LITERAL1 46 | HMAC_OPAD LITERAL1 47 | HMAC_IPAD LITERAL1 48 | -------------------------------------------------------------------------------- /airmonitor_device/lib/Crypto/library.properties: -------------------------------------------------------------------------------- 1 | name=Crypto 2 | version=1.0.0 3 | author=Chris Ellis 4 | maintainer=Chris Ellis 5 | sentence=Very minimal crypto 6 | paragraph=Very minimal crypto library derived from axtls 7 | category=Other 8 | url=https://github.com/intrbiz/arduino-crypto 9 | architectures=esp8266,esp32 10 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/.gitignore: -------------------------------------------------------------------------------- 1 | tests/bin 2 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/.library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PubSubClient", 3 | "repository": { 4 | "url": "https://github.com/knolleary/pubsubclient.git", 5 | "type": "git" 6 | }, 7 | "platforms": [ 8 | "atmelavr", 9 | "atmelsam", 10 | "espressif8266", 11 | "intel_arc32", 12 | "microchippic32", 13 | "nordicnrf51", 14 | "teensy", 15 | "timsp430" 16 | ], 17 | "frameworks": [ 18 | "arduino" 19 | ], 20 | "version": "2.6", 21 | "export": { 22 | "exclude": "tests" 23 | }, 24 | "examples": "examples/*/*.ino", 25 | "authors": [ 26 | { 27 | "maintainer": false, 28 | "name": "Nick O'Leary", 29 | "url": "https://github.com/knolleary", 30 | "email": null 31 | } 32 | ], 33 | "keywords": [ 34 | "ethernet", 35 | "mqtt", 36 | "iot", 37 | "m2m" 38 | ], 39 | "homepage": "http://pubsubclient.knolleary.net", 40 | "id": 89, 41 | "description": "A client library for MQTT messaging. MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000." 42 | } -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: cpp 3 | compiler: 4 | - g++ 5 | script: cd tests && make && make test 6 | os: 7 | - linux 8 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/CHANGES.txt: -------------------------------------------------------------------------------- 1 | 2.4 2 | * Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely 3 | whilst waiting for inbound data 4 | * Fixed return code when publishing >256 bytes 5 | 6 | 2.3 7 | * Add publish(topic,payload,retained) function 8 | 9 | 2.2 10 | * Change code layout to match Arduino Library reqs 11 | 12 | 2.1 13 | * Add MAX_TRANSFER_SIZE def to chunk messages if needed 14 | * Reject topic/payloads that exceed MQTT_MAX_PACKET_SIZE 15 | 16 | 2.0 17 | * Add (and default to) MQTT 3.1.1 support 18 | * Fix PROGMEM handling for Intel Galileo/ESP8266 19 | * Add overloaded constructors for convenience 20 | * Add chainable setters for server/callback/client/stream 21 | * Add state function to return connack return code 22 | 23 | 1.9 24 | * Do not split MQTT packets over multiple calls to _client->write() 25 | * API change: All constructors now require an instance of Client 26 | to be passed in. 27 | * Fixed example to match 1.8 api changes - dpslwk 28 | * Added username/password support - WilHall 29 | * Added publish_P - publishes messages from PROGMEM - jobytaffey 30 | 31 | 1.8 32 | * KeepAlive interval is configurable in PubSubClient.h 33 | * Maximum packet size is configurable in PubSubClient.h 34 | * API change: Return boolean rather than int from various functions 35 | * API change: Length parameter in message callback changed 36 | from int to unsigned int 37 | * Various internal tidy-ups around types 38 | 1.7 39 | * Improved keepalive handling 40 | * Updated to the Arduino-1.0 API 41 | 1.6 42 | * Added the ability to publish a retained message 43 | 44 | 1.5 45 | * Added default constructor 46 | * Fixed compile error when used with arduino-0021 or later 47 | 48 | 1.4 49 | * Fixed connection lost handling 50 | 51 | 1.3 52 | * Fixed packet reading bug in PubSubClient.readPacket 53 | 54 | 1.2 55 | * Fixed compile error when used with arduino-0016 or later 56 | 57 | 58 | 1.1 59 | * Reduced size of library 60 | * Added support for Will messages 61 | * Clarified licensing - see LICENSE.txt 62 | 63 | 64 | 1.0 65 | * Only Quality of Service (QOS) 0 messaging is supported 66 | * The maximum message size, including header, is 128 bytes 67 | * The keepalive interval is set to 30 seconds 68 | * No support for Will messages 69 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2015 Nicholas O'Leary 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/README.md: -------------------------------------------------------------------------------- 1 | # Arduino Client for MQTT 2 | 3 | This library provides a client for doing simple publish/subscribe messaging with 4 | a server that supports MQTT. 5 | 6 | ## Examples 7 | 8 | The library comes with a number of example sketches. See File > Examples > PubSubClient 9 | within the Arduino application. 10 | 11 | Full API documentation is available here: http://pubsubclient.knolleary.net 12 | 13 | ## Limitations 14 | 15 | - It can only publish QoS 0 messages. It can subscribe at QoS 0 or QoS 1. 16 | - The maximum message size, including header, is **128 bytes** by default. This 17 | is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h`. 18 | - The keepalive interval is set to 15 seconds by default. This is configurable 19 | via `MQTT_KEEPALIVE` in `PubSubClient.h`. 20 | - The client uses MQTT 3.1.1 by default. It can be changed to use MQTT 3.1 by 21 | changing value of `MQTT_VERSION` in `PubSubClient.h`. 22 | 23 | 24 | ## Compatible Hardware 25 | 26 | The library uses the Arduino Ethernet Client api for interacting with the 27 | underlying network hardware. This means it Just Works with a growing number of 28 | boards and shields, including: 29 | 30 | - Arduino Ethernet 31 | - Arduino Ethernet Shield 32 | - Arduino YUN – use the included `YunClient` in place of `EthernetClient`, and 33 | be sure to do a `Bridge.begin()` first 34 | - Arduino WiFi Shield - if you want to send packets > 90 bytes with this shield, 35 | enable the `MQTT_MAX_TRANSFER_SIZE` define in `PubSubClient.h`. 36 | - Sparkfun WiFly Shield – [library](https://github.com/dpslwk/WiFly) 37 | - TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library) 38 | - Intel Galileo/Edison 39 | - ESP8266 40 | 41 | The library cannot currently be used with hardware based on the ENC28J60 chip – 42 | such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an 43 | [alternative library](https://github.com/njh/NanodeMQTT) available. 44 | 45 | ## License 46 | 47 | This code is released under the MIT License. 48 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/examples/mqtt_auth/mqtt_auth.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Basic MQTT example with Authentication 3 | 4 | - connects to an MQTT server, providing username 5 | and password 6 | - publishes "hello world" to the topic "outTopic" 7 | - subscribes to the topic "inTopic" 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // Update these with values suitable for your network. 15 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 16 | IPAddress ip(172, 16, 0, 100); 17 | IPAddress server(172, 16, 0, 2); 18 | 19 | void callback(char* topic, byte* payload, unsigned int length) { 20 | // handle message arrived 21 | } 22 | 23 | EthernetClient ethClient; 24 | PubSubClient client(server, 1883, callback, ethClient); 25 | 26 | void setup() 27 | { 28 | Ethernet.begin(mac, ip); 29 | // Note - the default maximum packet size is 128 bytes. If the 30 | // combined length of clientId, username and password exceed this, 31 | // you will need to increase the value of MQTT_MAX_PACKET_SIZE in 32 | // PubSubClient.h 33 | 34 | if (client.connect("arduinoClient", "testuser", "testpass")) { 35 | client.publish("outTopic","hello world"); 36 | client.subscribe("inTopic"); 37 | } 38 | } 39 | 40 | void loop() 41 | { 42 | client.loop(); 43 | } 44 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/examples/mqtt_basic/mqtt_basic.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Basic MQTT example 3 | 4 | This sketch demonstrates the basic capabilities of the library. 5 | It connects to an MQTT server then: 6 | - publishes "hello world" to the topic "outTopic" 7 | - subscribes to the topic "inTopic", printing out any messages 8 | it receives. NB - it assumes the received payloads are strings not binary 9 | 10 | It will reconnect to the server if the connection is lost using a blocking 11 | reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to 12 | achieve the same result without blocking the main loop. 13 | 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | // Update these with values suitable for your network. 21 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 22 | IPAddress ip(172, 16, 0, 100); 23 | IPAddress server(172, 16, 0, 2); 24 | 25 | void callback(char* topic, byte* payload, unsigned int length) { 26 | Serial.print("Message arrived ["); 27 | Serial.print(topic); 28 | Serial.print("] "); 29 | for (int i=0;i Preferences -> Additional Boards Manager URLs": 20 | http://arduino.esp8266.com/stable/package_esp8266com_index.json 21 | - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266" 22 | - Select your ESP8266 in "Tools -> Board" 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | // Update these with values suitable for your network. 30 | 31 | const char* ssid = "........"; 32 | const char* password = "........"; 33 | const char* mqtt_server = "broker.mqtt-dashboard.com"; 34 | 35 | WiFiClient espClient; 36 | PubSubClient client(espClient); 37 | long lastMsg = 0; 38 | char msg[50]; 39 | int value = 0; 40 | 41 | void setup() { 42 | pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output 43 | Serial.begin(115200); 44 | setup_wifi(); 45 | client.setServer(mqtt_server, 1883); 46 | client.setCallback(callback); 47 | } 48 | 49 | void setup_wifi() { 50 | 51 | delay(10); 52 | // We start by connecting to a WiFi network 53 | Serial.println(); 54 | Serial.print("Connecting to "); 55 | Serial.println(ssid); 56 | 57 | WiFi.begin(ssid, password); 58 | 59 | while (WiFi.status() != WL_CONNECTED) { 60 | delay(500); 61 | Serial.print("."); 62 | } 63 | 64 | Serial.println(""); 65 | Serial.println("WiFi connected"); 66 | Serial.println("IP address: "); 67 | Serial.println(WiFi.localIP()); 68 | } 69 | 70 | void callback(char* topic, byte* payload, unsigned int length) { 71 | Serial.print("Message arrived ["); 72 | Serial.print(topic); 73 | Serial.print("] "); 74 | for (int i = 0; i < length; i++) { 75 | Serial.print((char)payload[i]); 76 | } 77 | Serial.println(); 78 | 79 | // Switch on the LED if an 1 was received as first character 80 | if ((char)payload[0] == '1') { 81 | digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level 82 | // but actually the LED is on; this is because 83 | // it is acive low on the ESP-01) 84 | } else { 85 | digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH 86 | } 87 | 88 | } 89 | 90 | void reconnect() { 91 | // Loop until we're reconnected 92 | while (!client.connected()) { 93 | Serial.print("Attempting MQTT connection..."); 94 | // Attempt to connect 95 | if (client.connect("ESP8266Client")) { 96 | Serial.println("connected"); 97 | // Once connected, publish an announcement... 98 | client.publish("outTopic", "hello world"); 99 | // ... and resubscribe 100 | client.subscribe("inTopic"); 101 | } else { 102 | Serial.print("failed, rc="); 103 | Serial.print(client.state()); 104 | Serial.println(" try again in 5 seconds"); 105 | // Wait 5 seconds before retrying 106 | delay(5000); 107 | } 108 | } 109 | } 110 | void loop() { 111 | 112 | if (!client.connected()) { 113 | reconnect(); 114 | } 115 | client.loop(); 116 | 117 | long now = millis(); 118 | if (now - lastMsg > 2000) { 119 | lastMsg = now; 120 | ++value; 121 | snprintf (msg, 75, "hello world #%ld", value); 122 | Serial.print("Publish message: "); 123 | Serial.println(msg); 124 | client.publish("outTopic", msg); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Publishing in the callback 3 | 4 | - connects to an MQTT server 5 | - subscribes to the topic "inTopic" 6 | - when a message is received, republishes it to "outTopic" 7 | 8 | This example shows how to publish messages within the 9 | callback function. The callback function header needs to 10 | be declared before the PubSubClient constructor and the 11 | actual callback defined afterwards. 12 | This ensures the client reference in the callback function 13 | is valid. 14 | 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | // Update these with values suitable for your network. 22 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 23 | IPAddress ip(172, 16, 0, 100); 24 | IPAddress server(172, 16, 0, 2); 25 | 26 | // Callback function header 27 | void callback(char* topic, byte* payload, unsigned int length); 28 | 29 | EthernetClient ethClient; 30 | PubSubClient client(server, 1883, callback, ethClient); 31 | 32 | // Callback function 33 | void callback(char* topic, byte* payload, unsigned int length) { 34 | // In order to republish this payload, a copy must be made 35 | // as the orignal payload buffer will be overwritten whilst 36 | // constructing the PUBLISH packet. 37 | 38 | // Allocate the correct amount of memory for the payload copy 39 | byte* p = (byte*)malloc(length); 40 | // Copy the payload to the new buffer 41 | memcpy(p,payload,length); 42 | client.publish("outTopic", p, length); 43 | // Free the memory 44 | free(p); 45 | } 46 | 47 | void setup() 48 | { 49 | 50 | Ethernet.begin(mac, ip); 51 | if (client.connect("arduinoClient")) { 52 | client.publish("outTopic","hello world"); 53 | client.subscribe("inTopic"); 54 | } 55 | } 56 | 57 | void loop() 58 | { 59 | client.loop(); 60 | } 61 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Reconnecting MQTT example - non-blocking 3 | 4 | This sketch demonstrates how to keep the client connected 5 | using a non-blocking reconnect function. If the client loses 6 | its connection, it attempts to reconnect every 5 seconds 7 | without blocking the main loop. 8 | 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | // Update these with values suitable for your hardware/network. 16 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 17 | IPAddress ip(172, 16, 0, 100); 18 | IPAddress server(172, 16, 0, 2); 19 | 20 | void callback(char* topic, byte* payload, unsigned int length) { 21 | // handle message arrived 22 | } 23 | 24 | EthernetClient ethClient; 25 | PubSubClient client(ethClient); 26 | 27 | long lastReconnectAttempt = 0; 28 | 29 | boolean reconnect() { 30 | if (client.connect("arduinoClient")) { 31 | // Once connected, publish an announcement... 32 | client.publish("outTopic","hello world"); 33 | // ... and resubscribe 34 | client.subscribe("inTopic"); 35 | } 36 | return client.connected(); 37 | } 38 | 39 | void setup() 40 | { 41 | client.setServer(server, 1883); 42 | client.setCallback(callback); 43 | 44 | Ethernet.begin(mac, ip); 45 | delay(1500); 46 | lastReconnectAttempt = 0; 47 | } 48 | 49 | 50 | void loop() 51 | { 52 | if (!client.connected()) { 53 | long now = millis(); 54 | if (now - lastReconnectAttempt > 5000) { 55 | lastReconnectAttempt = now; 56 | // Attempt to reconnect 57 | if (reconnect()) { 58 | lastReconnectAttempt = 0; 59 | } 60 | } 61 | } else { 62 | // Client connected 63 | 64 | client.loop(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/examples/mqtt_stream/mqtt_stream.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Example of using a Stream object to store the message payload 3 | 4 | Uses SRAM library: https://github.com/ennui2342/arduino-sram 5 | but could use any Stream based class such as SD 6 | 7 | - connects to an MQTT server 8 | - publishes "hello world" to the topic "outTopic" 9 | - subscribes to the topic "inTopic" 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | // Update these with values suitable for your network. 18 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 19 | IPAddress ip(172, 16, 0, 100); 20 | IPAddress server(172, 16, 0, 2); 21 | 22 | SRAM sram(4, SRAM_1024); 23 | 24 | void callback(char* topic, byte* payload, unsigned int length) { 25 | sram.seek(1); 26 | 27 | // do something with the message 28 | for(uint8_t i=0; i 4 | maintainer=Nick O'Leary 5 | sentence=A client library for MQTT messaging. 6 | paragraph=MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000. 7 | category=Communication 8 | url=http://pubsubclient.knolleary.net 9 | architectures=* 10 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/src/PubSubClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PubSubClient.cpp - A simple client for MQTT. 3 | Nick O'Leary 4 | http://knolleary.net 5 | */ 6 | 7 | #include "PubSubClient.h" 8 | #include "Arduino.h" 9 | 10 | PubSubClient::PubSubClient() { 11 | this->_state = MQTT_DISCONNECTED; 12 | this->_client = NULL; 13 | this->stream = NULL; 14 | setCallback(NULL); 15 | } 16 | 17 | PubSubClient::PubSubClient(Client& client) { 18 | this->_state = MQTT_DISCONNECTED; 19 | setClient(client); 20 | this->stream = NULL; 21 | } 22 | 23 | PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { 24 | this->_state = MQTT_DISCONNECTED; 25 | setServer(addr, port); 26 | setClient(client); 27 | this->stream = NULL; 28 | } 29 | PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) { 30 | this->_state = MQTT_DISCONNECTED; 31 | setServer(addr,port); 32 | setClient(client); 33 | setStream(stream); 34 | } 35 | PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { 36 | this->_state = MQTT_DISCONNECTED; 37 | setServer(addr, port); 38 | setCallback(callback); 39 | setClient(client); 40 | this->stream = NULL; 41 | } 42 | PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { 43 | this->_state = MQTT_DISCONNECTED; 44 | setServer(addr,port); 45 | setCallback(callback); 46 | setClient(client); 47 | setStream(stream); 48 | } 49 | 50 | PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { 51 | this->_state = MQTT_DISCONNECTED; 52 | setServer(ip, port); 53 | setClient(client); 54 | this->stream = NULL; 55 | } 56 | PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) { 57 | this->_state = MQTT_DISCONNECTED; 58 | setServer(ip,port); 59 | setClient(client); 60 | setStream(stream); 61 | } 62 | PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { 63 | this->_state = MQTT_DISCONNECTED; 64 | setServer(ip, port); 65 | setCallback(callback); 66 | setClient(client); 67 | this->stream = NULL; 68 | } 69 | PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { 70 | this->_state = MQTT_DISCONNECTED; 71 | setServer(ip,port); 72 | setCallback(callback); 73 | setClient(client); 74 | setStream(stream); 75 | } 76 | 77 | PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { 78 | this->_state = MQTT_DISCONNECTED; 79 | setServer(domain,port); 80 | setClient(client); 81 | this->stream = NULL; 82 | } 83 | PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) { 84 | this->_state = MQTT_DISCONNECTED; 85 | setServer(domain,port); 86 | setClient(client); 87 | setStream(stream); 88 | } 89 | PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { 90 | this->_state = MQTT_DISCONNECTED; 91 | setServer(domain,port); 92 | setCallback(callback); 93 | setClient(client); 94 | this->stream = NULL; 95 | } 96 | PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { 97 | this->_state = MQTT_DISCONNECTED; 98 | setServer(domain,port); 99 | setCallback(callback); 100 | setClient(client); 101 | setStream(stream); 102 | } 103 | 104 | boolean PubSubClient::connect(const char *id) { 105 | return connect(id,NULL,NULL,0,0,0,0); 106 | } 107 | 108 | boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { 109 | return connect(id,user,pass,0,0,0,0); 110 | } 111 | 112 | boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { 113 | return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); 114 | } 115 | 116 | boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { 117 | if (!connected()) { 118 | int result = 0; 119 | 120 | if (domain != NULL) { 121 | result = _client->connect(this->domain, this->port); 122 | } else { 123 | result = _client->connect(this->ip, this->port); 124 | } 125 | if (result == 1) { 126 | nextMsgId = 1; 127 | // Leave room in the buffer for header and variable length field 128 | uint16_t length = 5; 129 | unsigned int j; 130 | 131 | #if MQTT_VERSION == MQTT_VERSION_3_1 132 | uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION}; 133 | #define MQTT_HEADER_VERSION_LENGTH 9 134 | #elif MQTT_VERSION == MQTT_VERSION_3_1_1 135 | uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION}; 136 | #define MQTT_HEADER_VERSION_LENGTH 7 137 | #endif 138 | for (j = 0;j>1); 154 | } 155 | } 156 | 157 | buffer[length++] = v; 158 | 159 | buffer[length++] = ((MQTT_KEEPALIVE) >> 8); 160 | buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); 161 | length = writeString(id,buffer,length); 162 | if (willTopic) { 163 | length = writeString(willTopic,buffer,length); 164 | length = writeString(willMessage,buffer,length); 165 | } 166 | 167 | if(user != NULL) { 168 | length = writeString(user,buffer,length); 169 | if(pass != NULL) { 170 | length = writeString(pass,buffer,length); 171 | } 172 | } 173 | 174 | write(MQTTCONNECT,buffer,length-5); 175 | 176 | lastInActivity = lastOutActivity = millis(); 177 | 178 | while (!_client->available()) { 179 | unsigned long t = millis(); 180 | if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) { 181 | _state = MQTT_CONNECTION_TIMEOUT; 182 | _client->stop(); 183 | return false; 184 | } 185 | } 186 | uint8_t llen; 187 | uint16_t len = readPacket(&llen); 188 | 189 | if (len == 4) { 190 | if (buffer[3] == 0) { 191 | lastInActivity = millis(); 192 | pingOutstanding = false; 193 | _state = MQTT_CONNECTED; 194 | return true; 195 | } else { 196 | _state = buffer[3]; 197 | } 198 | } 199 | _client->stop(); 200 | } else { 201 | _state = MQTT_CONNECT_FAILED; 202 | } 203 | return false; 204 | } 205 | return true; 206 | } 207 | 208 | // reads a byte into result 209 | boolean PubSubClient::readByte(uint8_t * result) { 210 | uint32_t previousMillis = millis(); 211 | while(!_client->available()) { 212 | uint32_t currentMillis = millis(); 213 | if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){ 214 | return false; 215 | } 216 | } 217 | *result = _client->read(); 218 | return true; 219 | } 220 | 221 | // reads a byte into result[*index] and increments index 222 | boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){ 223 | uint16_t current_index = *index; 224 | uint8_t * write_address = &(result[current_index]); 225 | if(readByte(write_address)){ 226 | *index = current_index + 1; 227 | return true; 228 | } 229 | return false; 230 | } 231 | 232 | uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { 233 | uint16_t len = 0; 234 | if(!readByte(buffer, &len)) return 0; 235 | bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; 236 | uint32_t multiplier = 1; 237 | uint16_t length = 0; 238 | uint8_t digit = 0; 239 | uint16_t skip = 0; 240 | uint8_t start = 0; 241 | 242 | do { 243 | if(!readByte(&digit)) return 0; 244 | buffer[len++] = digit; 245 | length += (digit & 127) * multiplier; 246 | multiplier *= 128; 247 | } while ((digit & 128) != 0); 248 | *lengthLength = len-1; 249 | 250 | if (isPublish) { 251 | // Read in topic length to calculate bytes to skip over for Stream writing 252 | if(!readByte(buffer, &len)) return 0; 253 | if(!readByte(buffer, &len)) return 0; 254 | skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; 255 | start = 2; 256 | if (buffer[0]&MQTTQOS1) { 257 | // skip message id 258 | skip += 2; 259 | } 260 | } 261 | 262 | for (uint16_t i = start;istream) { 265 | if (isPublish && len-*lengthLength-2>skip) { 266 | this->stream->write(digit); 267 | } 268 | } 269 | if (len < MQTT_MAX_PACKET_SIZE) { 270 | buffer[len] = digit; 271 | } 272 | len++; 273 | } 274 | 275 | if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { 276 | len = 0; // This will cause the packet to be ignored. 277 | } 278 | 279 | return len; 280 | } 281 | 282 | boolean PubSubClient::loop() { 283 | if (connected()) { 284 | unsigned long t = millis(); 285 | if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) { 286 | if (pingOutstanding) { 287 | this->_state = MQTT_CONNECTION_TIMEOUT; 288 | _client->stop(); 289 | return false; 290 | } else { 291 | buffer[0] = MQTTPINGREQ; 292 | buffer[1] = 0; 293 | _client->write(buffer,2); 294 | lastOutActivity = t; 295 | lastInActivity = t; 296 | pingOutstanding = true; 297 | } 298 | } 299 | if (_client->available()) { 300 | uint8_t llen; 301 | uint16_t len = readPacket(&llen); 302 | uint16_t msgId = 0; 303 | uint8_t *payload; 304 | if (len > 0) { 305 | lastInActivity = t; 306 | uint8_t type = buffer[0]&0xF0; 307 | if (type == MQTTPUBLISH) { 308 | if (callback) { 309 | uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; 310 | char topic[tl+1]; 311 | for (uint16_t i=0;i0 316 | if ((buffer[0]&0x06) == MQTTQOS1) { 317 | msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; 318 | payload = buffer+llen+3+tl+2; 319 | callback(topic,payload,len-llen-3-tl-2); 320 | 321 | buffer[0] = MQTTPUBACK; 322 | buffer[1] = 2; 323 | buffer[2] = (msgId >> 8); 324 | buffer[3] = (msgId & 0xFF); 325 | _client->write(buffer,4); 326 | lastOutActivity = t; 327 | 328 | } else { 329 | payload = buffer+llen+3+tl; 330 | callback(topic,payload,len-llen-3-tl); 331 | } 332 | } 333 | } else if (type == MQTTPINGREQ) { 334 | buffer[0] = MQTTPINGRESP; 335 | buffer[1] = 0; 336 | _client->write(buffer,2); 337 | } else if (type == MQTTPINGRESP) { 338 | pingOutstanding = false; 339 | } 340 | } 341 | } 342 | return true; 343 | } 344 | return false; 345 | } 346 | 347 | boolean PubSubClient::publish(const char* topic, const char* payload) { 348 | return publish(topic,(const uint8_t*)payload,strlen(payload),false); 349 | } 350 | 351 | boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { 352 | return publish(topic,(const uint8_t*)payload,strlen(payload),retained); 353 | } 354 | 355 | boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { 356 | return publish(topic, payload, plength, false); 357 | } 358 | 359 | boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { 360 | if (connected()) { 361 | if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) { 362 | // Too long 363 | return false; 364 | } 365 | // Leave room in the buffer for header and variable length field 366 | uint16_t length = 5; 367 | length = writeString(topic,buffer,length); 368 | uint16_t i; 369 | for (i=0;i 0) { 407 | digit |= 0x80; 408 | } 409 | buffer[pos++] = digit; 410 | llen++; 411 | } while(len>0); 412 | 413 | pos = writeString(topic,buffer,pos); 414 | 415 | rc += _client->write(buffer,pos); 416 | 417 | for (i=0;iwrite((char)pgm_read_byte_near(payload + i)); 419 | } 420 | 421 | lastOutActivity = millis(); 422 | 423 | return rc == tlen + 4 + plength; 424 | } 425 | 426 | boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { 427 | uint8_t lenBuf[4]; 428 | uint8_t llen = 0; 429 | uint8_t digit; 430 | uint8_t pos = 0; 431 | uint16_t rc; 432 | uint16_t len = length; 433 | do { 434 | digit = len % 128; 435 | len = len / 128; 436 | if (len > 0) { 437 | digit |= 0x80; 438 | } 439 | lenBuf[pos++] = digit; 440 | llen++; 441 | } while(len>0); 442 | 443 | buf[4-llen] = header; 444 | for (int i=0;i 0) && result) { 454 | bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining; 455 | rc = _client->write(writeBuf,bytesToWrite); 456 | result = (rc == bytesToWrite); 457 | bytesRemaining -= rc; 458 | writeBuf += rc; 459 | } 460 | return result; 461 | #else 462 | rc = _client->write(buf+(4-llen),length+1+llen); 463 | lastOutActivity = millis(); 464 | return (rc == 1+llen+length); 465 | #endif 466 | } 467 | 468 | boolean PubSubClient::subscribe(const char* topic) { 469 | return subscribe(topic, 0); 470 | } 471 | 472 | boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { 473 | if (qos < 0 || qos > 1) { 474 | return false; 475 | } 476 | if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { 477 | // Too long 478 | return false; 479 | } 480 | if (connected()) { 481 | // Leave room in the buffer for header and variable length field 482 | uint16_t length = 5; 483 | nextMsgId++; 484 | if (nextMsgId == 0) { 485 | nextMsgId = 1; 486 | } 487 | buffer[length++] = (nextMsgId >> 8); 488 | buffer[length++] = (nextMsgId & 0xFF); 489 | length = writeString((char*)topic, buffer,length); 490 | buffer[length++] = qos; 491 | return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); 492 | } 493 | return false; 494 | } 495 | 496 | boolean PubSubClient::unsubscribe(const char* topic) { 497 | if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { 498 | // Too long 499 | return false; 500 | } 501 | if (connected()) { 502 | uint16_t length = 5; 503 | nextMsgId++; 504 | if (nextMsgId == 0) { 505 | nextMsgId = 1; 506 | } 507 | buffer[length++] = (nextMsgId >> 8); 508 | buffer[length++] = (nextMsgId & 0xFF); 509 | length = writeString(topic, buffer,length); 510 | return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); 511 | } 512 | return false; 513 | } 514 | 515 | void PubSubClient::disconnect() { 516 | buffer[0] = MQTTDISCONNECT; 517 | buffer[1] = 0; 518 | _client->write(buffer,2); 519 | _state = MQTT_DISCONNECTED; 520 | _client->stop(); 521 | lastInActivity = lastOutActivity = millis(); 522 | } 523 | 524 | uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) { 525 | const char* idp = string; 526 | uint16_t i = 0; 527 | pos += 2; 528 | while (*idp) { 529 | buf[pos++] = *idp++; 530 | i++; 531 | } 532 | buf[pos-i-2] = (i >> 8); 533 | buf[pos-i-1] = (i & 0xFF); 534 | return pos; 535 | } 536 | 537 | 538 | boolean PubSubClient::connected() { 539 | boolean rc; 540 | if (_client == NULL ) { 541 | rc = false; 542 | } else { 543 | rc = (int)_client->connected(); 544 | if (!rc) { 545 | if (this->_state == MQTT_CONNECTED) { 546 | this->_state = MQTT_CONNECTION_LOST; 547 | _client->flush(); 548 | _client->stop(); 549 | } 550 | } 551 | } 552 | return rc; 553 | } 554 | 555 | PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) { 556 | IPAddress addr(ip[0],ip[1],ip[2],ip[3]); 557 | return setServer(addr,port); 558 | } 559 | 560 | PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) { 561 | this->ip = ip; 562 | this->port = port; 563 | this->domain = NULL; 564 | return *this; 565 | } 566 | 567 | PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) { 568 | this->domain = domain; 569 | this->port = port; 570 | return *this; 571 | } 572 | 573 | PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) { 574 | this->callback = callback; 575 | return *this; 576 | } 577 | 578 | PubSubClient& PubSubClient::setClient(Client& client){ 579 | this->_client = &client; 580 | return *this; 581 | } 582 | 583 | PubSubClient& PubSubClient::setStream(Stream& stream){ 584 | this->stream = &stream; 585 | return *this; 586 | } 587 | 588 | int PubSubClient::state() { 589 | return this->_state; 590 | } 591 | -------------------------------------------------------------------------------- /airmonitor_device/lib/PubSubClient/src/PubSubClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | PubSubClient.h - A simple client for MQTT. 3 | Nick O'Leary 4 | http://knolleary.net 5 | */ 6 | 7 | #ifndef PubSubClient_h 8 | #define PubSubClient_h 9 | 10 | #include 11 | #include "IPAddress.h" 12 | #include "Client.h" 13 | #include "Stream.h" 14 | 15 | #define MQTT_VERSION_3_1 3 16 | #define MQTT_VERSION_3_1_1 4 17 | 18 | // MQTT_VERSION : Pick the version 19 | //#define MQTT_VERSION MQTT_VERSION_3_1 20 | #ifndef MQTT_VERSION 21 | #define MQTT_VERSION MQTT_VERSION_3_1_1 22 | #endif 23 | 24 | // MQTT_MAX_PACKET_SIZE : Maximum packet size 25 | #ifndef MQTT_MAX_PACKET_SIZE 26 | #define MQTT_MAX_PACKET_SIZE 512 27 | #endif 28 | 29 | // MQTT_KEEPALIVE : keepAlive interval in Seconds 30 | #ifndef MQTT_KEEPALIVE 31 | #define MQTT_KEEPALIVE 60 32 | #endif 33 | 34 | // MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds 35 | #ifndef MQTT_SOCKET_TIMEOUT 36 | #define MQTT_SOCKET_TIMEOUT 15 37 | #endif 38 | 39 | // MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client 40 | // in each write call. Needed for the Arduino Wifi Shield. Leave undefined to 41 | // pass the entire MQTT packet in each write call. 42 | //#define MQTT_MAX_TRANSFER_SIZE 80 43 | 44 | // Possible values for client.state() 45 | #define MQTT_CONNECTION_TIMEOUT -4 46 | #define MQTT_CONNECTION_LOST -3 47 | #define MQTT_CONNECT_FAILED -2 48 | #define MQTT_DISCONNECTED -1 49 | #define MQTT_CONNECTED 0 50 | #define MQTT_CONNECT_BAD_PROTOCOL 1 51 | #define MQTT_CONNECT_BAD_CLIENT_ID 2 52 | #define MQTT_CONNECT_UNAVAILABLE 3 53 | #define MQTT_CONNECT_BAD_CREDENTIALS 4 54 | #define MQTT_CONNECT_UNAUTHORIZED 5 55 | 56 | #define MQTTCONNECT 1 << 4 // Client request to connect to Server 57 | #define MQTTCONNACK 2 << 4 // Connect Acknowledgment 58 | #define MQTTPUBLISH 3 << 4 // Publish message 59 | #define MQTTPUBACK 4 << 4 // Publish Acknowledgment 60 | #define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1) 61 | #define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2) 62 | #define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3) 63 | #define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request 64 | #define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment 65 | #define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request 66 | #define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment 67 | #define MQTTPINGREQ 12 << 4 // PING Request 68 | #define MQTTPINGRESP 13 << 4 // PING Response 69 | #define MQTTDISCONNECT 14 << 4 // Client is Disconnecting 70 | #define MQTTReserved 15 << 4 // Reserved 71 | 72 | #define MQTTQOS0 (0 << 1) 73 | #define MQTTQOS1 (1 << 1) 74 | #define MQTTQOS2 (2 << 1) 75 | 76 | #ifdef ESP8266 77 | #include 78 | #define MQTT_CALLBACK_SIGNATURE std::function callback 79 | #else 80 | #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) 81 | #endif 82 | 83 | class PubSubClient { 84 | private: 85 | Client* _client; 86 | uint8_t buffer[MQTT_MAX_PACKET_SIZE]; 87 | uint16_t nextMsgId; 88 | unsigned long lastOutActivity; 89 | unsigned long lastInActivity; 90 | bool pingOutstanding; 91 | MQTT_CALLBACK_SIGNATURE; 92 | uint16_t readPacket(uint8_t*); 93 | boolean readByte(uint8_t * result); 94 | boolean readByte(uint8_t * result, uint16_t * index); 95 | boolean write(uint8_t header, uint8_t* buf, uint16_t length); 96 | uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); 97 | IPAddress ip; 98 | const char* domain; 99 | uint16_t port; 100 | Stream* stream; 101 | int _state; 102 | public: 103 | PubSubClient(); 104 | PubSubClient(Client& client); 105 | PubSubClient(IPAddress, uint16_t, Client& client); 106 | PubSubClient(IPAddress, uint16_t, Client& client, Stream&); 107 | PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); 108 | PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); 109 | PubSubClient(uint8_t *, uint16_t, Client& client); 110 | PubSubClient(uint8_t *, uint16_t, Client& client, Stream&); 111 | PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); 112 | PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); 113 | PubSubClient(const char*, uint16_t, Client& client); 114 | PubSubClient(const char*, uint16_t, Client& client, Stream&); 115 | PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); 116 | PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); 117 | 118 | PubSubClient& setServer(IPAddress ip, uint16_t port); 119 | PubSubClient& setServer(uint8_t * ip, uint16_t port); 120 | PubSubClient& setServer(const char * domain, uint16_t port); 121 | PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); 122 | PubSubClient& setClient(Client& client); 123 | PubSubClient& setStream(Stream& stream); 124 | 125 | boolean connect(const char* id); 126 | boolean connect(const char* id, const char* user, const char* pass); 127 | boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); 128 | boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); 129 | void disconnect(); 130 | boolean publish(const char* topic, const char* payload); 131 | boolean publish(const char* topic, const char* payload, boolean retained); 132 | boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); 133 | boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); 134 | boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); 135 | boolean subscribe(const char* topic); 136 | boolean subscribe(const char* topic, uint8_t qos); 137 | boolean unsubscribe(const char* topic); 138 | boolean loop(); 139 | boolean connected(); 140 | int state(); 141 | }; 142 | 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/.library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WifiManager", 3 | "repository": { 4 | "url": "https://github.com/tzapu/WiFiManager.git", 5 | "type": "git" 6 | }, 7 | "platforms": [ 8 | "espressif8266" 9 | ], 10 | "frameworks": [ 11 | "arduino" 12 | ], 13 | "version": "0.12", 14 | "authors": [ 15 | { 16 | "maintainer": false, 17 | "name": "tzapu", 18 | "url": "https://github.com/tzapu", 19 | "email": null 20 | } 21 | ], 22 | "keywords": [ 23 | "wifi", 24 | "wi-fi" 25 | ], 26 | "id": 567, 27 | "description": "ESP8266 WiFi Connection manager with fallback web configuration portal" 28 | } -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | before_install: 3 | - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16" 4 | - sleep 3 5 | - export DISPLAY=:1.0 6 | - wget http://downloads.arduino.cc/arduino-1.6.5-linux64.tar.xz 7 | - tar xf arduino-1.6.5-linux64.tar.xz 8 | - sudo mv arduino-1.6.5 /usr/local/share/arduino 9 | - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino 10 | install: 11 | - ln -s $PWD /usr/local/share/arduino/libraries/WiFiManager 12 | # boards manager not working on 1.6.7 - 1.6.8 13 | - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --save-prefs 14 | # install lib arduino json not working in 1.6.5 15 | # - arduino --install-library "ArduinoJson" 16 | - git clone https://github.com/bblanchon/ArduinoJson /usr/local/share/arduino/libraries/ArduinoJson 17 | - arduino --install-boards esp8266:esp8266 18 | - arduino --board esp8266:esp8266:generic --save-prefs 19 | - arduino --pref "compiler.warning_level=all" --save-prefs 20 | script: 21 | - "echo $PWD" 22 | - "echo $HOME" 23 | - "ls $PWD" 24 | - source $TRAVIS_BUILD_DIR/travis/common.sh 25 | - build_examples 26 | # - "cat $PWD/examples/AutoConnect/AutoConnect.ino" 27 | # - arduino -v --verbose-build --verify $PWD/examples/AutoConnect/AutoConnect.ino 28 | # - arduino --verify --board arduino:avr:uno $PWD/examples/IncomingCall/IncomingCall.ino 29 | # - arduino --verify --board arduino:avr:uno $PWD/examples/AdafruitIO_GPS/AdafruitIO_GPS.ino 30 | notifications: 31 | email: 32 | on_success: change 33 | on_failure: change 34 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 tzapu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/README.md: -------------------------------------------------------------------------------- 1 | # WiFiManager 2 | ESP8266 WiFi Connection manager with fallback web configuration portal 3 | 4 | [![Build Status](https://travis-ci.org/tzapu/WiFiManager.svg?branch=master)](https://travis-ci.org/tzapu/WiFiManager) 5 | 6 | The configuration portal is of the captive variety, so on various devices it will present the configuration dialogue as soon as you connect to the created access point. 7 | 8 | First attempt at a library. Lots more changes and fixes to do. Contributions are welcome. 9 | 10 | #### This works with the ESP8266 Arduino platform with a recent stable release(2.0.0 or newer) https://github.com/esp8266/Arduino 11 | 12 | ## Contents 13 | - [How it works](#how-it-works) 14 | - [Wishlist](#wishlist) 15 | - [Quick start](#quick-start) 16 | - Installing 17 | - [Through Library Manager](#install-through-library-manager) 18 | - [From Github](#checkout-from-github) 19 | - [Using](#using) 20 | - [Documentation](#documentation) 21 | - [Access Point Password](#password-protect-the-configuration-access-point) 22 | - [Callbacks](#callbacks) 23 | - [Configuration Portal Timeout](#configuration-portal-timeout) 24 | - [On Demand Configuration](#on-demand-configuration-portal) 25 | - [Custom Parameters](#custom-parameters) 26 | - [Custom IP Configuration](#custom-ip-configuration) 27 | - [Filter Low Quality Networks](#filter-networks) 28 | - [Debug Output](#debug) 29 | - [Troubleshooting](#troubleshooting) 30 | - [Releases](#releases) 31 | - [Contributors](#contributions-and-thanks) 32 | 33 | 34 | ## How It Works 35 | - when your ESP starts up, it sets it up in Station mode and tries to connect to a previously saved Access Point 36 | - if this is unsuccessful (or no previous network saved) it moves the ESP into Access Point mode and spins up a DNS and WebServer (default ip 192.168.4.1) 37 | - using any wifi enabled device with a browser (computer, phone, tablet) connect to the newly created Access Point 38 | - because of the Captive Portal and the DNS server you will either get a 'Join to network' type of popup or get any domain you try to access redirected to the configuration portal 39 | - choose one of the access points scanned, enter password, click save 40 | - ESP will try to connect. If successful, it relinquishes control back to your app. If not, reconnect to AP and reconfigure. 41 | 42 | ## How It Looks 43 | ![ESP8266 WiFi Captive Portal Homepage](http://i.imgur.com/YPvW9eql.png) ![ESP8266 WiFi Captive Portal Configuration](http://i.imgur.com/oicWJ4gl.png) 44 | 45 | ## Wishlist 46 | - ~~remove dependency on EEPROM library~~ 47 | - ~~move HTML Strings to PROGMEM~~ 48 | - ~~cleanup and streamline code~~ (although this is ongoing) 49 | - if timeout is set, extend it when a page is fetched in AP mode 50 | - ~~add ability to configure more parameters than ssid/password~~ 51 | - ~~maybe allow setting ip of ESP after reboot~~ 52 | - ~~add to Arduino Library Manager~~ 53 | - ~~add to PlatformIO~~ 54 | - add multiple sets of network credentials 55 | - ~~allow users to customize CSS~~ 56 | 57 | ## Quick Start 58 | 59 | ### Installing 60 | You can either install through the Arduino Library Manager or checkout the latest changes or a release from github 61 | 62 | #### Install through Library Manager 63 | __Currently version 0.8+ works with release 2.0.0 or newer of the [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)__ 64 | - in Arduino IDE got to Sketch/Include Library/Manage Libraries 65 | ![Manage Libraries](http://i.imgur.com/9BkEBkR.png) 66 | 67 | - search for WiFiManager 68 | ![WiFiManager package](http://i.imgur.com/18yIai8.png) 69 | 70 | - click Install and start [using it](#using) 71 | 72 | #### Checkout from github 73 | __Github version works with release 2.0.0 or newer of the [ESP8266 core for Arduino](https://github.com/esp8266/Arduino)__ 74 | - Checkout library to your Arduino libraries folder 75 | 76 | ### Using 77 | - Include in your sketch 78 | ```cpp 79 | #include //ESP8266 Core WiFi Library (you most likely already have this in your sketch) 80 | 81 | #include //Local DNS Server used for redirecting all requests to the configuration portal 82 | #include //Local WebServer used to serve the configuration portal 83 | #include //https://github.com/tzapu/WiFiManager WiFi Configuration Magic 84 | ``` 85 | 86 | - Initialize library, in your setup function add 87 | ```cpp 88 | WiFiManager wifiManager; 89 | ``` 90 | 91 | - Also in the setup function add 92 | ```cpp 93 | //first parameter is name of access point, second is the password 94 | wifiManager.autoConnect("AP-NAME", "AP-PASSWORD"); 95 | ``` 96 | if you just want an unsecured access point 97 | ```cpp 98 | wifiManager.autoConnect("AP-NAME"); 99 | ``` 100 | or if you want to use and auto generated name from 'ESP' and the esp's Chip ID use 101 | ```cpp 102 | wifiManager.autoConnect(); 103 | ``` 104 | 105 | After you write your sketch and start the ESP, it will try to connect to WiFi. If it fails it starts in Access Point mode. 106 | While in AP mode, connect to it then open a browser to the gateway IP, default 192.168.4.1, configure wifi, save and it should reboot and connect. 107 | 108 | Also see [examples](https://github.com/tzapu/WiFiManager/tree/master/examples). 109 | 110 | ## Documentation 111 | 112 | #### Password protect the configuration Access Point 113 | You can and should password protect the configuration access point. Simply add the password as a second parameter to `autoConnect`. 114 | A short password seems to have unpredictable results so use one that's around 8 characters or more in length. 115 | The guidelines are that a wifi password must consist of 8 to 63 ASCII-encoded characters in the range of 32 to 126 (decimal) 116 | ```cpp 117 | wifiManager.autoConnect("AutoConnectAP", "password") 118 | ``` 119 | 120 | #### Callbacks 121 | ##### Enter Config mode 122 | Use this if you need to do something when your device enters configuration mode on failed WiFi connection attempt. 123 | Before `autoConnect()` 124 | ```cpp 125 | wifiManager.setAPCallback(configModeCallback); 126 | ``` 127 | `configModeCallback` declaration and example 128 | ```cpp 129 | void configModeCallback (WiFiManager *myWiFiManager) { 130 | Serial.println("Entered config mode"); 131 | Serial.println(WiFi.softAPIP()); 132 | 133 | Serial.println(myWiFiManager->getConfigPortalSSID()); 134 | } 135 | ``` 136 | 137 | ##### Save settings 138 | This gets called when custom parameters have been set **AND** a connection has been established. Use it to set a flag, so when all the configuration finishes, you can save the extra parameters somewhere. 139 | 140 | See [AutoConnectWithFSParameters Example](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters). 141 | ```cpp 142 | wifiManager.setSaveConfigCallback(saveConfigCallback); 143 | ``` 144 | `saveConfigCallback` declaration and example 145 | ```cpp 146 | //flag for saving data 147 | bool shouldSaveConfig = false; 148 | 149 | //callback notifying us of the need to save config 150 | void saveConfigCallback () { 151 | Serial.println("Should save config"); 152 | shouldSaveConfig = true; 153 | } 154 | ``` 155 | 156 | #### Configuration Portal Timeout 157 | If you need to set a timeout so the ESP doesn't hang waiting to be configured, for instance after a power failure, you can add 158 | ```cpp 159 | wifiManager.setConfigPortalTimeout(180); 160 | ``` 161 | which will wait 3 minutes (180 seconds). When the time passes, the autoConnect function will return, no matter the outcome. 162 | Check for connection and if it's still not established do whatever is needed (on some modules I restart them to retry, on others I enter deep sleep) 163 | 164 | #### On Demand Configuration Portal 165 | If you would rather start the configuration portal on demand rather than automatically on a failed connection attempt, then this is for you. 166 | 167 | Instead of calling `autoConnect()` which does all the connecting and failover configuration portal setup for you, you need to use `startConfigPortal()`. __Do not use BOTH.__ 168 | 169 | Example usage 170 | ```cpp 171 | void loop() { 172 | // is configuration portal requested? 173 | if ( digitalRead(TRIGGER_PIN) == LOW ) { 174 | WiFiManager wifiManager; 175 | wifiManager.startConfigPortal("OnDemandAP"); 176 | Serial.println("connected...yeey :)"); 177 | } 178 | } 179 | ``` 180 | See example for a more complex version. [OnDemandConfigPortal](https://github.com/tzapu/WiFiManager/tree/master/examples/OnDemandConfigPortal) 181 | 182 | #### Custom Parameters 183 | You can use WiFiManager to collect more parameters than just SSID and password. 184 | This could be helpful for configuring stuff like MQTT host and port, [blynk](http://www.blynk.cc) or [emoncms](http://emoncms.org) tokens, just to name a few. 185 | **You are responsible for saving and loading these custom values.** The library just collects and displays the data for you as a convenience. 186 | Usage scenario would be: 187 | - load values from somewhere (EEPROM/FS) or generate some defaults 188 | - add the custom parameters to WiFiManager using 189 | ```cpp 190 | // id/name, placeholder/prompt, default, length 191 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); 192 | wifiManager.addParameter(&custom_mqtt_server); 193 | 194 | ``` 195 | - if connection to AP fails, configuration portal starts and you can set /change the values (or use on demand configuration portal) 196 | - once configuration is done and connection is established [save config callback]() is called 197 | - once WiFiManager returns control to your application, read and save the new values using the `WiFiManagerParameter` object. 198 | ```cpp 199 | mqtt_server = custom_mqtt_server.getValue(); 200 | ``` 201 | This feature is a lot more involved than all the others, so here are some examples to fully show how it is done. 202 | You should also take a look at adding custom HTML to your form. 203 | 204 | - Save and load custom parameters to file system in json form [AutoConnectWithFSParameters](https://github.com/tzapu/WiFiManager/tree/master/examples/AutoConnectWithFSParameters) 205 | - *Save and load custom parameters to EEPROM* (not done yet) 206 | 207 | #### Custom IP Configuration 208 | You can set a custom IP for both AP (access point, config mode) and STA (station mode, client mode, normal project state) 209 | 210 | ##### Custom Access Point IP Configuration 211 | This will set your captive portal to a specific IP should you need/want such a feature. Add the following snippet before `autoConnect()` 212 | ```cpp 213 | //set custom ip for portal 214 | wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); 215 | ``` 216 | 217 | ##### Custom Station (client) Static IP Configuration 218 | This will make use the specified IP configuration instead of using DHCP in station mode. 219 | ```cpp 220 | wifiManager.setSTAStaticIPConfig(IPAddress(192,168,0,99), IPAddress(192,168,0,1), IPAddress(255,255,255,0)); 221 | ``` 222 | There are a couple of examples in the examples folder that show you how to set a static IP and even how to configure it through the web configuration portal. 223 | 224 | #### Custom HTML, CSS, Javascript 225 | There are various ways in which you can inject custom HTML, CSS or Javascript into the configuration portal. 226 | The options are: 227 | - inject custom head element 228 | You can use this to any html bit to the head of the configuration portal. If you add a `"); 231 | ``` 232 | - inject a custom bit of html in the configuration form 233 | ```cpp 234 | WiFiManagerParameter custom_text("

This is just a text paragraph

"); 235 | wifiManager.addParameter(&custom_text); 236 | ``` 237 | - inject a custom bit of html in a configuration form element 238 | Just add the bit you want added as the last parameter to the custom parameter constructor. 239 | ```cpp 240 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", "iot.eclipse", 40, " readonly"); 241 | ``` 242 | 243 | #### Filter Networks 244 | You can filter networks based on signal quality and show/hide duplicate networks. 245 | 246 | - If you would like to filter low signal quality networks you can tell WiFiManager to not show networks below an arbitrary quality %; 247 | ```cpp 248 | wifiManager.setMinimumSignalQuality(10); 249 | ``` 250 | will not show networks under 10% signal quality. If you omit the parameter it defaults to 8%; 251 | 252 | - You can also remove or show duplicate networks (default is remove). 253 | Use this function to show (or hide) all networks. 254 | ```cpp 255 | wifiManager.setRemoveDuplicateAPs(false); 256 | ``` 257 | 258 | #### Debug 259 | Debug is enabled by default on Serial. To disable add before autoConnect 260 | ```cpp 261 | wifiManager.setDebugOutput(false); 262 | ``` 263 | 264 | ## Troubleshooting 265 | If you get compilation errors, more often than not, you may need to install a newer version of the ESP8266 core for Arduino. 266 | 267 | Changes added on 0.8 should make the latest trunk work without compilation errors. Tested down to ESP8266 core 2.0.0. **Please update to version 0.8** 268 | 269 | I am trying to keep releases working with release versions of the core, so they can be installed through boards manager, but if you checkout the latest version directly from github, sometimes, the library will only work if you update the ESP8266 core to the latest version because I am using some newly added function. 270 | 271 | If you connect to the created configuration Access Point but the configuration portal does not show up, just open a browser and type in the IP of the web portal, by default `192.168.4.1`. 272 | 273 | If trying to connect ends up in an endless loop, try to add `setConnectTimeout(60)` before `autoConnect();`. The parameter is timeout to try connecting in seconds. 274 | 275 | ## Releases 276 | #### 0.12 277 | - removed 204 header response 278 | - fixed incompatibility with other libs using isnan and other std:: functions without namespace 279 | 280 | ##### 0.11 281 | - a lot more reliable reconnecting to networks 282 | - custom html in custom parameters (for read only params) 283 | - custom html in custom parameter form (like labels) 284 | - custom head element (like custom css) 285 | - sort networks based on signal quality 286 | - remove duplicate networks 287 | 288 | ##### 0.10 289 | - some css changes 290 | - bug fixes and speed improvements 291 | - added an alternative to waitForConnectResult() for debugging 292 | - changed `setTimeout(seconds)` to `setConfigPortalTimeout(seconds)` 293 | 294 | ##### 0.9 295 | - fixed support for encoded characters in ssid/pass 296 | 297 | ##### 0.8 298 | - made it compile on older versions of ESP8266 core as well, tested down to 2.0.0 299 | - added simple example for Custom IP 300 | 301 | ##### 0.7 302 | - added static IP in station mode 303 | - added example of persisting custom IP to FS config.json 304 | - more option on portal homepage 305 | - added on PlatformIO 306 | 307 | ##### 0.6 308 | - custom parameters 309 | - prettier 310 | - on demand config portal 311 | - commit #100 :D 312 | 313 | ##### 0.5 314 | - Added to Arduino Boards Manager - Thanks Max 315 | - moved most stuff to PROGMEM 316 | - added signal quality and a nice little padlock to show which networks are encrypted 317 | 318 | ##### v0.4 - all of it user contributed changes - Thank you 319 | - added ability to password protect the configuration Access Point 320 | - callback for enter configuration mode 321 | - memory allocation improvements 322 | 323 | ##### v0.3 324 | - removed the need for EEPROM and works with the 2.0.0 and above stable release of the ESP8266 for Arduino IDE package 325 | - removed restart on save of credentials 326 | - updated examples 327 | 328 | ##### v0.2 329 | needs the latest staging version (or at least a recent release of the staging version) to work 330 | 331 | ##### v0.1 332 | works with the staging release ver. 1.6.5-1044-g170995a, built on Aug 10, 2015 of the ESP8266 Arduino library. 333 | 334 | 335 | ### Contributions and thanks 336 | The support and help I got from the community has been nothing short of phenomenal. I can't thank you guys enough. This is my first real attept in developing open source stuff and I must say, now I understand why people are so dedicated to it, it is because of all the wonderful people involved. 337 | 338 | __THANK YOU__ 339 | 340 | [Shawn A](https://github.com/tablatronix) 341 | 342 | [Maximiliano Duarte](https://github.com/domonetic) 343 | 344 | [alltheblinkythings](https://github.com/alltheblinkythings) 345 | 346 | [Niklas Wall](https://github.com/niklaswall) 347 | 348 | [Jakub Piasecki](https://github.com/zaporylie) 349 | 350 | [Peter Allan](https://github.com/alwynallan) 351 | 352 | [John Little](https://github.com/j0hnlittle) 353 | 354 | [markaswift](https://github.com/markaswift) 355 | 356 | [franklinvv](https://github.com/franklinvv) 357 | 358 | [Alberto Ricci Bitti](https://github.com/riccibitti) 359 | 360 | [SebiPanther](https://github.com/SebiPanther) 361 | 362 | [jonathanendersby](https://github.com/jonathanendersby) 363 | 364 | [walthercarsten](https://github.com/walthercarsten) 365 | 366 | Sorry if i have missed anyone. 367 | 368 | #### Inspiration 369 | - http://www.esp8266.com/viewtopic.php?f=29&t=2520 370 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/WiFiManager.h: -------------------------------------------------------------------------------- 1 | /************************************************************** 2 | WiFiManager is a library for the ESP8266/Arduino platform 3 | (https://github.com/esp8266/Arduino) to enable easy 4 | configuration and reconfiguration of WiFi credentials using a Captive Portal 5 | inspired by: 6 | http://www.esp8266.com/viewtopic.php?f=29&t=2520 7 | https://github.com/chriscook8/esp-arduino-apboot 8 | https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced 9 | Built by AlexT https://github.com/tzapu 10 | Licensed under MIT license 11 | **************************************************************/ 12 | 13 | #ifndef WiFiManager_h 14 | #define WiFiManager_h 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | extern "C" { 22 | #include "user_interface.h" 23 | } 24 | 25 | const char HTTP_HEAD[] PROGMEM = "{v}"; 26 | const char HTTP_STYLE[] PROGMEM = ""; 27 | const char HTTP_SCRIPT[] PROGMEM = ""; 28 | const char HTTP_HEAD_END[] PROGMEM = "
"; 29 | const char HTTP_PORTAL_OPTIONS[] PROGMEM = "



"; 30 | const char HTTP_ITEM[] PROGMEM = "
{v} {r}%
"; 31 | const char HTTP_FORM_START[] PROGMEM = "


"; 32 | const char HTTP_FORM_PARAM[] PROGMEM = "
"; 33 | const char HTTP_FORM_END[] PROGMEM = "
"; 34 | const char HTTP_SCAN_LINK[] PROGMEM = "
"; 35 | const char HTTP_SAVED[] PROGMEM = "
Credentials Saved
Trying to connect ESP to network.
If it fails reconnect to AP to try again
"; 36 | const char HTTP_END[] PROGMEM = "
"; 37 | 38 | #define WIFI_MANAGER_MAX_PARAMS 10 39 | 40 | class WiFiManagerParameter { 41 | public: 42 | WiFiManagerParameter(const char *custom); 43 | WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length); 44 | WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); 45 | 46 | const char *getID(); 47 | const char *getValue(); 48 | const char *getPlaceholder(); 49 | int getValueLength(); 50 | const char *getCustomHTML(); 51 | private: 52 | const char *_id; 53 | const char *_placeholder; 54 | char *_value; 55 | int _length; 56 | const char *_customHTML; 57 | 58 | void init(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); 59 | 60 | friend class WiFiManager; 61 | }; 62 | 63 | 64 | class WiFiManager 65 | { 66 | public: 67 | WiFiManager(); 68 | 69 | boolean autoConnect(); 70 | boolean autoConnect(char const *apName, char const *apPassword = NULL); 71 | 72 | //if you want to always start the config portal, without trying to connect first 73 | boolean startConfigPortal(char const *apName, char const *apPassword = NULL); 74 | 75 | // get the AP name of the config portal, so it can be used in the callback 76 | String getConfigPortalSSID(); 77 | 78 | void resetSettings(); 79 | 80 | //sets timeout before webserver loop ends and exits even if there has been no setup. 81 | //usefully for devices that failed to connect at some point and got stuck in a webserver loop 82 | //in seconds setConfigPortalTimeout is a new name for setTimeout 83 | void setConfigPortalTimeout(unsigned long seconds); 84 | void setTimeout(unsigned long seconds); 85 | 86 | //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects 87 | void setConnectTimeout(unsigned long seconds); 88 | 89 | 90 | void setDebugOutput(boolean debug); 91 | //defaults to not showing anything under 8% signal quality if called 92 | void setMinimumSignalQuality(int quality = 8); 93 | //sets a custom ip /gateway /subnet configuration 94 | void setAPStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); 95 | //sets config for a static IP 96 | void setSTAStaticIPConfig(IPAddress ip, IPAddress gw, IPAddress sn); 97 | //called when AP mode and config portal is started 98 | void setAPCallback( void (*func)(WiFiManager*) ); 99 | //called when settings have been changed and connection was successful 100 | void setSaveConfigCallback( void (*func)(void) ); 101 | //adds a custom parameter 102 | void addParameter(WiFiManagerParameter *p); 103 | //if this is set, it will exit after config, even if connection is unsucessful. 104 | void setBreakAfterConfig(boolean shouldBreak); 105 | //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins) 106 | //TODO 107 | //if this is set, customise style 108 | void setCustomHeadElement(const char* element); 109 | //if this is true, remove duplicated Access Points - defaut true 110 | void setRemoveDuplicateAPs(boolean removeDuplicates); 111 | 112 | private: 113 | std::unique_ptr dnsServer; 114 | std::unique_ptr server; 115 | 116 | //const int WM_DONE = 0; 117 | //const int WM_WAIT = 10; 118 | 119 | //const String HTTP_HEAD = "{v}"; 120 | 121 | void setupConfigPortal(); 122 | void startWPS(); 123 | 124 | const char* _apName = "no-net"; 125 | const char* _apPassword = NULL; 126 | String _ssid = ""; 127 | String _pass = ""; 128 | unsigned long _configPortalTimeout = 0; 129 | unsigned long _connectTimeout = 0; 130 | unsigned long _configPortalStart = 0; 131 | 132 | IPAddress _ap_static_ip; 133 | IPAddress _ap_static_gw; 134 | IPAddress _ap_static_sn; 135 | IPAddress _sta_static_ip; 136 | IPAddress _sta_static_gw; 137 | IPAddress _sta_static_sn; 138 | 139 | int _paramsCount = 0; 140 | int _minimumQuality = -1; 141 | boolean _removeDuplicateAPs = true; 142 | boolean _shouldBreakAfterConfig = false; 143 | boolean _tryWPS = false; 144 | 145 | const char* _customHeadElement = ""; 146 | 147 | //String getEEPROMString(int start, int len); 148 | //void setEEPROMString(int start, int len, String string); 149 | 150 | int status = WL_IDLE_STATUS; 151 | int connectWifi(String ssid, String pass); 152 | uint8_t waitForConnectResult(); 153 | 154 | void handleRoot(); 155 | void handleWifi(boolean scan); 156 | void handleWifiSave(); 157 | void handleInfo(); 158 | void handleReset(); 159 | void handleNotFound(); 160 | void handle204(); 161 | boolean captivePortal(); 162 | 163 | // DNS server 164 | const byte DNS_PORT = 53; 165 | 166 | //helpers 167 | int getRSSIasQuality(int RSSI); 168 | boolean isIp(String str); 169 | String toStringIp(IPAddress ip); 170 | 171 | boolean connect; 172 | boolean _debug = true; 173 | 174 | void (*_apcallback)(WiFiManager*) = NULL; 175 | void (*_savecallback)(void) = NULL; 176 | 177 | WiFiManagerParameter* _params[WIFI_MANAGER_MAX_PARAMS]; 178 | 179 | template 180 | void DEBUG_WM(Generic text); 181 | 182 | template 183 | auto optionalIPFromString(T *obj, const char *s) -> decltype( obj->fromString(s) ) { 184 | return obj->fromString(s); 185 | } 186 | auto optionalIPFromString(...) -> bool { 187 | DEBUG_WM("NO fromString METHOD ON IPAddress, you need ESP8266 core 2.1.0 or newer for Custom IP configuration to work."); 188 | return false; 189 | } 190 | }; 191 | 192 | #endif 193 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/AutoConnect/AutoConnect.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | 8 | 9 | void setup() { 10 | // put your setup code here, to run once: 11 | Serial.begin(115200); 12 | 13 | //WiFiManager 14 | //Local intialization. Once its business is done, there is no need to keep it around 15 | WiFiManager wifiManager; 16 | //reset saved settings 17 | //wifiManager.resetSettings(); 18 | 19 | //set custom ip for portal 20 | //wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); 21 | 22 | //fetches ssid and pass from eeprom and tries to connect 23 | //if it does not connect it starts an access point with the specified name 24 | //here "AutoConnectAP" 25 | //and goes into a blocking loop awaiting configuration 26 | wifiManager.autoConnect("AutoConnectAP"); 27 | //or use this for auto generated name ESP + ChipID 28 | //wifiManager.autoConnect(); 29 | 30 | 31 | //if you get here you have connected to the WiFi 32 | Serial.println("connected...yeey :)"); 33 | } 34 | 35 | void loop() { 36 | // put your main code here, to run repeatedly: 37 | 38 | } 39 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino: -------------------------------------------------------------------------------- 1 | #include //this needs to be first, or it all crashes and burns... 2 | 3 | #include //https://github.com/esp8266/Arduino 4 | 5 | //needed for library 6 | #include 7 | #include 8 | #include //https://github.com/tzapu/WiFiManager 9 | 10 | #include //https://github.com/bblanchon/ArduinoJson 11 | 12 | //define your default values here, if there are different values in config.json, they are overwritten. 13 | char mqtt_server[40]; 14 | char mqtt_port[6] = "8080"; 15 | char blynk_token[34] = "YOUR_BLYNK_TOKEN"; 16 | 17 | //flag for saving data 18 | bool shouldSaveConfig = false; 19 | 20 | //callback notifying us of the need to save config 21 | void saveConfigCallback () { 22 | Serial.println("Should save config"); 23 | shouldSaveConfig = true; 24 | } 25 | 26 | 27 | void setup() { 28 | // put your setup code here, to run once: 29 | Serial.begin(115200); 30 | Serial.println(); 31 | 32 | //clean FS, for testing 33 | //SPIFFS.format(); 34 | 35 | //read configuration from FS json 36 | Serial.println("mounting FS..."); 37 | 38 | if (SPIFFS.begin()) { 39 | Serial.println("mounted file system"); 40 | if (SPIFFS.exists("/config.json")) { 41 | //file exists, reading and loading 42 | Serial.println("reading config file"); 43 | File configFile = SPIFFS.open("/config.json", "r"); 44 | if (configFile) { 45 | Serial.println("opened config file"); 46 | size_t size = configFile.size(); 47 | // Allocate a buffer to store contents of the file. 48 | std::unique_ptr buf(new char[size]); 49 | 50 | configFile.readBytes(buf.get(), size); 51 | DynamicJsonBuffer jsonBuffer; 52 | JsonObject& json = jsonBuffer.parseObject(buf.get()); 53 | json.printTo(Serial); 54 | if (json.success()) { 55 | Serial.println("\nparsed json"); 56 | 57 | strcpy(mqtt_server, json["mqtt_server"]); 58 | strcpy(mqtt_port, json["mqtt_port"]); 59 | strcpy(blynk_token, json["blynk_token"]); 60 | 61 | } else { 62 | Serial.println("failed to load json config"); 63 | } 64 | } 65 | } 66 | } else { 67 | Serial.println("failed to mount FS"); 68 | } 69 | //end read 70 | 71 | 72 | 73 | // The extra parameters to be configured (can be either global or just in the setup) 74 | // After connecting, parameter.getValue() will get you the configured value 75 | // id/name placeholder/prompt default length 76 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); 77 | WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 5); 78 | WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 32); 79 | 80 | //WiFiManager 81 | //Local intialization. Once its business is done, there is no need to keep it around 82 | WiFiManager wifiManager; 83 | 84 | //set config save notify callback 85 | wifiManager.setSaveConfigCallback(saveConfigCallback); 86 | 87 | //set static ip 88 | wifiManager.setSTAStaticIPConfig(IPAddress(10,0,1,99), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); 89 | 90 | //add all your parameters here 91 | wifiManager.addParameter(&custom_mqtt_server); 92 | wifiManager.addParameter(&custom_mqtt_port); 93 | wifiManager.addParameter(&custom_blynk_token); 94 | 95 | //reset settings - for testing 96 | //wifiManager.resetSettings(); 97 | 98 | //set minimu quality of signal so it ignores AP's under that quality 99 | //defaults to 8% 100 | //wifiManager.setMinimumSignalQuality(); 101 | 102 | //sets timeout until configuration portal gets turned off 103 | //useful to make it all retry or go to sleep 104 | //in seconds 105 | //wifiManager.setTimeout(120); 106 | 107 | //fetches ssid and pass and tries to connect 108 | //if it does not connect it starts an access point with the specified name 109 | //here "AutoConnectAP" 110 | //and goes into a blocking loop awaiting configuration 111 | if (!wifiManager.autoConnect("AutoConnectAP", "password")) { 112 | Serial.println("failed to connect and hit timeout"); 113 | delay(3000); 114 | //reset and try again, or maybe put it to deep sleep 115 | ESP.reset(); 116 | delay(5000); 117 | } 118 | 119 | //if you get here you have connected to the WiFi 120 | Serial.println("connected...yeey :)"); 121 | 122 | //read updated parameters 123 | strcpy(mqtt_server, custom_mqtt_server.getValue()); 124 | strcpy(mqtt_port, custom_mqtt_port.getValue()); 125 | strcpy(blynk_token, custom_blynk_token.getValue()); 126 | 127 | //save the custom parameters to FS 128 | if (shouldSaveConfig) { 129 | Serial.println("saving config"); 130 | DynamicJsonBuffer jsonBuffer; 131 | JsonObject& json = jsonBuffer.createObject(); 132 | json["mqtt_server"] = mqtt_server; 133 | json["mqtt_port"] = mqtt_port; 134 | json["blynk_token"] = blynk_token; 135 | 136 | File configFile = SPIFFS.open("/config.json", "w"); 137 | if (!configFile) { 138 | Serial.println("failed to open config file for writing"); 139 | } 140 | 141 | json.printTo(Serial); 142 | json.printTo(configFile); 143 | configFile.close(); 144 | //end save 145 | } 146 | 147 | Serial.println("local ip"); 148 | Serial.println(WiFi.localIP()); 149 | 150 | } 151 | 152 | void loop() { 153 | // put your main code here, to run repeatedly: 154 | 155 | 156 | } 157 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/AutoConnectWithFSParametersAndCustomIP/AutoConnectWithFSParametersAndCustomIP.ino: -------------------------------------------------------------------------------- 1 | #include //this needs to be first, or it all crashes and burns... 2 | 3 | #include //https://github.com/esp8266/Arduino 4 | 5 | //needed for library 6 | #include 7 | #include 8 | #include //https://github.com/tzapu/WiFiManager 9 | 10 | #include //https://github.com/bblanchon/ArduinoJson 11 | 12 | //define your default values here, if there are different values in config.json, they are overwritten. 13 | //length should be max size + 1 14 | char mqtt_server[40]; 15 | char mqtt_port[6] = "8080"; 16 | char blynk_token[33] = "YOUR_BLYNK_TOKEN"; 17 | //default custom static IP 18 | char static_ip[16] = "10.0.1.56"; 19 | char static_gw[16] = "10.0.1.1"; 20 | char static_sn[16] = "255.255.255.0"; 21 | 22 | //flag for saving data 23 | bool shouldSaveConfig = false; 24 | 25 | //callback notifying us of the need to save config 26 | void saveConfigCallback () { 27 | Serial.println("Should save config"); 28 | shouldSaveConfig = true; 29 | } 30 | 31 | void setup() { 32 | // put your setup code here, to run once: 33 | Serial.begin(115200); 34 | Serial.println(); 35 | 36 | //clean FS, for testing 37 | //SPIFFS.format(); 38 | 39 | //read configuration from FS json 40 | Serial.println("mounting FS..."); 41 | 42 | if (SPIFFS.begin()) { 43 | Serial.println("mounted file system"); 44 | if (SPIFFS.exists("/config.json")) { 45 | //file exists, reading and loading 46 | Serial.println("reading config file"); 47 | File configFile = SPIFFS.open("/config.json", "r"); 48 | if (configFile) { 49 | Serial.println("opened config file"); 50 | size_t size = configFile.size(); 51 | // Allocate a buffer to store contents of the file. 52 | std::unique_ptr buf(new char[size]); 53 | 54 | configFile.readBytes(buf.get(), size); 55 | DynamicJsonBuffer jsonBuffer; 56 | JsonObject& json = jsonBuffer.parseObject(buf.get()); 57 | json.printTo(Serial); 58 | if (json.success()) { 59 | Serial.println("\nparsed json"); 60 | 61 | strcpy(mqtt_server, json["mqtt_server"]); 62 | strcpy(mqtt_port, json["mqtt_port"]); 63 | strcpy(blynk_token, json["blynk_token"]); 64 | 65 | if(json["ip"]) { 66 | Serial.println("setting custom ip from config"); 67 | //static_ip = json["ip"]; 68 | strcpy(static_ip, json["ip"]); 69 | strcpy(static_gw, json["gateway"]); 70 | strcpy(static_sn, json["subnet"]); 71 | //strcat(static_ip, json["ip"]); 72 | //static_gw = json["gateway"]; 73 | //static_sn = json["subnet"]; 74 | Serial.println(static_ip); 75 | /* Serial.println("converting ip"); 76 | IPAddress ip = ipFromCharArray(static_ip); 77 | Serial.println(ip);*/ 78 | } else { 79 | Serial.println("no custom ip in config"); 80 | } 81 | } else { 82 | Serial.println("failed to load json config"); 83 | } 84 | } 85 | } 86 | } else { 87 | Serial.println("failed to mount FS"); 88 | } 89 | //end read 90 | Serial.println(static_ip); 91 | Serial.println(blynk_token); 92 | Serial.println(mqtt_server); 93 | 94 | 95 | // The extra parameters to be configured (can be either global or just in the setup) 96 | // After connecting, parameter.getValue() will get you the configured value 97 | // id/name placeholder/prompt default length 98 | WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); 99 | WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 5); 100 | WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34); 101 | 102 | //WiFiManager 103 | //Local intialization. Once its business is done, there is no need to keep it around 104 | WiFiManager wifiManager; 105 | 106 | //set config save notify callback 107 | wifiManager.setSaveConfigCallback(saveConfigCallback); 108 | 109 | //set static ip 110 | IPAddress _ip,_gw,_sn; 111 | _ip.fromString(static_ip); 112 | _gw.fromString(static_gw); 113 | _sn.fromString(static_sn); 114 | 115 | wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn); 116 | 117 | //add all your parameters here 118 | wifiManager.addParameter(&custom_mqtt_server); 119 | wifiManager.addParameter(&custom_mqtt_port); 120 | wifiManager.addParameter(&custom_blynk_token); 121 | 122 | //reset settings - for testing 123 | //wifiManager.resetSettings(); 124 | 125 | //set minimu quality of signal so it ignores AP's under that quality 126 | //defaults to 8% 127 | wifiManager.setMinimumSignalQuality(); 128 | 129 | //sets timeout until configuration portal gets turned off 130 | //useful to make it all retry or go to sleep 131 | //in seconds 132 | //wifiManager.setTimeout(120); 133 | 134 | //fetches ssid and pass and tries to connect 135 | //if it does not connect it starts an access point with the specified name 136 | //here "AutoConnectAP" 137 | //and goes into a blocking loop awaiting configuration 138 | if (!wifiManager.autoConnect("AutoConnectAP", "password")) { 139 | Serial.println("failed to connect and hit timeout"); 140 | delay(3000); 141 | //reset and try again, or maybe put it to deep sleep 142 | ESP.reset(); 143 | delay(5000); 144 | } 145 | 146 | //if you get here you have connected to the WiFi 147 | Serial.println("connected...yeey :)"); 148 | 149 | //read updated parameters 150 | strcpy(mqtt_server, custom_mqtt_server.getValue()); 151 | strcpy(mqtt_port, custom_mqtt_port.getValue()); 152 | strcpy(blynk_token, custom_blynk_token.getValue()); 153 | 154 | //save the custom parameters to FS 155 | if (shouldSaveConfig) { 156 | Serial.println("saving config"); 157 | DynamicJsonBuffer jsonBuffer; 158 | JsonObject& json = jsonBuffer.createObject(); 159 | json["mqtt_server"] = mqtt_server; 160 | json["mqtt_port"] = mqtt_port; 161 | json["blynk_token"] = blynk_token; 162 | 163 | json["ip"] = WiFi.localIP().toString(); 164 | json["gateway"] = WiFi.gatewayIP().toString(); 165 | json["subnet"] = WiFi.subnetMask().toString(); 166 | 167 | File configFile = SPIFFS.open("/config.json", "w"); 168 | if (!configFile) { 169 | Serial.println("failed to open config file for writing"); 170 | } 171 | 172 | json.prettyPrintTo(Serial); 173 | json.printTo(configFile); 174 | configFile.close(); 175 | //end save 176 | } 177 | 178 | Serial.println("local ip"); 179 | Serial.println(WiFi.localIP()); 180 | Serial.println(WiFi.gatewayIP()); 181 | Serial.println(WiFi.subnetMask()); 182 | } 183 | 184 | void loop() { 185 | // put your main code here, to run repeatedly: 186 | 187 | 188 | } 189 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/AutoConnectWithFeedback/AutoConnectWithFeedback.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include "WiFiManager.h" //https://github.com/tzapu/WiFiManager 7 | 8 | void configModeCallback (WiFiManager *myWiFiManager) { 9 | Serial.println("Entered config mode"); 10 | Serial.println(WiFi.softAPIP()); 11 | //if you used auto generated SSID, print it 12 | Serial.println(myWiFiManager->getConfigPortalSSID()); 13 | } 14 | 15 | void setup() { 16 | // put your setup code here, to run once: 17 | Serial.begin(115200); 18 | 19 | //WiFiManager 20 | //Local intialization. Once its business is done, there is no need to keep it around 21 | WiFiManager wifiManager; 22 | //reset settings - for testing 23 | //wifiManager.resetSettings(); 24 | 25 | //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode 26 | wifiManager.setAPCallback(configModeCallback); 27 | 28 | //fetches ssid and pass and tries to connect 29 | //if it does not connect it starts an access point with the specified name 30 | //here "AutoConnectAP" 31 | //and goes into a blocking loop awaiting configuration 32 | if(!wifiManager.autoConnect()) { 33 | Serial.println("failed to connect and hit timeout"); 34 | //reset and try again, or maybe put it to deep sleep 35 | ESP.reset(); 36 | delay(1000); 37 | } 38 | 39 | //if you get here you have connected to the WiFi 40 | Serial.println("connected...yeey :)"); 41 | 42 | } 43 | 44 | void loop() { 45 | // put your main code here, to run repeatedly: 46 | 47 | } 48 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/AutoConnectWithFeedbackLED/AutoConnectWithFeedbackLED.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | 8 | //for LED status 9 | #include 10 | Ticker ticker; 11 | 12 | void tick() 13 | { 14 | //toggle state 15 | int state = digitalRead(BUILTIN_LED); // get the current state of GPIO1 pin 16 | digitalWrite(BUILTIN_LED, !state); // set pin to the opposite state 17 | } 18 | 19 | //gets called when WiFiManager enters configuration mode 20 | void configModeCallback (WiFiManager *myWiFiManager) { 21 | Serial.println("Entered config mode"); 22 | Serial.println(WiFi.softAPIP()); 23 | //if you used auto generated SSID, print it 24 | Serial.println(myWiFiManager->getConfigPortalSSID()); 25 | //entered config mode, make led toggle faster 26 | ticker.attach(0.2, tick); 27 | } 28 | 29 | void setup() { 30 | // put your setup code here, to run once: 31 | Serial.begin(115200); 32 | 33 | //set led pin as output 34 | pinMode(BUILTIN_LED, OUTPUT); 35 | // start ticker with 0.5 because we start in AP mode and try to connect 36 | ticker.attach(0.6, tick); 37 | 38 | //WiFiManager 39 | //Local intialization. Once its business is done, there is no need to keep it around 40 | WiFiManager wifiManager; 41 | //reset settings - for testing 42 | //wifiManager.resetSettings(); 43 | 44 | //set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode 45 | wifiManager.setAPCallback(configModeCallback); 46 | 47 | //fetches ssid and pass and tries to connect 48 | //if it does not connect it starts an access point with the specified name 49 | //here "AutoConnectAP" 50 | //and goes into a blocking loop awaiting configuration 51 | if (!wifiManager.autoConnect()) { 52 | Serial.println("failed to connect and hit timeout"); 53 | //reset and try again, or maybe put it to deep sleep 54 | ESP.reset(); 55 | delay(1000); 56 | } 57 | 58 | //if you get here you have connected to the WiFi 59 | Serial.println("connected...yeey :)"); 60 | ticker.detach(); 61 | //keep LED on 62 | digitalWrite(BUILTIN_LED, LOW); 63 | } 64 | 65 | void loop() { 66 | // put your main code here, to run repeatedly: 67 | 68 | } 69 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/AutoConnectWithReset/AutoConnectWithReset.ino: -------------------------------------------------------------------------------- 1 | #include //this needs to be first, or it all crashes and burns... 2 | 3 | #include //https://github.com/esp8266/Arduino 4 | 5 | //needed for library 6 | #include 7 | #include 8 | #include //https://github.com/tzapu/WiFiManager 9 | 10 | void setup() { 11 | // put your setup code here, to run once: 12 | Serial.begin(115200); 13 | Serial.println(); 14 | 15 | //WiFiManager 16 | //Local intialization. Once its business is done, there is no need to keep it around 17 | WiFiManager wifiManager; 18 | 19 | //exit after config instead of connecting 20 | wifiManager.setBreakAfterConfig(true); 21 | 22 | //reset settings - for testing 23 | //wifiManager.resetSettings(); 24 | 25 | 26 | //tries to connect to last known settings 27 | //if it does not connect it starts an access point with the specified name 28 | //here "AutoConnectAP" with password "password" 29 | //and goes into a blocking loop awaiting configuration 30 | if (!wifiManager.autoConnect("AutoConnectAP", "password")) { 31 | Serial.println("failed to connect, we should reset as see if it connects"); 32 | delay(3000); 33 | ESP.reset(); 34 | delay(5000); 35 | } 36 | 37 | //if you get here you have connected to the WiFi 38 | Serial.println("connected...yeey :)"); 39 | 40 | 41 | Serial.println("local ip"); 42 | Serial.println(WiFi.localIP()); 43 | } 44 | 45 | void loop() { 46 | // put your main code here, to run repeatedly: 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/AutoConnectWithStaticIP/AutoConnectWithStaticIP.ino: -------------------------------------------------------------------------------- 1 | #include //this needs to be first, or it all crashes and burns... 2 | 3 | #include //https://github.com/esp8266/Arduino 4 | 5 | //needed for library 6 | #include 7 | #include 8 | #include //https://github.com/tzapu/WiFiManager 9 | 10 | 11 | /************************************************************************************** 12 | * this example shows how to set a static IP configuration for the ESP 13 | * although the IP shows in the config portal, the changes will revert 14 | * to the IP set in the source file. 15 | * if you want the ability to configure and persist the new IP configuration 16 | * look at the FS examples, which save the config to file 17 | *************************************************************************************/ 18 | 19 | 20 | 21 | //default custom static IP 22 | //char static_ip[16] = "10.0.1.59"; 23 | //char static_gw[16] = "10.0.1.1"; 24 | //char static_sn[16] = "255.255.255.0"; 25 | 26 | void setup() { 27 | // put your setup code here, to run once: 28 | Serial.begin(115200); 29 | Serial.println(); 30 | 31 | //WiFiManager 32 | //Local intialization. Once its business is done, there is no need to keep it around 33 | WiFiManager wifiManager; 34 | 35 | //reset settings - for testing 36 | //wifiManager.resetSettings(); 37 | 38 | //set static ip 39 | //the commented bit only works for ESP8266 core 2.1.0 or newer 40 | /*IPAddress _ip,_gw,_sn; 41 | _ip.fromString(static_ip); 42 | _gw.fromString(static_gw); 43 | _sn.fromString(static_sn); 44 | */ 45 | IPAddress _ip = IPAddress(10, 0, 1, 78); 46 | IPAddress _gw = IPAddress(10, 0, 1, 1); 47 | IPAddress _sn = IPAddress(255, 255, 255, 0); 48 | 49 | wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn); 50 | 51 | 52 | //tries to connect to last known settings 53 | //if it does not connect it starts an access point with the specified name 54 | //here "AutoConnectAP" with password "password" 55 | //and goes into a blocking loop awaiting configuration 56 | if (!wifiManager.autoConnect("AutoConnectAP", "password")) { 57 | Serial.println("failed to connect, we should reset as see if it connects"); 58 | delay(3000); 59 | ESP.reset(); 60 | delay(5000); 61 | } 62 | 63 | //if you get here you have connected to the WiFi 64 | Serial.println("connected...yeey :)"); 65 | 66 | 67 | Serial.println("local ip"); 68 | Serial.println(WiFi.localIP()); 69 | } 70 | 71 | void loop() { 72 | // put your main code here, to run repeatedly: 73 | 74 | 75 | } 76 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/AutoConnectWithTimeout/AutoConnectWithTimeout.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | 8 | 9 | 10 | void setup() { 11 | // put your setup code here, to run once: 12 | Serial.begin(115200); 13 | 14 | //WiFiManager 15 | //Local intialization. Once its business is done, there is no need to keep it around 16 | WiFiManager wifiManager; 17 | //reset settings - for testing 18 | //wifiManager.resetSettings(); 19 | 20 | //sets timeout until configuration portal gets turned off 21 | //useful to make it all retry or go to sleep 22 | //in seconds 23 | wifiManager.setTimeout(180); 24 | 25 | //fetches ssid and pass and tries to connect 26 | //if it does not connect it starts an access point with the specified name 27 | //here "AutoConnectAP" 28 | //and goes into a blocking loop awaiting configuration 29 | if(!wifiManager.autoConnect("AutoConnectAP")) { 30 | Serial.println("failed to connect and hit timeout"); 31 | delay(3000); 32 | //reset and try again, or maybe put it to deep sleep 33 | ESP.reset(); 34 | delay(5000); 35 | } 36 | 37 | //if you get here you have connected to the WiFi 38 | Serial.println("connected...yeey :)"); 39 | 40 | } 41 | 42 | void loop() { 43 | // put your main code here, to run repeatedly: 44 | 45 | } 46 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/examples/OnDemandConfigPortal/OnDemandConfigPortal.ino: -------------------------------------------------------------------------------- 1 | #include //https://github.com/esp8266/Arduino 2 | 3 | //needed for library 4 | #include 5 | #include 6 | #include //https://github.com/tzapu/WiFiManager 7 | 8 | // select wich pin will trigger the configuraton portal when set to LOW 9 | // ESP-01 users please note: the only pins available (0 and 2), are shared 10 | // with the bootloader, so always set them HIGH at power-up 11 | #define TRIGGER_PIN 0 12 | 13 | 14 | void setup() { 15 | // put your setup code here, to run once: 16 | Serial.begin(115200); 17 | Serial.println("\n Starting"); 18 | 19 | pinMode(TRIGGER_PIN, INPUT); 20 | } 21 | 22 | 23 | void loop() { 24 | // is configuration portal requested? 25 | if ( digitalRead(TRIGGER_PIN) == LOW ) { 26 | //WiFiManager 27 | //Local intialization. Once its business is done, there is no need to keep it around 28 | WiFiManager wifiManager; 29 | 30 | //reset settings - for testing 31 | //wifiManager.resetSettings(); 32 | 33 | //sets timeout until configuration portal gets turned off 34 | //useful to make it all retry or go to sleep 35 | //in seconds 36 | //wifiManager.setTimeout(120); 37 | 38 | //it starts an access point with the specified name 39 | //here "AutoConnectAP" 40 | //and goes into a blocking loop awaiting configuration 41 | 42 | //WITHOUT THIS THE AP DOES NOT SEEM TO WORK PROPERLY WITH SDK 1.5 , update to at least 1.5.1 43 | //WiFi.mode(WIFI_STA); 44 | 45 | if (!wifiManager.startConfigPortal("OnDemandAP")) { 46 | Serial.println("failed to connect and hit timeout"); 47 | delay(3000); 48 | //reset and try again, or maybe put it to deep sleep 49 | ESP.reset(); 50 | delay(5000); 51 | } 52 | 53 | //if you get here you have connected to the WiFi 54 | Serial.println("connected...yeey :)"); 55 | } 56 | 57 | 58 | // put your main code here, to run repeatedly: 59 | 60 | } 61 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/extras/WiFiManager.template.html: -------------------------------------------------------------------------------- 1 | {v} 2 | 3 | 4 | 5 |
6 | 14 | 15 | 19 | 20 |
{v} {r}%
21 |
PMisa 100%
22 | 23 |
PMisa 8%
24 | 25 | 26 | 27 |
28 | 29 | 30 |


31 |
32 |
33 |

34 |
35 |
36 | 37 |
38 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For WifiManager 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | WiFiManager KEYWORD1 10 | WiFiManagerParameter KEYWORD1 11 | 12 | 13 | ####################################### 14 | # Methods and Functions (KEYWORD2) 15 | ####################################### 16 | autoConnect KEYWORD2 17 | getSSID KEYWORD2 18 | getPassword KEYWORD2 19 | getConfigPortalSSID KEYWORD2 20 | resetSettings KEYWORD2 21 | setConfigPortalTimeout KEYWORD2 22 | setConnectTimeout KEYWORD2 23 | setDebugOutput KEYWORD2 24 | setMinimumSignalQuality KEYWORD2 25 | setAPStaticIPConfig KEYWORD2 26 | setSTAStaticIPConfig KEYWORD2 27 | setAPCallback KEYWORD2 28 | setSaveConfigCallback KEYWORD2 29 | addParameter KEYWORD2 30 | getID KEYWORD2 31 | getValue KEYWORD2 32 | getPlaceholder KEYWORD2 33 | getValueLength KEYWORD2 34 | 35 | ####################################### 36 | # Constants (LITERAL1) 37 | ####################################### 38 | 39 | # LITERAL1 40 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WifiManager", 3 | "keywords": "wifi, wi-fi", 4 | "description": "ESP8266 WiFi Connection manager with fallback web configuration portal", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/tzapu/WiFiManager.git" 9 | }, 10 | "frameworks": "arduino", 11 | "platforms": "espressif8266", 12 | "version": "0.12" 13 | } 14 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/library.properties: -------------------------------------------------------------------------------- 1 | name=WiFiManager 2 | version=0.12 3 | author=tzapu 4 | maintainer=tzapu 5 | sentence=ESP8266 WiFi Connection manager with fallback web configuration portal 6 | paragraph=Library for configuring ESP8266 modules WiFi credentials at runtime. 7 | category=Communication 8 | url=https://github.com/tzapu/WiFiManager.git 9 | architectures=esp8266 10 | -------------------------------------------------------------------------------- /airmonitor_device/lib/WifiManager/travis/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function build_examples() 4 | { 5 | # track the exit code for this platform 6 | local exit_code=0 7 | # loop through results and add them to the array 8 | examples=($(find $PWD/examples/ -name "*.pde" -o -name "*.ino")) 9 | 10 | # get the last example in the array 11 | local last="${examples[@]:(-1)}" 12 | 13 | # loop through example sketches 14 | for example in "${examples[@]}"; do 15 | 16 | # store the full path to the example's sketch directory 17 | local example_dir=$(dirname $example) 18 | 19 | # store the filename for the example without the path 20 | local example_file=$(basename $example) 21 | 22 | echo "$example_file: " 23 | local sketch="$example_dir/$example_file" 24 | echo "$sketch" 25 | #arduino -v --verbose-build --verify $sketch 26 | 27 | # verify the example, and save stdout & stderr to a variable 28 | # we have to avoid reading the exit code of local: 29 | # "when declaring a local variable in a function, the local acts as a command in its own right" 30 | local build_stdout 31 | build_stdout=$(arduino --verify $sketch 2>&1) 32 | 33 | # echo output if the build failed 34 | if [ $? -ne 0 ]; then 35 | # heavy X 36 | echo -e "\xe2\x9c\x96" 37 | echo -e "----------------------------- DEBUG OUTPUT -----------------------------\n" 38 | echo "$build_stdout" 39 | echo -e "\n------------------------------------------------------------------------\n" 40 | 41 | # mark as fail 42 | exit_code=1 43 | 44 | else 45 | # heavy checkmark 46 | echo -e "\xe2\x9c\x93" 47 | fi 48 | done 49 | 50 | return $exit_code 51 | } 52 | -------------------------------------------------------------------------------- /airmonitor_device/lib/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for the project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link to executable file. 4 | 5 | The source code of each library should be placed in separate directory, like 6 | "lib/private_lib/[here are source files]". 7 | 8 | For example, see how can be organized `Foo` and `Bar` libraries: 9 | 10 | |--lib 11 | | |--Bar 12 | | | |--docs 13 | | | |--examples 14 | | | |--src 15 | | | |- Bar.c 16 | | | |- Bar.h 17 | | |--Foo 18 | | | |- Foo.c 19 | | | |- Foo.h 20 | | |- readme.txt --> THIS FILE 21 | |- platformio.ini 22 | |--src 23 | |- main.c 24 | 25 | Then in `src/main.c` you should use: 26 | 27 | #include 28 | #include 29 | 30 | // rest H/C/CPP code 31 | 32 | PlatformIO will find your libraries automatically, configure preprocessor's 33 | include paths and build them. 34 | 35 | More information about PlatformIO Library Dependency Finder 36 | - http://docs.platformio.org/page/librarymanager/ldf.html 37 | -------------------------------------------------------------------------------- /airmonitor_device/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | 11 | [env:nodemcuv2] 12 | platform = espressif8266 13 | board = nodemcuv2 14 | framework = arduino 15 | -------------------------------------------------------------------------------- /airmonitor_device/src/aliyun_iot.cpp: -------------------------------------------------------------------------------- 1 | #include "aliyun_iot.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static WiFiClient mqttWiFiClient; 8 | static PubSubClient AliyunMQTTclient(mqttWiFiClient); 9 | 10 | static String productKey; 11 | static String deviceName; 12 | static String deviceSecret; 13 | static String mqttBroker; 14 | static IPAddress mqttBrokerIP; 15 | static String mqttClientID; 16 | static String mqttUsername; 17 | static String mqttPassword; 18 | static String mqttPostPropertyTopic; 19 | 20 | void AliyunIoT_Init(String& pk, String& dn, String& ds) { 21 | productKey = pk; 22 | deviceName = dn; 23 | deviceSecret = ds; 24 | 25 | // 获取 MQTT 服务器地址 26 | mqttBroker = F("%pk%.iot-as-mqtt.cn-shanghai.aliyuncs.com"); 27 | mqttBroker.replace("%pk%", pk); 28 | String host = mqttBroker; 29 | host.toLowerCase(); 30 | WiFi.hostByName(host.c_str(), mqttBrokerIP); 31 | 32 | // 生成 MQTT ClientID 33 | String timestamp = F(""); 34 | timestamp += millis(); 35 | mqttClientID = F("%dn%&%pk%|securemode=3,signmethod=hmacsha256,timestamp=%timestamp%|"); 36 | mqttClientID.replace("%pk%", pk); 37 | mqttClientID.replace("%dn%", dn); 38 | mqttClientID.replace("%timestamp%", timestamp); 39 | 40 | // 生成 MQTT Username 41 | mqttUsername = dn; 42 | mqttUsername += "&"; 43 | mqttUsername += pk; 44 | 45 | // 生成 MQTT Password 46 | String signcontent = F("clientId"); 47 | signcontent += dn + F("&") + pk + F("deviceName") + dn + F("productKey") + pk + F("timestamp") + timestamp; 48 | mqttPassword = AliyunIoT_GetSign(signcontent, ds); 49 | 50 | String log = F("Aliyun IoT options:\n"); 51 | log += "Broker: " + mqttBroker + "\n"; 52 | log += "BrokerIP: "; 53 | log += String(mqttBrokerIP[0]) + "." + String(mqttBrokerIP[1]) + "." + String(mqttBrokerIP[2]) + "." + String(mqttBrokerIP[3]) + F("\n"); 54 | log += "ClientID: " + mqttClientID + "\n"; 55 | log += "Username: " + mqttUsername + "\n"; 56 | log += "Password: " + mqttPassword + "\n"; 57 | Serial.println(log); 58 | } 59 | 60 | String AliyunIoT_GetSign(String& signcontent, String& ds) { 61 | SHA256HMAC hmac((const byte *)ds.c_str(), ds.length()); 62 | hmac.doUpdate((const byte *)signcontent.c_str(), signcontent.length()); 63 | byte authCode[SHA256HMAC_SIZE]; 64 | hmac.doFinal(authCode); 65 | String sign = F(""); 66 | for (byte i = 0; i < SHA256HMAC_SIZE; ++i) { 67 | if (authCode[i] < 0x10) { 68 | sign += F("0"); 69 | } 70 | sign += String(authCode[i], HEX); 71 | } 72 | String log = F("GetSign:\n"); 73 | log += signcontent + F("\n"); 74 | log += sign + F("\n"); 75 | Serial.println(log); 76 | return sign; 77 | } 78 | 79 | void AliyunIoT_MQTTCallback(char* c_topic, byte* b_payload, unsigned int length) { 80 | 81 | } 82 | 83 | bool AliyunIoT_Connect() { 84 | AliyunMQTTclient.setServer(mqttBrokerIP, 1883); 85 | AliyunMQTTclient.setCallback(AliyunIoT_MQTTCallback); 86 | 87 | Serial.println("Start connecting to Aliyun IoT..."); 88 | 89 | bool result = false; 90 | for (byte i = 0; i < 3; ++i) { 91 | result = AliyunMQTTclient.connect(mqttClientID.c_str(), 92 | mqttUsername.c_str(), 93 | mqttPassword.c_str()); 94 | if (result) { 95 | Serial.println("Connected to Aliyun IoT."); 96 | break; 97 | } else { 98 | String log = F("Connect to Aliyun IoT failed with state "); 99 | log += AliyunMQTTclient.state(); 100 | Serial.println(log); 101 | } 102 | delay(500); 103 | } 104 | 105 | return result; 106 | } 107 | 108 | bool AliyunIoT_CheckConnection() { 109 | if (!AliyunMQTTclient.connected()) { 110 | AliyunMQTTclient.disconnect(); 111 | Serial.println("Aliyun IoT connection lost, reconnecting..."); 112 | AliyunIoT_Connect(); 113 | } 114 | 115 | return AliyunMQTTclient.connected(); 116 | } 117 | 118 | String AliyunIoT_BuildPayload(String& props) { 119 | String payload = F("{\"id\":\""); 120 | payload += millis(); 121 | payload += F("\",\"version\":\"1.0\",\"method\":\"thing.event.property.post\",\"params\":{"); 122 | payload += props; 123 | payload += F("}}"); 124 | return payload; 125 | } 126 | 127 | void AliyunIoT_Loop() { 128 | AliyunMQTTclient.loop(); 129 | } 130 | 131 | bool AliyunIoT_PostProperty(String& props) { 132 | // 根据 Alink 协议,生成上报数据所使用的 topic 133 | if (mqttPostPropertyTopic.length() == 0) { 134 | String topic = F("/sys/%pk%/%dn%/thing/event/property/post"); 135 | topic.replace("%pk%", productKey); 136 | topic.replace("%dn%", deviceName); 137 | mqttPostPropertyTopic = topic; 138 | } 139 | 140 | bool result = false; 141 | if (AliyunIoT_CheckConnection()) { 142 | String payload = AliyunIoT_BuildPayload(props); 143 | result = AliyunMQTTclient.publish(mqttPostPropertyTopic.c_str(), payload.c_str(), 0); 144 | Serial.println("Post property payload:"); 145 | Serial.println(payload); 146 | } 147 | 148 | return result; 149 | } 150 | -------------------------------------------------------------------------------- /airmonitor_device/src/aliyun_iot.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * 初始化连接参数 5 | * @param productKey 硬件产品的ProductKey 6 | * @param deviceName 测试设备的 DeviceName 7 | * @param deviceSecret 测试设备的 DeviceSecret 8 | */ 9 | void AliyunIoT_Init(String& productKey, String& deviceName, String& deviceSecret); 10 | 11 | /** 12 | * 与阿里云 IoT 建立连接 13 | * @return 连接是否成功 14 | */ 15 | bool AliyunIoT_Connect(); 16 | 17 | /** 18 | * 检查与阿里云 IoT 的连接状态,如果未连接则尝试连接 19 | * @return 是否已经与阿里云 IoT 建立连接 20 | */ 21 | bool AliyunIoT_CheckConnection(); 22 | 23 | /** 24 | * 生成建立连接需要签名 25 | * @param signcontent 需要签名的内容 26 | * @param ds 测试设备的 DeviceSecret 27 | * @return 生成的签名 28 | */ 29 | String AliyunIoT_GetSign(String& signcontent, String& ds); 30 | 31 | /** 32 | * PubSubClient 定时检测 33 | */ 34 | void AliyunIoT_Loop(); 35 | 36 | /** 37 | * 上报数据到阿里云 IoT 38 | * @param props 属性值列表,使用键值对,以逗号分隔,例如 "PM25Value":12,"CurrentTemperature":25 39 | */ 40 | bool AliyunIoT_PostProperty(String& props); 41 | -------------------------------------------------------------------------------- /airmonitor_device/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include "aliyun_iot.h" 5 | #include "sensor.h" 6 | 7 | void setup() { 8 | Serial.begin(115200); 9 | 10 | // 接入 WiFi 网络 11 | WiFiManager wifiManager; 12 | wifiManager.autoConnect("AirMonitor_Config"); 13 | Serial.println("Connected to internet.\n"); 14 | 15 | // 初始化连接参数 16 | String productKey = F("__YOUR_DEVICE_PRODUCT_KEY__"); 17 | String deviceName = F("__YOUR_DEVICE_NAME__"); 18 | String deviceSecret = F("__YOUR_DEVICE_SECRET__"); 19 | AliyunIoT_Init(productKey, deviceName, deviceSecret); 20 | 21 | // 建立连接 22 | AliyunIoT_Connect(); 23 | } 24 | 25 | unsigned long postSensorDataTimer = 0; 26 | #define POST_SENSOR_DATA_INTERVAL 60 27 | 28 | void postSensorData() { 29 | int pm25 = sensor_get_pm25(); 30 | int pm1 = sensor_get_pm1(); 31 | int pm10 = sensor_get_pm10(); 32 | float temperature = sensor_get_temperature(); 33 | int humidity = sensor_get_humidity(); 34 | String props = F("\"PM25Value\":"); 35 | props += pm25; 36 | props += ",\"PM1\":"; 37 | props += pm1; 38 | props += ",\"PM10\":"; 39 | props += pm10; 40 | props += ",\"CurrentTemperature\":"; 41 | props += temperature; 42 | props += ",\"RelativeHumidity\":"; 43 | props += humidity; 44 | AliyunIoT_PostProperty(props); 45 | } 46 | 47 | void loop() { 48 | if (millis() - postSensorDataTimer > POST_SENSOR_DATA_INTERVAL*1000) { 49 | if (AliyunIoT_CheckConnection()) { 50 | Serial.println("Start sending sensor data..."); 51 | postSensorData(); 52 | } 53 | postSensorDataTimer = millis(); 54 | } 55 | 56 | AliyunIoT_Loop(); 57 | delay(1); 58 | } 59 | -------------------------------------------------------------------------------- /airmonitor_device/src/sensor.cpp: -------------------------------------------------------------------------------- 1 | #include "sensor.h" 2 | #include 3 | 4 | static int pm25 = 12; 5 | static int pm1 = 12; 6 | static int pm10 = 12; 7 | 8 | float sensor_get_temperature() { 9 | return 25.3; 10 | } 11 | 12 | int sensor_get_humidity() { 13 | return 50; 14 | } 15 | 16 | int sensor_get_pm1() { 17 | int adjust = random(0, 10) - 5; 18 | pm1 = pm1 + adjust >= 0 ? pm1 + adjust : 0; 19 | pm1 = pm1 > 200 ? 200 : pm1; 20 | return pm1; 21 | } 22 | 23 | int sensor_get_pm25() { 24 | int adjust = random(0, 10) - 5; 25 | pm25 = pm25 + adjust >= 0 ? pm25 + adjust : 0; 26 | pm25 = pm25 > 200 ? 200 : pm25; 27 | return pm25; 28 | } 29 | 30 | int sensor_get_pm10() { 31 | int adjust = random(0, 10) - 5; 32 | pm10 = pm10 + adjust >= 0 ? pm10 + adjust : 0; 33 | pm10 = pm10 > 200 ? 200 : pm10; 34 | return pm10; 35 | } 36 | -------------------------------------------------------------------------------- /airmonitor_device/src/sensor.h: -------------------------------------------------------------------------------- 1 | #ifndef _SENSOR_H_ 2 | #define _SENSOR_H_ 3 | 4 | float sensor_get_temperature(); 5 | 6 | int sensor_get_humidity(); 7 | 8 | int sensor_get_pm25(); 9 | 10 | int sensor_get_pm1(); 11 | 12 | int sensor_get_pm10(); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /airmonitor_ios/Podfile: -------------------------------------------------------------------------------- 1 | # SDK 最低支持版本为 iOS 8.0 2 | platform:ios, '8.0' 3 | 4 | # github 官方 pod 源 5 | source 'https://github.com/CocoaPods/Specs.git' 6 | # 阿里云 pod 源 7 | source 'https://github.com/aliyun/aliyun-specs.git' 8 | 9 | # 需要替换下述 "IMSDemoApp" 为开发者 App 的 target 名称 10 | target "airmonitor" do 11 | pod 'IMSApiClient', '1.0.0' 12 | pod 'IMSBoneKit', '1.0.1' 13 | pod 'AKReactNative', '0.41.2' 14 | pod 'MJRefresh', '3.1.15' 15 | pod 'ZipArchive', '1.4.0' 16 | end 17 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 40922312CADDABA5E262A4F4 /* libPods-airmonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 172DCD576FC6E72C9DC815D0 /* libPods-airmonitor.a */; }; 11 | 8909F010202EFC7C004F5106 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8909F00F202EFC7C004F5106 /* AppDelegate.m */; }; 12 | 8909F013202EFC7C004F5106 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8909F012202EFC7C004F5106 /* ViewController.m */; }; 13 | 8909F016202EFC7C004F5106 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8909F014202EFC7C004F5106 /* Main.storyboard */; }; 14 | 8909F018202EFC7C004F5106 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8909F017202EFC7C004F5106 /* Assets.xcassets */; }; 15 | 8909F01B202EFC7C004F5106 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8909F019202EFC7C004F5106 /* LaunchScreen.storyboard */; }; 16 | 8909F01E202EFC7C004F5106 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8909F01D202EFC7C004F5106 /* main.m */; }; 17 | 8909F025202F3650004F5106 /* yw_1222_07e8.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 8909F024202F3650004F5106 /* yw_1222_07e8.jpg */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 172DCD576FC6E72C9DC815D0 /* libPods-airmonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-airmonitor.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | 8909F00B202EFC7C004F5106 /* airmonitor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = airmonitor.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 8909F00E202EFC7C004F5106 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 24 | 8909F00F202EFC7C004F5106 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 25 | 8909F011202EFC7C004F5106 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 26 | 8909F012202EFC7C004F5106 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 27 | 8909F015202EFC7C004F5106 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 28 | 8909F017202EFC7C004F5106 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 29 | 8909F01A202EFC7C004F5106 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 30 | 8909F01C202EFC7C004F5106 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | 8909F01D202EFC7C004F5106 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 32 | 8909F024202F3650004F5106 /* yw_1222_07e8.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = yw_1222_07e8.jpg; sourceTree = SOURCE_ROOT; }; 33 | A9E2A4A0C618DDD5717A0A85 /* Pods-airmonitor.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-airmonitor.release.xcconfig"; path = "Pods/Target Support Files/Pods-airmonitor/Pods-airmonitor.release.xcconfig"; sourceTree = ""; }; 34 | DD7A9700B74E9D301B44654B /* Pods-airmonitor.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-airmonitor.debug.xcconfig"; path = "Pods/Target Support Files/Pods-airmonitor/Pods-airmonitor.debug.xcconfig"; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | 8909F008202EFC7C004F5106 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | 40922312CADDABA5E262A4F4 /* libPods-airmonitor.a in Frameworks */, 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXFrameworksBuildPhase section */ 47 | 48 | /* Begin PBXGroup section */ 49 | 091DD99D3C261D72D20436A1 /* Pods */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | DD7A9700B74E9D301B44654B /* Pods-airmonitor.debug.xcconfig */, 53 | A9E2A4A0C618DDD5717A0A85 /* Pods-airmonitor.release.xcconfig */, 54 | ); 55 | name = Pods; 56 | sourceTree = ""; 57 | }; 58 | 8909F002202EFC7C004F5106 = { 59 | isa = PBXGroup; 60 | children = ( 61 | 8909F00D202EFC7C004F5106 /* airmonitor */, 62 | 8909F00C202EFC7C004F5106 /* Products */, 63 | 091DD99D3C261D72D20436A1 /* Pods */, 64 | D5533B23A6F8F4F5D420E923 /* Frameworks */, 65 | ); 66 | sourceTree = ""; 67 | }; 68 | 8909F00C202EFC7C004F5106 /* Products */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 8909F00B202EFC7C004F5106 /* airmonitor.app */, 72 | ); 73 | name = Products; 74 | sourceTree = ""; 75 | }; 76 | 8909F00D202EFC7C004F5106 /* airmonitor */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 8909F024202F3650004F5106 /* yw_1222_07e8.jpg */, 80 | 8909F00E202EFC7C004F5106 /* AppDelegate.h */, 81 | 8909F00F202EFC7C004F5106 /* AppDelegate.m */, 82 | 8909F011202EFC7C004F5106 /* ViewController.h */, 83 | 8909F012202EFC7C004F5106 /* ViewController.m */, 84 | 8909F014202EFC7C004F5106 /* Main.storyboard */, 85 | 8909F017202EFC7C004F5106 /* Assets.xcassets */, 86 | 8909F019202EFC7C004F5106 /* LaunchScreen.storyboard */, 87 | 8909F01C202EFC7C004F5106 /* Info.plist */, 88 | 8909F01D202EFC7C004F5106 /* main.m */, 89 | ); 90 | path = airmonitor; 91 | sourceTree = ""; 92 | }; 93 | D5533B23A6F8F4F5D420E923 /* Frameworks */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 172DCD576FC6E72C9DC815D0 /* libPods-airmonitor.a */, 97 | ); 98 | name = Frameworks; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 8909F00A202EFC7C004F5106 /* airmonitor */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 8909F021202EFC7C004F5106 /* Build configuration list for PBXNativeTarget "airmonitor" */; 107 | buildPhases = ( 108 | EAD752616A8356AE1727D133 /* [CP] Check Pods Manifest.lock */, 109 | 8909F007202EFC7C004F5106 /* Sources */, 110 | 8909F008202EFC7C004F5106 /* Frameworks */, 111 | 8909F009202EFC7C004F5106 /* Resources */, 112 | 5A77D22835F9382623C02246 /* [CP] Embed Pods Frameworks */, 113 | 8EFB025E130CA3877AF2E82D /* [CP] Copy Pods Resources */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = airmonitor; 120 | productName = airmonitor; 121 | productReference = 8909F00B202EFC7C004F5106 /* airmonitor.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 8909F003202EFC7C004F5106 /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 0920; 131 | ORGANIZATIONNAME = Aliyun; 132 | TargetAttributes = { 133 | 8909F00A202EFC7C004F5106 = { 134 | CreatedOnToolsVersion = 9.2; 135 | ProvisioningStyle = Automatic; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 8909F006202EFC7C004F5106 /* Build configuration list for PBXProject "airmonitor" */; 140 | compatibilityVersion = "Xcode 8.0"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 8909F002202EFC7C004F5106; 148 | productRefGroup = 8909F00C202EFC7C004F5106 /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 8909F00A202EFC7C004F5106 /* airmonitor */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 8909F009202EFC7C004F5106 /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 8909F025202F3650004F5106 /* yw_1222_07e8.jpg in Resources */, 163 | 8909F01B202EFC7C004F5106 /* LaunchScreen.storyboard in Resources */, 164 | 8909F018202EFC7C004F5106 /* Assets.xcassets in Resources */, 165 | 8909F016202EFC7C004F5106 /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 5A77D22835F9382623C02246 /* [CP] Embed Pods Frameworks */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "[CP] Embed Pods Frameworks"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-airmonitor/Pods-airmonitor-frameworks.sh\"\n"; 185 | showEnvVarsInLog = 0; 186 | }; 187 | 8EFB025E130CA3877AF2E82D /* [CP] Copy Pods Resources */ = { 188 | isa = PBXShellScriptBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | ); 192 | inputPaths = ( 193 | ); 194 | name = "[CP] Copy Pods Resources"; 195 | outputPaths = ( 196 | ); 197 | runOnlyForDeploymentPostprocessing = 0; 198 | shellPath = /bin/sh; 199 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-airmonitor/Pods-airmonitor-resources.sh\"\n"; 200 | showEnvVarsInLog = 0; 201 | }; 202 | EAD752616A8356AE1727D133 /* [CP] Check Pods Manifest.lock */ = { 203 | isa = PBXShellScriptBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | ); 207 | inputPaths = ( 208 | ); 209 | name = "[CP] Check Pods Manifest.lock"; 210 | outputPaths = ( 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | shellPath = /bin/sh; 214 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 215 | showEnvVarsInLog = 0; 216 | }; 217 | /* End PBXShellScriptBuildPhase section */ 218 | 219 | /* Begin PBXSourcesBuildPhase section */ 220 | 8909F007202EFC7C004F5106 /* Sources */ = { 221 | isa = PBXSourcesBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | 8909F013202EFC7C004F5106 /* ViewController.m in Sources */, 225 | 8909F01E202EFC7C004F5106 /* main.m in Sources */, 226 | 8909F010202EFC7C004F5106 /* AppDelegate.m in Sources */, 227 | ); 228 | runOnlyForDeploymentPostprocessing = 0; 229 | }; 230 | /* End PBXSourcesBuildPhase section */ 231 | 232 | /* Begin PBXVariantGroup section */ 233 | 8909F014202EFC7C004F5106 /* Main.storyboard */ = { 234 | isa = PBXVariantGroup; 235 | children = ( 236 | 8909F015202EFC7C004F5106 /* Base */, 237 | ); 238 | name = Main.storyboard; 239 | sourceTree = ""; 240 | }; 241 | 8909F019202EFC7C004F5106 /* LaunchScreen.storyboard */ = { 242 | isa = PBXVariantGroup; 243 | children = ( 244 | 8909F01A202EFC7C004F5106 /* Base */, 245 | ); 246 | name = LaunchScreen.storyboard; 247 | sourceTree = ""; 248 | }; 249 | /* End PBXVariantGroup section */ 250 | 251 | /* Begin XCBuildConfiguration section */ 252 | 8909F01F202EFC7C004F5106 /* Debug */ = { 253 | isa = XCBuildConfiguration; 254 | buildSettings = { 255 | ALWAYS_SEARCH_USER_PATHS = NO; 256 | CLANG_ANALYZER_NONNULL = YES; 257 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 258 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 259 | CLANG_CXX_LIBRARY = "libc++"; 260 | CLANG_ENABLE_MODULES = YES; 261 | CLANG_ENABLE_OBJC_ARC = YES; 262 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_COMMA = YES; 265 | CLANG_WARN_CONSTANT_CONVERSION = YES; 266 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 267 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 268 | CLANG_WARN_EMPTY_BODY = YES; 269 | CLANG_WARN_ENUM_CONVERSION = YES; 270 | CLANG_WARN_INFINITE_RECURSION = YES; 271 | CLANG_WARN_INT_CONVERSION = YES; 272 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 273 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 275 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 276 | CLANG_WARN_STRICT_PROTOTYPES = YES; 277 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 278 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 279 | CLANG_WARN_UNREACHABLE_CODE = YES; 280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 281 | CODE_SIGN_IDENTITY = "iPhone Developer"; 282 | COPY_PHASE_STRIP = NO; 283 | DEBUG_INFORMATION_FORMAT = dwarf; 284 | ENABLE_STRICT_OBJC_MSGSEND = YES; 285 | ENABLE_TESTABILITY = YES; 286 | GCC_C_LANGUAGE_STANDARD = gnu11; 287 | GCC_DYNAMIC_NO_PIC = NO; 288 | GCC_NO_COMMON_BLOCKS = YES; 289 | GCC_OPTIMIZATION_LEVEL = 0; 290 | GCC_PREPROCESSOR_DEFINITIONS = ( 291 | "DEBUG=1", 292 | "$(inherited)", 293 | ); 294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 296 | GCC_WARN_UNDECLARED_SELECTOR = YES; 297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 298 | GCC_WARN_UNUSED_FUNCTION = YES; 299 | GCC_WARN_UNUSED_VARIABLE = YES; 300 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 301 | MTL_ENABLE_DEBUG_INFO = YES; 302 | ONLY_ACTIVE_ARCH = YES; 303 | SDKROOT = iphoneos; 304 | }; 305 | name = Debug; 306 | }; 307 | 8909F020202EFC7C004F5106 /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ALWAYS_SEARCH_USER_PATHS = NO; 311 | CLANG_ANALYZER_NONNULL = YES; 312 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 314 | CLANG_CXX_LIBRARY = "libc++"; 315 | CLANG_ENABLE_MODULES = YES; 316 | CLANG_ENABLE_OBJC_ARC = YES; 317 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 318 | CLANG_WARN_BOOL_CONVERSION = YES; 319 | CLANG_WARN_COMMA = YES; 320 | CLANG_WARN_CONSTANT_CONVERSION = YES; 321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 322 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 323 | CLANG_WARN_EMPTY_BODY = YES; 324 | CLANG_WARN_ENUM_CONVERSION = YES; 325 | CLANG_WARN_INFINITE_RECURSION = YES; 326 | CLANG_WARN_INT_CONVERSION = YES; 327 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 328 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 330 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 331 | CLANG_WARN_STRICT_PROTOTYPES = YES; 332 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 333 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 334 | CLANG_WARN_UNREACHABLE_CODE = YES; 335 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 336 | CODE_SIGN_IDENTITY = "iPhone Developer"; 337 | COPY_PHASE_STRIP = NO; 338 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 339 | ENABLE_NS_ASSERTIONS = NO; 340 | ENABLE_STRICT_OBJC_MSGSEND = YES; 341 | GCC_C_LANGUAGE_STANDARD = gnu11; 342 | GCC_NO_COMMON_BLOCKS = YES; 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 350 | MTL_ENABLE_DEBUG_INFO = NO; 351 | SDKROOT = iphoneos; 352 | VALIDATE_PRODUCT = YES; 353 | }; 354 | name = Release; 355 | }; 356 | 8909F022202EFC7C004F5106 /* Debug */ = { 357 | isa = XCBuildConfiguration; 358 | baseConfigurationReference = DD7A9700B74E9D301B44654B /* Pods-airmonitor.debug.xcconfig */; 359 | buildSettings = { 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | CODE_SIGN_STYLE = Automatic; 362 | DEVELOPMENT_TEAM = ""; 363 | INFOPLIST_FILE = airmonitor/Info.plist; 364 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 365 | PRODUCT_BUNDLE_IDENTIFIER = com.lddemo.airmonitor; 366 | PRODUCT_NAME = "$(TARGET_NAME)"; 367 | TARGETED_DEVICE_FAMILY = "1,2"; 368 | }; 369 | name = Debug; 370 | }; 371 | 8909F023202EFC7C004F5106 /* Release */ = { 372 | isa = XCBuildConfiguration; 373 | baseConfigurationReference = A9E2A4A0C618DDD5717A0A85 /* Pods-airmonitor.release.xcconfig */; 374 | buildSettings = { 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | CODE_SIGN_STYLE = Automatic; 377 | DEVELOPMENT_TEAM = ""; 378 | INFOPLIST_FILE = airmonitor/Info.plist; 379 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 380 | PRODUCT_BUNDLE_IDENTIFIER = com.lddemo.airmonitor; 381 | PRODUCT_NAME = "$(TARGET_NAME)"; 382 | TARGETED_DEVICE_FAMILY = "1,2"; 383 | }; 384 | name = Release; 385 | }; 386 | /* End XCBuildConfiguration section */ 387 | 388 | /* Begin XCConfigurationList section */ 389 | 8909F006202EFC7C004F5106 /* Build configuration list for PBXProject "airmonitor" */ = { 390 | isa = XCConfigurationList; 391 | buildConfigurations = ( 392 | 8909F01F202EFC7C004F5106 /* Debug */, 393 | 8909F020202EFC7C004F5106 /* Release */, 394 | ); 395 | defaultConfigurationIsVisible = 0; 396 | defaultConfigurationName = Release; 397 | }; 398 | 8909F021202EFC7C004F5106 /* Build configuration list for PBXNativeTarget "airmonitor" */ = { 399 | isa = XCConfigurationList; 400 | buildConfigurations = ( 401 | 8909F022202EFC7C004F5106 /* Debug */, 402 | 8909F023202EFC7C004F5106 /* Release */, 403 | ); 404 | defaultConfigurationIsVisible = 0; 405 | defaultConfigurationName = Release; 406 | }; 407 | /* End XCConfigurationList section */ 408 | }; 409 | rootObject = 8909F003202EFC7C004F5106 /* Project object */; 410 | } 411 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // airmonitor 4 | // 5 | // Created by LinkDevelop on 10/02/2018. 6 | // Copyright © 2018 Aliyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // airmonitor 4 | // 5 | // Created by LinkDevelop on 10/02/2018. 6 | // Copyright © 2018 Aliyun. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import 12 | #import 13 | 14 | @interface AppDelegate () 15 | 16 | @end 17 | 18 | @implementation AppDelegate 19 | 20 | 21 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 22 | // Override point for customization after application launch. 23 | 24 | // 指定 API 通道服务器域名和环境 25 | [IMSConfiguration initWithHost:@"api.link.aliyun.com" serverEnv:IMSServerRelease]; 26 | 27 | // 配置 Bone Mobile 容器运行环境 28 | IMSBoneConfiguration *configuration = [IMSBoneConfiguration sharedInstance]; 29 | configuration.pluginEnvironment = IMSBonePluginEnvironmentDaily; 30 | configuration.serverEnvironment = IMSBoneServerEnvironmentRelease; 31 | 32 | return YES; 33 | } 34 | 35 | 36 | - (void)applicationWillResignActive:(UIApplication *)application { 37 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 38 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 39 | } 40 | 41 | 42 | - (void)applicationDidEnterBackground:(UIApplication *)application { 43 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 44 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 45 | } 46 | 47 | 48 | - (void)applicationWillEnterForeground:(UIApplication *)application { 49 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 50 | } 51 | 52 | 53 | - (void)applicationDidBecomeActive:(UIApplication *)application { 54 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 55 | } 56 | 57 | 58 | - (void)applicationWillTerminate:(UIApplication *)application { 59 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 60 | } 61 | 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 51 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 0.1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoads 28 | 29 | 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // airmonitor 4 | // 5 | // Created by LinkDevelop on 10/02/2018. 6 | // Copyright © 2018 Aliyun. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UITableViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // airmonitor 4 | // 5 | // Created by LinkDevelop on 10/02/2018. 6 | // Copyright © 2018 Aliyun. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import 12 | 13 | #import 14 | 15 | #import 16 | 17 | @interface ViewController () 18 | @property (nonatomic, strong) NSArray *deviceStatus; 19 | @property (nonatomic, strong) NSDictionary *unitForStatus; 20 | @property (nonatomic, weak) NSTimer *refreshTimer; 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | - (void)dealloc { 26 | [self.refreshTimer invalidate]; 27 | } 28 | 29 | 30 | - (void)viewDidLoad { 31 | [super viewDidLoad]; 32 | 33 | NSURL *url = [NSURL URLWithString:@"link://__YOUR_MOBILE_PLUGIN_ID__"]; 34 | NSDictionary *params = @{ 35 | @"ProductKey": @"__YOUR_DEVICE_PRODUCT_KEY__", 36 | @"DeviceName": @"__YOUR_DEVICE_NAME__" 37 | }; 38 | [[IMSRouterService sharedService] openURL:url 39 | options:params 40 | completionHandler:^(BOOL success) { 41 | if (success) { 42 | NSLog(@"插件打开成功"); 43 | } else { 44 | NSLog(@"插件打开失败"); 45 | } 46 | }]; 47 | } 48 | 49 | 50 | - (void)queryDeviceStatus { 51 | // 构建请求 52 | NSDictionary *params = @{ 53 | @"ProductKey": @"__YOUR_DEVICE_PRODUCT_KEY__", 54 | @"DeviceName": @"__YOUR_DEVICE_NAME__", 55 | }; 56 | IMSIoTRequestBuilder *builder = [[IMSIoTRequestBuilder alloc] initWithPath:@"/thing/device/status/query" 57 | apiVersion:@"1.0.1" 58 | params:params]; 59 | 60 | //通过 IMSRequestClient 发送请求 61 | [IMSRequestClient asyncSendRequest:builder.build responseHandler:^(NSError * _Nullable error, IMSResponse * _Nullable response) { 62 | if (error) { 63 | //处理Error,非服务端返回的错误都通过该Error回调 64 | } else { 65 | if (response.code == 200) { 66 | //成功,处理response.data 67 | self.deviceStatus = response.data; 68 | [self.tableView reloadData]; 69 | } else { 70 | //处理服务端错误,可通过response.localizedMsg展示错误Toast 71 | } 72 | } 73 | }]; 74 | } 75 | 76 | 77 | - (void)didReceiveMemoryWarning { 78 | [super didReceiveMemoryWarning]; 79 | // Dispose of any resources that can be recreated. 80 | } 81 | 82 | 83 | #pragma mark - TableView delegate 84 | 85 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 86 | return 1; 87 | } 88 | 89 | 90 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 91 | return self.deviceStatus.count; 92 | } 93 | 94 | 95 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 96 | 97 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"DataCell"]; 98 | NSDictionary *status = self.deviceStatus[indexPath.row]; 99 | cell.textLabel.text = status[@"attribute"]; 100 | cell.detailTextLabel.text = [[status[@"value"] description] stringByAppendingString:self.unitForStatus[status[@"attribute"]]]; 101 | return cell; 102 | } 103 | 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /airmonitor_ios/airmonitor/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // airmonitor 4 | // 5 | // Created by LinkDevelop on 10/02/2018. 6 | // Copyright © 2018 Aliyun. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /airmonitor_ios/yw_1222_07e8.jpg: -------------------------------------------------------------------------------- 1 | yw_1222_07e8.jpg 2 | -------------------------------------------------------------------------------- /airmonitor_status-board/README.md: -------------------------------------------------------------------------------- 1 | # airmonitor_status-board 2 | 3 | 4 | 5 | ## QuickStart 6 | 7 | 8 | 9 | see [egg docs][egg] for more detail. 10 | 11 | ### Development 12 | 13 | ```bash 14 | $ npm i 15 | $ npm run dev 16 | $ open http://localhost:7001/ 17 | ``` 18 | 19 | ### Deploy 20 | 21 | ```bash 22 | $ npm start 23 | $ npm stop 24 | ``` 25 | 26 | ### npm scripts 27 | 28 | - Use `npm run lint` to check code style. 29 | - Use `npm test` to run unit test. 30 | - Use `npm run autod` to auto detect dependencies upgrade, see [autod](https://www.npmjs.com/package/autod) for more detail. 31 | 32 | 33 | [egg]: https://eggjs.org -------------------------------------------------------------------------------- /airmonitor_status-board/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # airmonitor_status-board 2 | 3 | 4 | 5 | ## 快速入门 6 | 7 | 8 | 9 | 如需进一步了解,参见 [egg 文档][egg]。 10 | 11 | ### 本地开发 12 | 13 | ```bash 14 | $ npm i 15 | $ npm run dev 16 | $ open http://localhost:7001/ 17 | ``` 18 | 19 | ### 部署 20 | 21 | ```bash 22 | $ npm start 23 | $ npm stop 24 | ``` 25 | 26 | ### 单元测试 27 | 28 | - [egg-bin] 内置了 [mocha], [thunk-mocha], [power-assert], [istanbul] 等框架,让你可以专注于写单元测试,无需理会配套工具。 29 | - 断言库非常推荐使用 [power-assert]。 30 | - 具体参见 [egg 文档 - 单元测试](https://eggjs.org/zh-cn/core/unittest)。 31 | 32 | ### 内置指令 33 | 34 | - 使用 `npm run lint` 来做代码风格检查。 35 | - 使用 `npm test` 来执行单元测试。 36 | - 使用 `npm run autod` 来自动检测依赖更新,详细参见 [autod](https://www.npmjs.com/package/autod) 。 37 | 38 | 39 | [egg]: https://eggjs.org 40 | -------------------------------------------------------------------------------- /airmonitor_status-board/app/controller/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Controller = require('egg').Controller; 4 | 5 | class HomeController extends Controller { 6 | async index() { 7 | await this.ctx.render('index.html', { }); 8 | } 9 | 10 | async statusData() { 11 | // 获取配置中所有的设备列表 12 | const deviceNames = this.config.deviceNames; 13 | const statusData = {}; 14 | const devicePositions = Object.keys(deviceNames); 15 | 16 | for (let i = 0; i < devicePositions.length; ++i) { 17 | const devicePosition = devicePositions[i]; 18 | 19 | // 使用 /thing/device/properties/query 这个 API 来获取设备的所有属性列表 20 | const ret = await this.ctx.service.apiclient.post('/thing/device/properties/query', '1.1.0', { 21 | productKey: this.config.ProductKey, 22 | deviceName: deviceNames[devicePosition], 23 | }); 24 | 25 | if (ret.code === 200) { 26 | // API 返回的属性列表为数组形式,这里转换为键值对 27 | const data = ret.data.reduce((props, item) => { 28 | props[item.attribute] = item.value; 29 | return props; 30 | }, {}); 31 | statusData[devicePosition] = data; 32 | } 33 | } 34 | 35 | this.ctx.body = JSON.stringify(statusData); 36 | this.ctx.response.set('Content-Type', 'application/json'); 37 | } 38 | } 39 | 40 | module.exports = HomeController; 41 | -------------------------------------------------------------------------------- /airmonitor_status-board/app/public/img/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aliyun-linkdevelop/airmonitor_demo/d94188994ec97df709e0a1e90ee32952183fb8d7/airmonitor_status-board/app/public/img/background.png -------------------------------------------------------------------------------- /airmonitor_status-board/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @param {Egg.Application} app - egg application 5 | */ 6 | module.exports = app => { 7 | const { router, controller } = app; 8 | router.get('/', controller.home.index); 9 | 10 | // 提供给页面使用的获取数据 API 11 | router.get('/status-data', controller.home.statusData); 12 | }; 13 | -------------------------------------------------------------------------------- /airmonitor_status-board/app/service/apiclient.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Service = require('egg').Service; 4 | const Client = require('aliyun-api-gateway').Client; 5 | 6 | class ApiClient extends Service { 7 | getClient() { 8 | if (!this.client) { 9 | // 使用配置中的 AppKey 以及 AppSecret 创建阿里云 API 网关 Client 10 | this.client = new Client(this.config.appKey, this.config.appSecret); 11 | } 12 | 13 | return this.client; 14 | } 15 | 16 | async post(apiPath, apiVer, params) { 17 | const client = this.getClient(); 18 | 19 | let response = null; 20 | try { 21 | // LinkDevelop 平台的 URL 为 http://api.link.aliyun.com 22 | // 该地址可以在 LinkDevelop 平台的资源管理》官方服务中通过查看 API 详情得到 23 | const apiurl = 'https://api.link.aliyun.com' + apiPath; 24 | const payload = { 25 | data: { 26 | id: new Date() * 1 + '', 27 | version: '1.0', 28 | request: { 29 | apiVer: apiVer || '', 30 | }, 31 | params, 32 | }, 33 | }; 34 | response = await client.post(apiurl, payload); 35 | 36 | } catch (error) { 37 | this.ctx.logger.error('API Response Error', error); 38 | response = error; 39 | } 40 | return response || {}; 41 | } 42 | } 43 | 44 | module.exports = ApiClient; 45 | -------------------------------------------------------------------------------- /airmonitor_status-board/app/view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | AirMonitor Status Board 4 | 17 | 18 | 19 |
20 |
21 | 22 |
23 | 客厅
24 | PM2.5:-μg/m³
25 | 温度:-°C
26 | 湿度:-%
27 |
28 |
29 | 主卧
30 | PM2.5:-μg/m³
31 | 温度:-°C
32 | 湿度:-%
33 |
34 |
35 | 次卧
36 | PM2.5:-μg/m³
37 | 温度:-°C
38 | 湿度:-%
39 |
40 |
41 |
42 | 43 | 62 | 63 | -------------------------------------------------------------------------------- /airmonitor_status-board/appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '8' 4 | 5 | install: 6 | - ps: Install-Product node $env:nodejs_version 7 | - npm i npminstall && node_modules\.bin\npminstall 8 | 9 | test_script: 10 | - node --version 11 | - npm --version 12 | - npm run test 13 | 14 | build: off 15 | -------------------------------------------------------------------------------- /airmonitor_status-board/config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = appInfo => { 4 | const config = exports = {}; 5 | 6 | // use for cookie sign key, should change to your own and keep security 7 | config.keys = appInfo.name + '_1517990340798_1979'; 8 | 9 | // add your config here 10 | config.middleware = []; 11 | 12 | // 硬件产品 ProductKey,为设备接入中创建产品时得到的 ProductKey 13 | config.ProductKey = '__YOUR_DEVICE_PRODUCT_KEY__'; 14 | 15 | // 非托管 Web 应用的 AppKey 及 AppSecret 16 | config.appKey = '__YOUR_WEB_APP_KEY__'; 17 | config.appSecret = '__YOUR_WEB_APP_SECRET__'; 18 | 19 | // 需要展示数据的设备名称列表,这里为在设备接入中添加的测试设备名称 20 | config.deviceNames = { 21 | 'living-room': '__YOUR_DEVICE_NAME__', 22 | 'bed-room': '__YOUR_DEVICE_NAME__', 23 | 'guest-room': '__YOUR_DEVICE_NAME__', 24 | }; 25 | 26 | // 配置模板引擎 27 | config.view = { 28 | defaultViewEngine: 'nunjucks', 29 | mapping: { 30 | '.html': 'nunjucks', 31 | }, 32 | }; 33 | 34 | return config; 35 | }; 36 | -------------------------------------------------------------------------------- /airmonitor_status-board/config/plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // had enabled by egg 4 | // exports.static = true; 5 | exports.nunjucks = { 6 | enable: true, 7 | package: 'egg-view-nunjucks' 8 | }; -------------------------------------------------------------------------------- /airmonitor_status-board/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "airmonitor_status-board", 3 | "version": "1.0.0", 4 | "description": "", 5 | "private": true, 6 | "dependencies": { 7 | "aliyun-api-gateway": "^1.1.4", 8 | "egg": "^2.2.1", 9 | "egg-scripts": "^2.5.0", 10 | "egg-view-nunjucks": "^2.1.4" 11 | }, 12 | "devDependencies": { 13 | "autod": "^3.0.1", 14 | "autod-egg": "^1.0.0", 15 | "egg-bin": "^4.3.5", 16 | "egg-ci": "^1.8.0", 17 | "egg-mock": "^3.14.0", 18 | "eslint": "^4.11.0", 19 | "eslint-config-egg": "^6.0.0", 20 | "webstorm-disable-index": "^1.2.0" 21 | }, 22 | "engines": { 23 | "node": ">=8.9.0" 24 | }, 25 | "scripts": { 26 | "start": "egg-scripts start --daemon --title=egg-server-airmonitor_status-board", 27 | "stop": "egg-scripts stop --title=egg-server-airmonitor_status-board", 28 | "dev": "egg-bin dev", 29 | "debug": "egg-bin debug", 30 | "test": "npm run lint -- --fix && npm run test-local", 31 | "test-local": "egg-bin test", 32 | "cov": "egg-bin cov", 33 | "lint": "eslint .", 34 | "ci": "npm run lint && npm run cov", 35 | "autod": "autod" 36 | }, 37 | "ci": { 38 | "version": "8" 39 | }, 40 | "repository": { 41 | "type": "git", 42 | "url": "" 43 | }, 44 | "license": "MIT" 45 | } 46 | --------------------------------------------------------------------------------