├── H5 ├── .gitignore ├── README.md ├── app.js ├── config │ └── _sample.json ├── package.json ├── public │ ├── bower.json │ ├── images │ │ ├── busy.gif │ │ ├── icon.png │ │ ├── icon_round.png │ │ ├── loading.jpg │ │ ├── scan.gif │ │ ├── scan1.gif │ │ ├── setting.png │ │ ├── voice.png │ │ └── web-loading.gif │ ├── scripts │ │ ├── config_sample.js │ │ ├── drag.js │ │ └── iot.js │ ├── style │ │ └── iot.css │ └── views │ │ └── index.html ├── route │ └── handle.js └── util │ └── weixin.js ├── LightBlue ├── LightBlue设置IOT TAG.md └── 截图.jpg ├── README.md ├── wechat ├── lib │ ├── DHT11.zip │ ├── DHT11 │ │ ├── DHT11.cpp │ │ ├── DHT11.h │ │ └── examples │ │ │ └── DHT11 │ │ │ └── DHT11.ino │ ├── Moto.zip │ ├── Moto │ │ ├── Moto.cpp │ │ ├── Moto.h │ │ └── example │ │ │ └── MotoTest │ │ │ └── MotoTest.ino │ ├── RGBLED.zip │ └── RGBLED │ │ ├── RGBLED.cpp │ │ ├── RGBLED.h │ │ └── example │ │ └── RGBLED_Test │ │ └── RGBLED_Test.ino └── wechat_hardware │ └── wechat_hardware.ino ├── wechat_v2 ├── doc │ └── arduino_extend.PDF ├── lib │ ├── DHT11.zip │ ├── DHT11 │ │ ├── DHT11.cpp │ │ ├── DHT11.h │ │ └── examples │ │ │ └── DHT11 │ │ │ └── DHT11.ino │ ├── Moto.zip │ ├── Moto │ │ ├── Moto.cpp │ │ ├── Moto.h │ │ └── example │ │ │ └── MotoTest │ │ │ └── MotoTest.ino │ ├── MsTimer2.zip │ ├── MsTimer2 │ │ ├── MsTimer2.cpp │ │ ├── MsTimer2.h │ │ ├── README.md │ │ ├── examples │ │ │ └── FlashLed │ │ │ │ └── FlashLed.pde │ │ ├── keywords.txt │ │ ├── library.json │ │ └── library.properties │ ├── RGB_Led_P9823.zip │ └── RGB_Led_P9823 │ │ ├── RGB_Led.cpp │ │ ├── RGB_Led.h │ │ ├── example │ │ └── RGB_Led_Example │ │ │ └── RGB_Led_Example.ino │ │ ├── p9823.cpp │ │ └── p9823.h ├── readme.md └── wechat_hardware │ └── wechat_hardware.ino ├── 串口驱动 ├── Mac OS X │ ├── CH341SER_MAC.ZIP │ └── 安装说明.md └── Windows │ ├── CH341SER.zip │ ├── HL-340.EXE │ └── 支持Win7-Win8的驱动程序.jpg └── 原理图 ├── IOT 体验板原理图.pdf └── SMART TAG 插槽原理图.PDF /H5/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dump.rdb 3 | bin 4 | public/scripts/config.js 5 | config/* 6 | redis.conf 7 | public/bower_components 8 | *.bak 9 | !config/_sample.json 10 | access_token.txt 11 | jsapi_ticket.txt 12 | *~ -------------------------------------------------------------------------------- /H5/README.md: -------------------------------------------------------------------------------- 1 | # wechat-iot-example 2 | 微信 IOT 蓝牙硬件设备操作 demo 3 | 4 | ##### 获取代码并安装项目依赖的库 5 | 6 | ``` 7 | git clone git@github.com:liuxiaodong/wechat-iot-example.git 8 | 9 | npm install 10 | 11 | cd public && bower install 12 | ``` 13 | 14 | ##### 修改配置文件 15 | 16 | ``` 17 | cp config/_sample.json config/development.json 18 | 19 | 修改 development.json 中的配置项为自己公众号的 appid 和 appsecret 20 | 21 | cp public/scripts/config_sample.js public/scripts/config.js 22 | 修改 config.js 文件中变量 baseUrl 为自己服务器地址 23 | ``` 24 | 25 | ##### 启动服务 26 | 27 | ``` 28 | node app.js 29 | ``` 30 | 31 | ##### 公众号配置 32 | 33 | * 在公众号配置好 URL(服务器地址) 为 `http://yourdomian.com/wechat` 34 | * 如图所在位置 35 | 36 | 37 | -------------------------------------------------------------------------------- /H5/app.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var express = require('express'); 3 | var morgan = require('morgan'); 4 | var weixin = require('./util/weixin'); 5 | 6 | var app = express(); 7 | app.set('port', process.env.PORT || 3000); 8 | 9 | app.use(morgan('dev')); 10 | app.use(express.static(path.join(__dirname, 'public'))); 11 | app.set('views', __dirname + '/public/views'); 12 | app.engine('html', require('ejs').renderFile); 13 | app.set('view engine', 'html'); 14 | app.use(require('weixin-body-parser')()); 15 | 16 | // 微信公众号配置的URL 路由 17 | app.use('/wechat', weixin.trap); 18 | 19 | // H5页面需要的接口(获取签名) 20 | require('./route/handle')(app); 21 | 22 | // H5 的demo页面 23 | app.get('/*', function(req, res, next){ 24 | res.render('index'); 25 | }); 26 | 27 | app.use(function(req, res, next) { 28 | var err = new Error('Not Found'); 29 | err.status = 404; 30 | next(err); 31 | }); 32 | 33 | /* jshint unused:false */ 34 | if (app.get('env') === 'development') { 35 | app.use(function(err, req, res, next) { 36 | res.status(err.status || 500); 37 | res.json({ 38 | env: 'development', 39 | message: err.message, 40 | error: err 41 | }); 42 | }); 43 | } 44 | 45 | app.use(function(err, req, res, next) { 46 | res.status(err.status || 500); 47 | res.json({ 48 | message: err.message, 49 | error: {} 50 | }); 51 | }); 52 | 53 | var server = app.listen(app.get('port'), function(a, b){ 54 | console.log('weixin server listening on port ' + server.address().port); 55 | }); 56 | -------------------------------------------------------------------------------- /H5/config/_sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "weixin": { 3 | "id": "your weixin id", 4 | "token": "your weixin token", 5 | "appid": "your weixin app_id", 6 | "appsecret": "your weixin app_secret" 7 | }, 8 | 9 | "demoUrl": "http://youdomain.com/demo" // 你自己 iot H5 页面的完整 URL 地址 10 | } 11 | -------------------------------------------------------------------------------- /H5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wechat-iot-example", 3 | "version": "1.0.1", 4 | "description": "微信 IOT 蓝牙硬件设备操作", 5 | "main": "app.js", 6 | "dependencies": { 7 | "config": "^1.9.0", 8 | "ejs": "^1.0.0", 9 | "encode-gb2312": "^0.0.2", 10 | "express": "^4.10.6", 11 | "morgan": "^1.5.1", 12 | "weixin-body-parser": "0.0.6", 13 | "weixin-trap": "0.0.11" 14 | }, 15 | "devDependencies": {}, 16 | "scripts": { 17 | "test": "echo \"Error: no test specified\" && exit 1" 18 | }, 19 | "keywords": [ 20 | "wechat-iot-example", 21 | "wechat-iot", 22 | "iot", 23 | "wechat", 24 | "weixin", 25 | "wx" 26 | ], 27 | "author": "liuxiaodong ", 28 | "license": "ISC" 29 | } 30 | -------------------------------------------------------------------------------- /H5/public/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scripts", 3 | "version": "1.0.1", 4 | "authors": [ 5 | "liuxiaodong " 6 | ], 7 | "license": "MIT", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "tests" 14 | ], 15 | "dependencies": { 16 | "vue": "~0.11.4", 17 | "js-base64": "~2.1.6", 18 | "encode-to-gb2312": "*", 19 | "jquery": "~2.1.4", 20 | "underscore": "~1.8.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /H5/public/images/busy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/busy.gif -------------------------------------------------------------------------------- /H5/public/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/icon.png -------------------------------------------------------------------------------- /H5/public/images/icon_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/icon_round.png -------------------------------------------------------------------------------- /H5/public/images/loading.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/loading.jpg -------------------------------------------------------------------------------- /H5/public/images/scan.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/scan.gif -------------------------------------------------------------------------------- /H5/public/images/scan1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/scan1.gif -------------------------------------------------------------------------------- /H5/public/images/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/setting.png -------------------------------------------------------------------------------- /H5/public/images/voice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/voice.png -------------------------------------------------------------------------------- /H5/public/images/web-loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/H5/public/images/web-loading.gif -------------------------------------------------------------------------------- /H5/public/scripts/config_sample.js: -------------------------------------------------------------------------------- 1 | var baseUrl = "http://localhost:3000"; 2 | -------------------------------------------------------------------------------- /H5/public/scripts/drag.js: -------------------------------------------------------------------------------- 1 | ;(function(window, undefined){ 2 | Vue.directive('drag', { 3 | isLiteral: true, 4 | bind: function(){ 5 | var _pressEvents = 'touchstart mousedown'; 6 | var _moveEvents = 'touchmove mousemove'; 7 | var _releaseEvents = 'touchend mouseup'; 8 | var el = this.el; 9 | var isdrag=false; 10 | var _mx, _my, _mrx, _mry, _tx, _ty, offset, _dragOffset; 11 | 12 | function inputEvent(event) { 13 | if(event.touches && event.touches[0]){ 14 | return event.touches[0]; 15 | }else if(event.originalEvent && event.originalEvent.targetTouches && event.originalEvent.targetTouches[0]){ 16 | return event.originalEvent.targetTouches[0]; 17 | }else { 18 | return event; 19 | } 20 | } 21 | 22 | function onpress(e){ 23 | if($(e.target).data("disdrag")) return; 24 | isdrag = true; 25 | e.preventDefault(); 26 | offset = $(el).offset(); 27 | el.centerX = $(el).width() / 2; 28 | el.centerY = $(el).height() / 2; 29 | _mx = inputEvent(e).pageX; 30 | _my = inputEvent(e).pageY; 31 | _mrx = _mx - offset.left; 32 | _mry = _my - offset.top; 33 | _tx = offset.left - $(window).scrollLeft(); 34 | _ty = offset.top - $(window).scrollTop(); 35 | moveElement(_tx, _ty); 36 | $(document).on(_moveEvents, onmove); 37 | $(document).on(_releaseEvents, onrelease); 38 | } 39 | 40 | function onmove(e){ 41 | if (!isdrag) return; 42 | e.preventDefault(); 43 | _mx = inputEvent(e).pageX; 44 | _my = inputEvent(e).pageY; 45 | _tx = _mx - _mrx - $(window).scrollLeft(); 46 | _ty = _my - _mry - $(window).scrollTop(); 47 | moveElement(_tx, _ty); 48 | } 49 | 50 | function onrelease(e){ 51 | if(!isdrag) return; 52 | e.preventDefault(); 53 | $(document).off(_moveEvents, onmove); 54 | $(document).off(_releaseEvents, onrelease); 55 | } 56 | 57 | 58 | function moveElement(x, y){ 59 | $(el).css({left:x,top:y, position:'fixed', 'z-index':99999, margin: '0'}); 60 | // $(el).css({ 61 | // transform: 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ' + x + ', ' + y + ', 0, 1)', 62 | // 'z-index': 99999, 63 | // '-webkit-transform': 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ' + x + ', ' + y + ', 0, 1)', 64 | // '-ms-transform': 'matrix(1, 0, 0, 1, ' + x + ', ' + y + ')' 65 | // }); 66 | } 67 | 68 | $(el).on(_pressEvents, onpress); 69 | 70 | $(el).on("touchcancel", function(){ 71 | if(isdrag){ 72 | isdrag = false; 73 | $(document).off(_moveEvents, onmove); 74 | $(document).off(_releaseEvents, onrelease); 75 | } 76 | }); 77 | } 78 | }); 79 | 80 | 81 | })(window); -------------------------------------------------------------------------------- /H5/public/scripts/iot.js: -------------------------------------------------------------------------------- 1 | (function(window, undefined) { 2 | var reg = /(。|,|!|:|;|?)/g; // 语音解析的正则表达式,微信解析语音后会再后面加上一个标点符号 3 | var mobile = (window.navigator.userAgent.toLowerCase().indexOf("android") > -1) ? 'android' : 'iphone'; 4 | var is_nexus5 = (window.navigator.userAgent.replace(/ /g, "").toLowerCase().indexOf("nexus5") > -1); 5 | 6 | if (mobile === 'android') { 7 | $(".text-input .input-box").css("margin-top", "10px"); 8 | $(".text-input .input-box input").css("height", "25px"); 9 | $(".text-input .send button").css("margin-top", "15px"); 10 | $(".text-input .voice-icon").css("margin-top", "11px"); 11 | } 12 | 13 | if (is_nexus5) { 14 | $(".text-input .voice-btn").text("点击 说话"); 15 | } 16 | 17 | var vm, signData, openid, 18 | // 语音录制内容 19 | voice = { 20 | localId: '', 21 | serverId: '' 22 | }; 23 | 24 | // 微信 config 25 | var code = getQueryString('code'); 26 | var url = location.href.replace(location.hash, ""); 27 | url = encodeURIComponent(url); 28 | $.get(baseUrl + "/sign?url=" + url + "&code=" + code, function(data) { 29 | openid = data.openid; 30 | signData = { 31 | "verifyAppId": data.appid, 32 | "verifyTimestamp": data.timestamp, 33 | "verifySignType": "sha1", 34 | "verifyNonceStr": data.nonceStr, 35 | "verifySignature": data.signature 36 | }; 37 | wx.config({ 38 | debug: false, 39 | appId: data.appid, 40 | timestamp: data.timestamp, 41 | nonceStr: data.nonceStr, 42 | signature: data.signature, 43 | jsApiList: [ 44 | 'openWXDeviceLib', 45 | 'closeWXDeviceLib', 46 | 'getWXDeviceInfos', 47 | 'getWXDeviceTicket', 48 | 'getWXDeviceBindTicket', 49 | 'getWXDeviceUnbindTicket', 50 | 'setSendDataDirection', 51 | 'startScanWXDevice', 52 | 'stopScanWXDevice', 53 | 'connectWXDevice', 54 | 'disconnectWXDevice', 55 | 'sendDataToWXDevice', 56 | 'chooseImage', 57 | 'translateVoice', 58 | 'startRecord', 59 | 'stopRecord', 60 | 'onRecordEnd', 61 | 'playVoice', 62 | 'pauseVoice', 63 | 'stopVoice', 64 | 'uploadVoice', 65 | 'downloadVoice' 66 | ] 67 | }); 68 | }); 69 | 70 | // 获取url上的query内容 71 | function getQueryString(name) { 72 | var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); 73 | var r = window.location.search.substr(1).match(reg); 74 | if (r !== null) return unescape(r[2]); 75 | return null; 76 | } 77 | 78 | /** 79 | * 初始化 80 | * 81 | */ 82 | function init() { 83 | //checkJsApi(); 84 | openWXDeviceLib(function(err) { 85 | getWXDeviceInfos(function(err, devices) { 86 | if (err) showDialog(JSON.stringify(err)); 87 | $('.busy').hide(); 88 | vm.$data.progress = 'complete'; 89 | setDeviceData(devices); 90 | }); 91 | }); 92 | } 93 | 94 | // 微信接口config完成 95 | wx.ready(function() { 96 | init(); 97 | 98 | // 设备绑定状态发生变化 99 | WeixinJSBridge.on('onWXDeviceBindStateChange', function(argv) { 100 | //alert("bindChange:" + JSON.stringify(argv)); 101 | }); 102 | 103 | // 设备连接状态发生变化 104 | WeixinJSBridge.on('onWXDeviceStateChange', function(argv) { 105 | if (!argv) return; 106 | var flag = false; 107 | for (var i = 0; i < vm.$data.devices.length; i++) { 108 | if (vm.$data.devices[i].deviceId === argv.deviceId) { 109 | flag = true; 110 | vm.$data.devices[i].state = argv.state || 'disconnected'; 111 | } 112 | } 113 | if (!flag) { 114 | vm.$data.devices[i].push(argv); 115 | } 116 | var el; 117 | if (argv.state === 'connecting') { 118 | el = $("#" + deviceId + " #connect"); 119 | el.text(""); 120 | el.addClass('loading'); 121 | } else if (argv.state === 'connected') { 122 | el = $("#" + deviceId + " #connect"); 123 | el.text("连接"); 124 | el.removeClass('loading'); 125 | } 126 | }); 127 | 128 | WeixinJSBridge.on('onReceiveDataFromWXDevice', function(argv) { 129 | alert("receiveData: " + JSON.stringify(argv)); 130 | }); 131 | 132 | WeixinJSBridge.on('onWXDeviceBluetoothStateChange', function(argv) { 133 | if (avgv.state === 'off') { 134 | alert("请打开手机蓝牙"); 135 | } else { 136 | alert("init"); 137 | init(); 138 | } 139 | }); 140 | 141 | // 扫描到设备 142 | WeixinJSBridge.on('onScanWXDeviceResult', function(argv) { 143 | if (!argv) return; 144 | var devices = argv.devices; 145 | if (!devices || devices.length === 0) return; 146 | for (var i = 0; i < devices.length; i++) { 147 | var id = devices[i].deviceId; 148 | var flag = _.find(vm.$data.devices, function(d) { 149 | return d.deviceId === id; 150 | }); 151 | var obj = { 152 | deviceId: id 153 | }; 154 | if (!flag) vm.$data.devices.push(obj); 155 | } 156 | }); 157 | 158 | 159 | }); 160 | 161 | // 微信config失败 162 | wx.error(function(res) { 163 | alert(JSON.stringify(res)); 164 | }); 165 | 166 | // 排序 167 | Vue.filter('sortList', function(value) { 168 | if (!value || value.length === 0) return value; 169 | var arr1 = [], 170 | arr2 = [], 171 | arr3 = []; 172 | _.each(value, function(v) { 173 | if (v.state === 'connected' || v.state === 'connecting') { 174 | arr1.push(v); 175 | } else if (v.state === 'disconnected') { 176 | arr2.push(v); 177 | } else { 178 | arr3.push(v); 179 | } 180 | }); 181 | 182 | arr1 = _.sortBy(arr1, function(a1) { return a1.deviceId; }); 183 | arr2 = _.sortBy(arr2, function(a2) { return a2.deviceId; }); 184 | arr3 = _.sortBy(arr3, function(a3) { return a3.deviceId; }); 185 | return arr1.concat(arr2, arr3); 186 | }); 187 | 188 | // id如果太长,截断显示 189 | Vue.filter('truncation', function(value) { 190 | if (!value) return 'undefined'; 191 | if(value.length < 17) return value; 192 | return value.slice(0, 14) + "..."; 193 | }); 194 | 195 | Vue.transition('fade', { 196 | beforeEnter: function(el) {}, 197 | enter: function(el, done) { 198 | // element is already inserted into the DOM 199 | // call done when animation finishes. 200 | $(el) 201 | .css('opacity', 0) 202 | .css('height', 0) 203 | .animate({ 204 | opacity: 1, 205 | height: 95 206 | }, 500, done); 207 | // optionally return a "cancel" function 208 | // to clean up if the animation is cancelled 209 | return function() { 210 | $(el).stop(); 211 | }; 212 | }, 213 | leave: function(el, done) { 214 | // same as enter 215 | $(el).animate({ 216 | opacity: 0, 217 | height: 0, 218 | padding: 0, 219 | margin: 0 220 | }, 500, done); 221 | return function() { 222 | $(el).stop(); 223 | }; 224 | } 225 | }); 226 | 227 | 228 | renderView(); 229 | 230 | function renderView() { 231 | vm = new Vue({ 232 | el: '.container', 233 | data: { 234 | progress: 'complete', 235 | devices: [], 236 | currentDevice: "", 237 | deviceid: "", 238 | alias: "", 239 | debug_flag: false 240 | }, 241 | methods: { 242 | debug: function() { 243 | //this.debug_flag = !this.debug_flag; 244 | }, 245 | switchPage: function() { // 页面切换 246 | if ($(".show-container").is(":visible")) { 247 | $(".switch").text("查看说明书"); 248 | $(".show-container").hide(); 249 | $(".list").show(); 250 | } else { 251 | $(".switch").text("返回主页面"); 252 | $(".list").hide(); 253 | $(".show-container").show(); 254 | } 255 | }, 256 | switchHandle: function() { // 语音和手动输入切换 257 | if ($(".text-input .icon-control i").hasClass('edit-icon')) { 258 | $(".text-input .icon-control i").removeClass('edit-icon'); 259 | $(".text-input .icon-control i").addClass('voice-icon'); 260 | $(".text-input .send").removeClass('hide'); 261 | $(".text-input input").removeClass('hide'); 262 | $(".text-input .voice-btn").addClass('hide'); 263 | } else { 264 | $(".text-input .icon-control i").removeClass('voice-icon'); 265 | $(".text-input .icon-control i").addClass('edit-icon'); 266 | $(".text-input .send").addClass('hide'); 267 | $(".text-input input").addClass('hide'); 268 | $(".text-input .voice-btn").removeClass('hide'); 269 | } 270 | }, 271 | sendText: function(s) { // 发送数据到设备 272 | var o = _.find(vm.$data.devices, function(d) { 273 | return d.deviceId === vm.$data.currentDevice; 274 | }); 275 | if (!o) return showDialog("未选择操作设备,请选择一个"); 276 | if (!s) { 277 | s = $(".text-input input").val(); 278 | $(".text-input input").val(""); 279 | $(".text-input input").blur(); 280 | } 281 | if (!s) return showDialog("命令不能为空!"); 282 | var gb = encodeToGb2312(s) + "\n"; 283 | var buf = Base64.encode(gb); 284 | if (this.debug_flag) showDialog("原始字符串: " + s + " GB2312: " + gb, 5000); 285 | sendDataToWXDevice(o.deviceId, buf, function() {}); 286 | }, 287 | selectDevice: function(deviceId) { // 选择操作的设备 288 | var device = _.find(this.devices, function(d) { 289 | return d.deviceId === deviceId; 290 | }); 291 | if (device.state !== 'connected') { 292 | return showDialog("设备未连接!"); 293 | } 294 | this.currentDevice = deviceId; 295 | }, 296 | stopScan: function() { // 停止扫描 297 | $("#startscan").show(); 298 | $(".debug").show(); 299 | $("#stopscan").hide(); 300 | $(".scan-gif").hide(); 301 | stopScanWXDevice(function(err) { 302 | if (err) showDialog(JSON.stringify(err), 5000); 303 | }); 304 | }, 305 | startScan: function() { // 开始扫描 306 | $("#stopscan").show(); 307 | $("#startscan").hide(); 308 | $(".debug").hide(); 309 | $(".scan-gif").show(); 310 | startScanWXDevice(function(err) { 311 | if (err) showDialog(JSON.stringify(err)); 312 | }); 313 | }, 314 | bind: function(deviceId) { // 绑定设备 315 | var that = this; 316 | getWXDeviceTicket(deviceId, 1, function(err, ticket) { 317 | if (err) return showDialog(err); 318 | bindDevice(deviceId, ticket, function(err) { 319 | if (err){ 320 | var msg = "绑定失败,请退出页面后从新从公众号进入页面再进行绑定操作"; 321 | return showDialog(msg, 3000); 322 | } 323 | that.devices = _.map(that.devices, function(d) { 324 | if (d.deviceId === deviceId) { 325 | return { 326 | state: 'disconnected', 327 | deviceId: deviceId 328 | }; 329 | } else { 330 | return d; 331 | } 332 | }); 333 | }); 334 | }); 335 | }, 336 | unbind: function(deviceId) { // 解绑设备 337 | var that = this; 338 | if(confirm("解绑设备,解绑后将从列表删除!")){ 339 | getWXDeviceTicket(deviceId, 2, function(err, ticket) { 340 | if (err) return showDialog(err); 341 | unbindDevice(deviceId, ticket, function(err) { 342 | if (err) return showDialog(err); 343 | that.devices = _.filter(that.devices, function(d) { 344 | return d.deviceId !== deviceId; 345 | }); 346 | if (that.currentDevice === deviceId && that.devices.length > 0) that.currentDevice = that.devices[0].deviceId; 347 | }); 348 | }); 349 | } 350 | }, 351 | connect: function(deviceId, state) { // 连接设备 352 | if ($("#stopscan").is(":visible")) { 353 | this.stopScan(); 354 | } 355 | if (state === "connected") { 356 | showDialog("设备已经连接"); 357 | } else { 358 | var el = $("#" + deviceId + " #connect"); 359 | el.text(""); 360 | el.addClass('loading'); 361 | connectWXDevice(deviceId, function(err) { 362 | el.text("连接"); 363 | el.removeClass('loading'); 364 | if (err) return showDialog(JSON.stringify(err)); 365 | }); 366 | } 367 | }, 368 | disconnect: function(deviceId, state) { // 断开连接 369 | if ($("#stopscan").is(":visible")) { 370 | this.stopScan(); 371 | } 372 | if (state === "disconnected") { 373 | showDialog("设备已经断开连接"); 374 | } else { 375 | var el = $("#" + deviceId + " #disconnect"); 376 | el.text(""); 377 | el.addClass('loading'); 378 | disconnectWXDevice(deviceId, function(err) { 379 | el.text("断开"); 380 | el.removeClass('loading'); 381 | if (err) return showDialog(JSON.stringify(err)); 382 | }); 383 | } 384 | }, 385 | } 386 | }); 387 | } 388 | 389 | // 开始录音 390 | function startRecord() { 391 | $(".voice-btn").addClass("press"); 392 | if (!is_nexus5) { 393 | showDialog("", 60000, function() { 394 | $(".dialog .dia-body").addClass('img-voice'); 395 | }); 396 | } else { 397 | showDialog("", 60000, function() { 398 | $(".dialog .dia-body").addClass('img-voice-nexus5'); 399 | }); 400 | } 401 | wx.startRecord({ 402 | cancel: function() { 403 | showDialog('用户拒绝授权录音'); 404 | } 405 | }); 406 | } 407 | 408 | // 结束录音并解析 409 | function stopRecord() { 410 | $(".voice-btn").removeClass("press"); 411 | hideDialog(); 412 | wx.stopRecord({ 413 | success: function(res) { 414 | voice.localId = res.localId; 415 | wx.translateVoice({ 416 | localId: voice.localId, 417 | complete: function(res) { 418 | if (res.hasOwnProperty('translateResult')) { 419 | var s = res.translateResult; 420 | s = s.replace(reg, ""); 421 | var o = _.find(vm.$data.devices, function(d) { 422 | return d.deviceId === vm.$data.currentDevice; 423 | }); 424 | if (!o) return showDialog("未选择操作设备,请选择一个"); 425 | var gb = encodeToGb2312(s) + "\n"; 426 | var buf = Base64.encode(gb); 427 | if (vm.$data.debug_flag) showDialog("原始字符串: " + s + " GB2312: " + gb, 5000); 428 | sendDataToWXDevice(o.deviceId, buf, function() {}); 429 | } else { 430 | showDialog("无法识别"); 431 | } 432 | } 433 | }); 434 | }, 435 | fail: function(err) { 436 | if (err.errMsg === "stopRecord:tooshort") { 437 | showDialog("时间太短,请重试"); 438 | } else { 439 | showDialog(JSON.stringify(err)); 440 | } 441 | } 442 | }); 443 | } 444 | 445 | // 按下开始录音 446 | if (!is_nexus5) { 447 | $("body").on("touchstart", ".voice-btn", function(event) { 448 | $(".voice-btn").text("松开 结束"); 449 | startRecord(); 450 | }); 451 | 452 | $("body").on("touchmove", ".voice-btn", function(event) { 453 | event.preventDefault(); 454 | }); 455 | 456 | 457 | $("body").on("touchcancel", ".voice-btn", function(event) { 458 | event.preventDefault(); 459 | $(".voice-btn").text("按住 说话"); 460 | stopRecord(); 461 | }); 462 | 463 | // 松开录音结束 464 | $("body").on("touchend", ".voice-btn", function(event) { 465 | event.preventDefault(); 466 | $(".voice-btn").text("按住 说话"); 467 | stopRecord(); 468 | }); 469 | } 470 | 471 | /** 472 | * 对 nexus5做的定制 473 | * nexus5 在调用 wx.startRecord后不会触发 touchmove 和 touchend事件,直接触发了 touchcancel事件 474 | * 475 | */ 476 | if (is_nexus5) { 477 | $("body").on("click", ".voice-btn", function(event) { 478 | if ($(".voice-btn").hasClass("press")) { 479 | $(".voice-btn").text("点击 说话"); 480 | stopRecord(); 481 | } else { 482 | $(".voice-btn").text("点击 结束"); 483 | startRecord(); 484 | } 485 | }); 486 | } 487 | 488 | // 监听录音自动停止,超过一分钟则停止 489 | wx.onVoiceRecordEnd({ 490 | complete: function(res) { 491 | $(".voice-btn").removeClass("press"); 492 | hideDialog(); 493 | voice.localId = res.localId; 494 | wx.translateVoice({ 495 | localId: voice.localId, 496 | complete: function(res) { 497 | if (res.hasOwnProperty('translateResult')) { 498 | var s = res.translateResult; 499 | s = s.replace(reg, ""); 500 | var o = _.find(vm.$data.devices, function(d) { 501 | return d.deviceId === vm.$data.currentDevice; 502 | }); 503 | if (!o) return showDialog("未选择操作设备,请选择一个"); 504 | var gb = encodeToGb2312(s) + "\n"; 505 | var buf = Base64.encode(gb); 506 | if (vm.$data.debug_flag) showDialog("原始字符串: " + s + " GB2312: " + gb, 5000); 507 | sendDataToWXDevice(o.deviceId, buf, function() {}); 508 | } else { 509 | showDialog("无法识别"); 510 | } 511 | } 512 | }); 513 | } 514 | }); 515 | 516 | // 监听录音播放结束 517 | wx.onVoicePlayEnd({ 518 | complete: function(res) { 519 | showDialog('录音播放结束'); 520 | } 521 | }); 522 | 523 | 524 | /* 525 | * jsapi接口的封装 526 | */ 527 | function checkJsApi() { 528 | wx.checkJsApi({ 529 | jsApiList: ['getWXDeviceTicket'], 530 | success: function(res) { 531 | //alert(JSON.stringify(res)); 532 | } 533 | }); 534 | } 535 | 536 | // 列表添加设备 537 | function setDeviceData(devices) { 538 | if (devices && devices.length > 0) { 539 | $('.no-device').addClass('hide'); 540 | for (var i = 0; i < devices.length; i++) { 541 | var obj = devices[i]; 542 | if (!vm.$data.currentDevice && obj.state === 'connected') { 543 | vm.$data.currentDevice = obj.deviceId; 544 | } 545 | var flag = _.find(vm.$data.devices, function(d) { 546 | return d.deviceId === obj.deviceId; 547 | }); 548 | if (!flag) vm.$data.devices.push(obj); 549 | } 550 | } 551 | } 552 | 553 | function openWXDeviceLib(cb) { 554 | WeixinJSBridge.invoke('openWXDeviceLib', signData, function(res) { 555 | if (res.err_msg === 'openWXDeviceLib:ok') return cb(null, 'ok'); 556 | return cb(res); 557 | }); 558 | } 559 | 560 | function closeWXDeviceLib(cb) { 561 | WeixinJSBridge.invoke('closeWXDeviceLib', signData, function(res) { 562 | if (res.err_msg === 'closeWXDeviceLib:ok') return cb(null, 'ok'); 563 | return cb(res); 564 | }); 565 | } 566 | 567 | 568 | function getWXDeviceInfos(cb) { 569 | WeixinJSBridge.invoke('getWXDeviceInfos', signData, function(res) { 570 | if (res.err_msg === 'getWXDeviceInfos:ok') return cb(null, res.deviceInfos); 571 | return cb(res); 572 | }); 573 | } 574 | 575 | function connectWXDevice(deviceId, cb) { 576 | var _data = mixin({ 577 | "deviceId": deviceId 578 | }, signData); 579 | WeixinJSBridge.invoke('connectWXDevice', _data, function(res) { 580 | if (res.err_msg === 'connectWXDevice:ok') return cb(null, null); 581 | return cb(res); 582 | }); 583 | } 584 | 585 | function disconnectWXDevice(deviceId, cb) { 586 | var _data = mixin({ 587 | "deviceId": deviceId 588 | }, signData); 589 | WeixinJSBridge.invoke('disconnectWXDevice', _data, function(res) { 590 | if (res.err_msg && res.err_msg.toLowerCase() === 'disconnectwxdevice:ok') return cb(null, null); 591 | return cb(res); 592 | }); 593 | } 594 | 595 | var send_flag = false; // 是否正在给某个设备发送数据 596 | var retry_count_total = 5; // 重试次数 597 | function sendDataToWXDevice(deviceId, buf, cb, retry_count) { 598 | var _data = mixin({ 599 | "deviceId": deviceId, 600 | "base64Data": buf 601 | }, signData); 602 | // 若正在给某个设备发送数据,则等待 10 ms 重试 603 | if (!retry_count) retry_count = 0; 604 | if (send_flag && retry_count < retry_count_total) { 605 | return setTimeout(function() { 606 | sendDataToWXDevice(deviceId, buf, cb, ++this.retry_count); 607 | }.bind({retry_count: retry_count}), 10); 608 | } else if (send_flag && retry_count >= retry_count_total) { // 重试 5 次后直接发送数据 609 | send_flag = false; 610 | sendDataToWXDevice(deviceId, buf, cb, retry_count); 611 | } 612 | send_flag = true; 613 | WeixinJSBridge.invoke('sendDataToWXDevice', _data, function(res) { 614 | send_flag = false; 615 | if (res.err_msg === 'sendDataToWXDevice:ok') return cb(null, null); 616 | return cb(res); 617 | }); 618 | } 619 | 620 | function startScanWXDevice(cb) { 621 | var _data = mixin({ 622 | btVersion: 'ble' 623 | }, signData); 624 | WeixinJSBridge.invoke('startScanWXDevice', _data, function(res) { 625 | if (res.err_msg === 'startScanWXDevice:ok') return cb(null, 'ok'); 626 | cb(res); 627 | }); 628 | } 629 | 630 | function stopScanWXDevice(cb) { 631 | WeixinJSBridge.invoke('stopScanWXDevice', signData, function(res) { 632 | if (res.err_msg === 'stopScanWXDevice:ok') return cb(null, 'ok'); 633 | cb(res); 634 | }); 635 | } 636 | 637 | function getWXDeviceTicket(deviceId, type, cb) { 638 | var _data = mixin({ 639 | "deviceId": deviceId, 640 | type: type 641 | }, signData); 642 | WeixinJSBridge.invoke('getWXDeviceTicket', _data, function(res) { 643 | if (res.err_msg === 'getWXDeviceTicket:ok') return cb(null, res.ticket); 644 | return cb(res); 645 | }); 646 | } 647 | 648 | function bindDevice(deviceId, ticket, cb) { 649 | $.ajax({ 650 | url: baseUrl + "/bind", 651 | type: 'POST', 652 | data: { 653 | openid: openid, 654 | deviceid: deviceId, 655 | ticket: ticket 656 | }, 657 | dataType: 'json', 658 | success: function(data) { 659 | cb(null, data); 660 | }, 661 | error: function(err){ 662 | cb(err.responseText); 663 | } 664 | }); 665 | } 666 | 667 | function unbindDevice(deviceId, ticket, cb) { 668 | $.post(baseUrl + "/unbind", { 669 | openid: openid, 670 | deviceid: deviceId, 671 | ticket: ticket 672 | }, function(data) { 673 | if (data === 'ok') { 674 | return cb(null, null); 675 | } 676 | return cb(data); 677 | }); 678 | } 679 | 680 | 681 | // 工具集 682 | function mixin(dest, src) { 683 | Object.getOwnPropertyNames(src).forEach(function(name) { 684 | var descriptor = Object.getOwnPropertyDescriptor(src, name); 685 | Object.defineProperty(dest, name, descriptor); 686 | }); 687 | return dest; 688 | } 689 | 690 | var dialog_timer = null; 691 | 692 | function showDialog(msg, time, fn) { 693 | time = time ? (Number(time) || 1000) : 1000; 694 | $(".dialog .dia-body").text(msg); 695 | $(".dialog .dia-body").removeClass('img-voice'); 696 | $(".dialog .dia-body").removeClass('img-voice-nexus5'); 697 | if (typeof fn === "function") fn(); 698 | var top = 0; 699 | if (msg) { 700 | len = msg.replace(/[^\x00-\xff]/g, "xx").length; 701 | if (len <= 16) { 702 | top = 40; 703 | } else if (len <= 32) { 704 | top = 30; 705 | } else if (len <= 46) { 706 | top = 22; 707 | } else if (len <= 62) { 708 | top = 10; 709 | } 710 | } 711 | $(".dialog-content .dia-body").css("margin-top", top); 712 | $(".dialog").show(); 713 | if (dialog_timer) { 714 | clearTimeout(dialog_timer); 715 | dialog_timer = null; 716 | } 717 | dialog_timer = setTimeout(hideDialog, time); 718 | } 719 | 720 | function hideDialog() { 721 | $(".dialog").hide(); 722 | $(".dialog .dia-body").text(""); 723 | $(".dialog .dia-body").removeClass('img-voice'); 724 | $(".dialog .dia-body").removeClass('.img-voice-nexus5'); 725 | $(".dialog-content .dia-body").css("margin-top", 0); 726 | if (dialog_timer) clearTimeout(dialog_timer); 727 | dialog_timer = null; 728 | } 729 | 730 | $("body").on("click", ".dialog .dia-header .close", function() { 731 | $(".dialog").hide(); 732 | $(".dialog .dia-body").text(""); 733 | $(".dialog .dia-body").removeClass("img-voice"); 734 | }); 735 | 736 | function showModal() { 737 | $(".modal").show(); 738 | } 739 | 740 | function hideModal() { 741 | $(".modal").hide(); 742 | } 743 | 744 | $("body").on("click", ".modal .modal-header .close, .close-btn", function() { 745 | hideModal(); 746 | }); 747 | 748 | 749 | window.onload = function() {  750 | $('.container').removeClass('hidden'); 751 | }; 752 | 753 | })(window); 754 | -------------------------------------------------------------------------------- /H5/public/style/iot.css: -------------------------------------------------------------------------------- 1 | .dis-select { 2 | -webkit-user-select: none; 3 | } 4 | 5 | * { 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | background: #282828; 11 | min-height: 615px; 12 | color: white; 13 | } 14 | 15 | .hide { 16 | display: none; 17 | } 18 | 19 | .opacity-hide { 20 | opacity: 0; 21 | } 22 | 23 | .hidden { 24 | visibility:hidden; 25 | } 26 | 27 | .device-list { 28 | text-align: center; 29 | } 30 | 31 | .device-info { 32 | position: relative; 33 | background: #333333; 34 | border-radius: 10px; 35 | width: 90%; 36 | margin: 10px auto; 37 | padding: 10px 10px 15px 10px; 38 | } 39 | 40 | .list .header { 41 | height: 50px; 42 | margin-bottom: 10px; 43 | border-bottom: solid #2e2e2e 1px; 44 | } 45 | 46 | .device-id { 47 | word-wrap: break-word; 48 | } 49 | 50 | .line-space { 51 | margin-top: 7px; 52 | margin-bottom: 7px; 53 | height: 1px; 54 | background: #2e2e2e; 55 | } 56 | 57 | .info { 58 | height: 25px; 59 | line-height: 25px; 60 | padding: 5px; 61 | } 62 | 63 | .info .state { 64 | float: left; 65 | clear: both; 66 | } 67 | 68 | .btns { 69 | float: right; 70 | } 71 | 72 | .light {l 73 | float: right; 74 | background: #626262; 75 | border-radius: 4px; 76 | height: 20px; 77 | padding: 5px; 78 | line-height: 20px; 79 | margin-left: 10px; 80 | color: white; 81 | font-size: 14px; 82 | height: 30px; 83 | border: 0; 84 | min-width: 50px; 85 | } 86 | 87 | .light.loading{ 88 | color: #000; 89 | } 90 | 91 | .loading { 92 | background: url(../images/loading.jpg) no-repeat; 93 | background-position: -13px -20px; 94 | background-size: 140%; 95 | } 96 | 97 | .img-voice { 98 | background: url(../images/voice.png) no-repeat; 99 | background-position: 48px 5px; 100 | background-size: 31%; 101 | width: 100%; 102 | height: 100px; 103 | } 104 | 105 | .img-voice:after { 106 | content: "松开手指结束"; 107 | top: 90px; 108 | position: absolute; 109 | left: 42px; 110 | font-size: 14px; 111 | } 112 | 113 | .img-voice-nexus5 { 114 | background: url(../images/voice.png) no-repeat; 115 | background-position: 48px 5px; 116 | background-size: 31%; 117 | width: 100%; 118 | height: 100px; 119 | } 120 | 121 | .img-voice-nexus5:after { 122 | content: "再次点击结束"; 123 | top: 90px; 124 | position: absolute; 125 | left: 42px; 126 | font-size: 14px; 127 | } 128 | 129 | .busy { 130 | background: url(../images/busy.gif) no-repeat; 131 | background-size: 100%; 132 | width: 70px; 133 | height: 70px; 134 | margin: 0 auto; 135 | } 136 | 137 | .btn { 138 | margin: 0 auto; 139 | height: 40px; 140 | width: 210px; 141 | background: #626262; 142 | line-height: 40px; 143 | padding: 5px; 144 | border-radius: 10px; 145 | text-align: center; 146 | margin-bottom: 30px; 147 | } 148 | 149 | .scan-btn { 150 | width: 100px; 151 | float: right; 152 | margin-right: 10px; 153 | line-height: 40px; 154 | padding: 5px; 155 | text-align: right; 156 | color: white; 157 | } 158 | 159 | .header-left { 160 | float: left; 161 | width: 50px; 162 | height: 50px; 163 | } 164 | 165 | .scan-gif { 166 | background: url(../images/scan1.gif) no-repeat; 167 | background-size: 100%; 168 | background-position: 0px 6px; 169 | } 170 | 171 | .debug { 172 | width: auto; 173 | text-align: center; 174 | line-height: 50px; 175 | margin-left: 15px; 176 | } 177 | 178 | .debug input[type="checkbox"] { 179 | border: 0; 180 | } 181 | 182 | .modal.shade { 183 | position: fixed; 184 | top: 0px; 185 | right: 0px; 186 | bottom: 0px; 187 | left: 0px; 188 | z-index: 1050; 189 | overflow-y: scroll; 190 | overflow-x: auto; 191 | outline: 0px; 192 | -webkit-box-sizing: border-box; 193 | -moz-box-sizing: border-box; 194 | box-sizing: border-box; 195 | background: rgba(0,0,0,0.8); 196 | } 197 | 198 | .dialog-content, .modal-content{ 199 | width: 150px; 200 | height: 110px; 201 | background: rgba(0,0,0,.8); 202 | color: white; 203 | padding: 10px; 204 | border-radius: 10px; 205 | left: 28%; 206 | position: fixed; 207 | top: 150px; 208 | font-size: 20px; 209 | } 210 | 211 | .dialog-content .dia-body { 212 | height: 100%; 213 | text-align: center; 214 | word-wrap: break-word; 215 | overflow-y: auto; 216 | } 217 | 218 | .dialog-content .dia-body.img-voice { 219 | line-height: 2; 220 | padding-top: 0; 221 | } 222 | 223 | .dia-header .close, .modal-content .close { 224 | float: right; 225 | margin: -10px -9px 0px -17px; 226 | width: 25px; 227 | height: 25px; 228 | text-align: center; 229 | line-height: 25px; 230 | cursor: pointer; 231 | font-family: Lato,Calibri,Arial,sans-serif; 232 | } 233 | 234 | .modal-content { 235 | background: #282828; 236 | width: 250px; 237 | height: 180px; 238 | left: 16%; 239 | padding: 0; 240 | } 241 | 242 | .modal-header { 243 | padding: 10px; 244 | border-bottom: solid #2e2e2e 1px; 245 | } 246 | 247 | .modal-footer { 248 | text-align: right; 249 | border-top: solid #2e2e2e 1px; 250 | } 251 | 252 | .modal-header h4 { 253 | margin: 0; 254 | } 255 | 256 | .modal-header .close { 257 | margin: -28px -5px 0px 0px; 258 | } 259 | 260 | .modal-body { 261 | text-align: center; 262 | } 263 | 264 | .modal-body input{ 265 | margin: 20px 0; 266 | height: 35px; 267 | width: 200px; 268 | border-radius: 4px; 269 | font-size: 18px; 270 | background: #333333; 271 | color: white; 272 | } 273 | 274 | .modal-footer button { 275 | width: 60px; 276 | height: 30px; 277 | border-radius: 5px; 278 | margin-top: 8px; 279 | background: #626262; 280 | color: white; 281 | font-size: 14px; 282 | } 283 | 284 | .current { 285 | position: absolute; 286 | display: block; 287 | float: left; 288 | margin-top: 4px; 289 | clear: both; 290 | left: 35px; 291 | font-size: 12px; 292 | color: #A5A1A1; 293 | } 294 | 295 | .current:before { 296 | content: ''; 297 | position: absolute; 298 | background: #79ff79; 299 | height: 15px; 300 | width: 15px; 301 | border-radius: 8px; 302 | left: -20px; 303 | top: -2px; 304 | } 305 | 306 | .setting { 307 | position: absolute; 308 | right: 10px; 309 | margin-top: 0px; 310 | background: url(../images/setting.png) no-repeat; 311 | height: 30px; 312 | width: 30px; 313 | background-size: 60%; 314 | } 315 | 316 | .show { 317 | width: 100px; 318 | height: 100px; 319 | background: #ededed; 320 | border-radius: 50px; 321 | text-align: center; 322 | line-height: 6; 323 | margin: 80px auto; 324 | color: #000; 325 | } 326 | 327 | .show.loading { 328 | background: #EF9393; 329 | } 330 | 331 | .switch { 332 | background: #21bf9a; 333 | color: white; 334 | height: 40px; 335 | line-height: 40px; 336 | font-size: 18px; 337 | text-align: center; 338 | } 339 | 340 | .description { 341 | margin-left: 20px; 342 | } 343 | 344 | .space { 345 | height: 50px; 346 | } 347 | 348 | .text-input { 349 | position: fixed; 350 | bottom: 0px; 351 | width: 100%; 352 | height: 50px; 353 | background-color: #282828; 354 | border-top: solid #2e2e2e 1px; 355 | } 356 | 357 | .icon-control { 358 | float: left; 359 | width: 42px; 360 | height: 100%; 361 | } 362 | 363 | .text-input .voice-icon { 364 | display: block; 365 | height: 25px; 366 | width: 25px; 367 | margin: 13px 0 0 9px; 368 | background: url(../images/icon_round.png) no-repeat; 369 | background-size: 290%; 370 | background-position: -48px 0px; 371 | } 372 | 373 | .text-input .edit-icon { 374 | display: block; 375 | height: 25px; 376 | width: 25px; 377 | margin: 13px 0 0 9px; 378 | background: url(../images/icon_round.png) no-repeat; 379 | background-size: 290%; 380 | } 381 | 382 | .text-input .input-box { 383 | color: white; 384 | margin-top: 8px; 385 | right: 61px; 386 | position: absolute; 387 | left: 42px; 388 | padding-right: 10px; 389 | } 390 | 391 | .text-input .input-box input { 392 | border-radius: 4px; 393 | font-size: 18px; 394 | background-color: #333333; 395 | color: white; 396 | width: 100%; 397 | } 398 | 399 | .text-input .send { 400 | float: right; 401 | height: 100%; 402 | width: 61px; 403 | color: white; 404 | font-size: 13px; 405 | text-align: right; 406 | } 407 | 408 | .text-input .send button { 409 | float: right; 410 | margin-top: 17px; 411 | display: block; 412 | margin-right: 19px; 413 | background: #282828; 414 | padding: 0; 415 | color: white; 416 | font-size: 13px; 417 | border: 0; 418 | } 419 | 420 | .text-input .voice-btn { 421 | height: 31px; 422 | border: solid #333333 1px; 423 | margin-top: 8px; 424 | line-height: 31px; 425 | text-align: center; 426 | font-size: 14px; 427 | border-radius: 4px; 428 | background: #333333; 429 | color: white; 430 | right: 19px; 431 | position: absolute; 432 | left: 42px; 433 | } 434 | 435 | .voice-btn.press { 436 | opacity: 0.5; 437 | } 438 | 439 | .base-controll { 440 | padding: 5px; 441 | margin-top: 10px; 442 | overflow: hidden; 443 | } 444 | 445 | .base-controll:before { 446 | content: '基本功能模块'; 447 | font-size: 12px; 448 | float: left; 449 | color: #A5A1A1; 450 | } 451 | 452 | .menu-down:before { 453 | content: '▲'; 454 | } 455 | 456 | .base-controll .fun-btns { 457 | padding-top: 20px; 458 | text-align: left; 459 | } 460 | 461 | .base-controll .light{ 462 | width: 50px; 463 | margin-top: 10px; 464 | margin-right: 10px; 465 | margin-left: 0; 466 | } -------------------------------------------------------------------------------- /H5/public/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IOT 6 | 7 | 8 | 9 | 10 | 11 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /H5/route/handle.js: -------------------------------------------------------------------------------- 1 | var config = require('config'); 2 | var weixin = require('../util/weixin'); 3 | 4 | var appid = config.weixin.appid; 5 | 6 | module.exports = function(app){ 7 | 8 | /** 9 | * jssdk 签名, 供H5页面调用 10 | * 11 | * @param {String} url H5 当前页面的 url(去掉 hash) 12 | */ 13 | 14 | // 缓存 code 对应的 openid,以免页面刷新后获取不到 openid 15 | var codeMap = {}; 16 | var getOpenid = function(code, callback) { 17 | if (codeMap[code]) { 18 | return callback(null, codeMap[code]); 19 | } 20 | weixin.api.getOauthAccessToken(appid, code, function(err, data){ 21 | var openid = data && data.openid; 22 | if (openid) { 23 | codeMap[code] = openid; 24 | } 25 | return callback(err, openid); 26 | }); 27 | }; 28 | 29 | app.get('/sign', function(req, res){ 30 | var url = req.query.url; 31 | var code = req.query.code; 32 | if (!url) { 33 | return res.status(400).json({errMsg: "need url"}); 34 | } 35 | url = decodeURIComponent(url); 36 | // 若有 code,说明用户是通过授权近入的页面,通过接口那个用户的 openid,页面绑定设备时需用 37 | if (code) { 38 | getOpenid(code, function(err, openid){ 39 | weixin.api.getTicketToken(function(err, token){ 40 | if (!token) return res.json({}); 41 | var ret = weixin.util.getJsConfig(token.ticket, url); 42 | ret.appid = config.weixin.appid; 43 | ret.openid = openid; 44 | console.log('token: ', token); 45 | console.log('signData: ', ret); 46 | res.json(ret); 47 | }); 48 | }); 49 | } else { 50 | weixin.api.getTicketToken(function(err, token){ 51 | if (!token) return res.json({}); 52 | var ret = weixin.util.getJsConfig(token.ticket, url); 53 | ret.appid = config.weixin.appid; 54 | console.log('token: ', token); 55 | console.log('signData: ', ret); 56 | res.json(ret); 57 | }); 58 | } 59 | }); 60 | 61 | /** 62 | * 绑定设备 63 | * 64 | * @param {String} openid 微信用户的 openid 65 | * @param {String} deviceid 设备 id 66 | * @param {String} ticket H5 页面生成的 ticket(若没有此参数则强制绑定) 67 | */ 68 | app.post('/bind', function (req, res) { 69 | var openid = req.body.openid; 70 | var deviceid = req.body.deviceid; 71 | var ticket = req.body.ticket; 72 | if (!openid || !deviceid) { 73 | return res.status(400).json({errmsg: 'Parameter error'}); 74 | } 75 | if (ticket) { 76 | weixin.api.bindDevice(appid, deviceid, openid, ticket, function(err){ 77 | if (err) { 78 | return res.json(400).json({errMsg: 'Bind failure', info: JSON.stringify(err)}); 79 | } 80 | res.json('ok'); 81 | }); 82 | } else { // 强制绑定 83 | weixin.api.compelBindDevice(appid, deviceid, openid, function(err){ 84 | if (err) { 85 | return res.json(400).json({errMsg: 'Bind failure', info: JSON.stringify(err)}); 86 | } 87 | res.json('ok'); 88 | }); 89 | } 90 | }); 91 | 92 | /** 93 | * 解绑设备 94 | * 95 | * @param {String} openid 微信用户的 openid 96 | * @param {String} deviceid 设备 id 97 | * @param {String} ticket H5 页面生成的 ticket(若没有此参数则强制解绑) 98 | */ 99 | app.post('/unbind', function(req, res){ 100 | var ticket = req.body.ticket; 101 | var openid = req.body.openid; 102 | var deviceid = req.body.deviceid; 103 | if (!openid || !deviceid) { 104 | return res.status(400).json({errmsg: 'Parameter error'}); 105 | } 106 | if (ticket) { 107 | weixin.api.unbindDevice(appid, deviceid, openid, ticket, function(err){ 108 | if (err) { 109 | return res.json(400).json({errMsg: 'Bind failure', info: JSON.stringify(err)}); 110 | } 111 | res.json('ok'); 112 | }); 113 | } else { // 强制绑定 114 | weixin.api.compelUnbindDevice(appid, deviceid, openid, function(err){ 115 | if (err) { 116 | return res.json(400).json({errMsg: 'Bind failure', info: JSON.stringify(err)}); 117 | } 118 | res.json('ok'); 119 | }); 120 | } 121 | }); 122 | 123 | }; -------------------------------------------------------------------------------- /H5/util/weixin.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | var config = require('config'); 4 | var gb2312 = require('encode-gb2312'); 5 | 6 | var accessTokenFile = path.join(__dirname, '../access_token.txt'); 7 | 8 | if (!fs.existsSync(accessTokenFile)) { 9 | fs.appendFileSync(accessTokenFile, '', {encoding: 'utf8'}); 10 | } 11 | 12 | var jsApiTicketFile = path.join(__dirname, '../jsapi_ticket.txt'); 13 | 14 | if (!fs.existsSync(jsApiTicketFile)) { 15 | fs.appendFileSync(jsApiTicketFile, '', {encoding: 'utf8'}); 16 | } 17 | 18 | var noop = function(){}; 19 | 20 | var weixin = require("weixin-trap")({ 21 | getBody: false, 22 | parseXml: false, 23 | populate_user: false, 24 | attrNameProcessors: 'underscored', 25 | saveToken: function(token, callback){ 26 | token.saveTime = new Date().getTime(); 27 | var tokenStr = JSON.stringify(token); 28 | fs.writeFile(accessTokenFile, tokenStr, {encoding: 'utf8'}, callback); 29 | }, 30 | getToken: function(callback){ 31 | fs.readFile(accessTokenFile, {encoding: 'utf8'}, function(err, str){ 32 | var token; 33 | if (str) { 34 | token = JSON.parse(str); 35 | } 36 | var time = new Date().getTime(); 37 | if (token && (time - token.saveTime) < ((token.expireTime - 120) * 1000) ) { 38 | return callback(null, token); 39 | } 40 | callback(); 41 | }); 42 | }, 43 | saveTicketToken: function(appid, type, token, callback) { 44 | token.saveTime = new Date().getTime(); 45 | var tokenStr = JSON.stringify(token); 46 | fs.writeFile(jsApiTicketFile, tokenStr, {encoding: 'utf8'}, callback); 47 | }, 48 | getTicketToken: function(callback) { 49 | fs.readFile(jsApiTicketFile, {encoding: 'utf8'}, function(err, str){ 50 | var token; 51 | if (str) { 52 | token = JSON.parse(str); 53 | } 54 | var time = new Date().getTime(); 55 | if (token && (time - token.saveTime) < ((token.expireTime - 120) * 1000) ) { 56 | return callback(null, token); 57 | } 58 | weixin.api.getTicket(config.weixin.id, 'jsapi', function(err, token){ 59 | if (err) { 60 | console.log('获取 jsapi 签名出错: ', err); 61 | } 62 | callback(null, token); 63 | }); 64 | }); 65 | }, 66 | config: { 67 | id: config.weixin.id, // 微信公众号 id 68 | appid: config.weixin.appid, 69 | token: config.weixin.token, 70 | appsecret: config.weixin.appsecret, 71 | encryptkey: config.weixin.encryptkey // 若公众号配置加密 key,则必填此参数 72 | } 73 | }); 74 | 75 | var appid = config.weixin.appid; 76 | 77 | var menu = { 78 | button: [ 79 | { 80 | name: '官网', 81 | type: 'view', 82 | url: 'http://www.sensoro.com' 83 | }, 84 | { 85 | name: '订购', 86 | type: 'view', 87 | url: 'http://www.sensoro.com/zh/order' 88 | }, 89 | { 90 | 'name': '微信硬件之旅', 91 | 'type': 'view', 92 | 'url' : 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + appid + '&redirect_uri=' + config.demoUrl + '?action=viewtest&response_type=code&scope=snsapi_base&state=1#wechat_redirect' 93 | } 94 | ] 95 | }; 96 | // 创建菜单 97 | weixin.api.createMenu(appid, menu, function(err, ret){ 98 | if (err){ 99 | console.log('创建菜单失败: ' + JSON.stringify(err)); 100 | } else { 101 | console.log('创建菜单成功'); 102 | } 103 | }); 104 | 105 | /** 106 | * 用户关注公众号时给用户推送一条图文消息 107 | */ 108 | weixin.trap.subscribe(function(req, res){ 109 | var news = [ 110 | { 111 | title: 'SENSORO IOT 开发者套件', 112 | description: 'SMART TAG KIT,开启智能硬件的微信之旅。', 113 | pic_url: 'http://mmbiz.qpic.cn/mmbiz/MLoSLUepSAUicFkVMvrXopwgDYk1ibnQPSdDedFDc4LqDhIpicHoCSSKpEpwrSmIYTc1iakPIicInib9cwG9wuFhFeOw/640?wx_fmt=jpeg&tp=webp&wxfrom=5', 114 | url: 'http://mp.weixin.qq.com/s?__biz=MzA4NzY0NzIwNA==&mid=208501245&idx=1&sn=cd8d02239a6d0676a38475bdd3578db0&key=1936e2bc22c2ceb56109026562aab17ea5e7d58279452994c7598f38d5f5dd4c422fe0d1b7649f82fa210bfcde5e14f6&ascene=0&uin=MTA1ODcyNTU0MQ%3D%3D&devicetype=iMac+MacBookPro11%2C1+OSX+OSX+10.10.3+build(14D136)&version=11000006&pass_ticket=yFB37OPAOKmVAr206aivWMLsyB3oXYkw1tgl2Wdqw%2FGHrXsigb%2FgTlg129q5Kg0N' 115 | } 116 | ]; 117 | res.news(news); 118 | }); 119 | 120 | // 缓存用户想要控制的设备 ID 对应关系 121 | var user_devices_map = {}; 122 | 123 | /** 124 | * 处理微信用户发送到公众号的文本消息 125 | * 126 | * 用户可以直接通过微信公众号界面输入框控制设备 127 | */ 128 | weixin.trap.text(/\S/, function(req, res){ 129 | var wechat_id = req.body.to_user_name; 130 | var openid = req.body.from_user_name; 131 | var content = req.body.content; 132 | if(!content) return res.text(''); 133 | content = content.trim(); 134 | var content_lower = content.toLowerCase(); 135 | // 微信用户必须首先告诉系统想要控制的设备 id 136 | // example: device:123456 137 | // 控制设备 ID 为 123456 的蓝牙涉笔 138 | if (content_lower.indexOf('device:') === 0 || content_lower.indexOf('device:') === 0) { 139 | var deviceid = content_lower.replace('device:', '').replace('device:', '').trim(); 140 | user_devices_map[openid] = deviceid; 141 | res.text('现在可以往设备: ' + deviceid + ' 上发送消息了。'); 142 | } else if(content_lower === 'list') { 143 | // 列表用户绑定的设备 144 | // example: list 145 | res.text('设备列表'); 146 | weixin.api.getBindDevice(appid, openid, function(err, ret){ 147 | var devices = ret.device_list; 148 | var ds = ''; 149 | for(var i=0; i SENSORO 公众号 -> IOT 页面 -> 绑定并连接设备(自动连接) 13 | -> 语音输入 -> 蓝牙发送转码命令 -> SMART TAG 接受命令 -> SMART TAG 串口输出命令 14 | -> 智能硬件开发板 解析命令 -> 智能硬件开发板 控制 IOT 体验板 -> RGB灯或者电机响应命令 15 | 16 | ####一、IOT 页面 17 | 主要功能:与 SMART TAG 通讯,完成绑定、连接等操作。支持语音向 SMART TAG 发送命令,如语音输入“蓝色”,iot页面将命令进行GB2312转码为“C0B6C9AB”,然后传递给 SMART TAG。 18 | 19 | ####二、SMART TAG 20 | 主要功能:接受微信客户端的命令,通过串口经过 IOT 体验板传递给 智能硬件开发板。所有的命令均使用GB2312编码,我们将 Arduino D6、D7 两个io口模拟成的虚拟串口来接受 SMART TAG 传递的命令。 21 | 22 | ####三、智能硬件开发板 23 | 主要功能:通过 D6、D7 模拟的虚拟串口接收 SMART TAG 的指令。如收到“蓝色”对于编码命令“C0B6C9AB”,智能硬件开发板 将通过控制自己的io口来控制 SENSORO IOT 体验板。 24 | 25 | ####四、SENSORO IOT 体验板 26 | 主要功能:集成RGB灯、电机、温度湿度传感器、红外传感器等元件,提供 SMART TAG 插槽并将其串口与 智能硬件开发板 接口对接。 27 | 28 | ##智能硬件开发板接口对应表 29 | 开发者可以为 SMART TAG KIT 中的 智能硬件开发板 编写程序,来实现功能的自定义。 30 | 下面列出已被占用的 智能硬件开发板 接口: 31 | 32 | ####虚拟串口,与 SMART TAG 进行串口通讯 33 | RX :D6 34 | TX :D7 35 | ####RGB灯 36 | SCL :A5 37 | SDA :A4 38 | ####电机 39 | ANODE : D5 40 | CATHODE :D4 41 | ####温湿度传感器 42 | PIN :D3 43 | 44 | 45 | ##体验步骤 46 | 1. 用 USB 线为 智能硬件开发板 板子供电 47 | 2. 微信扫描随机附赠卡片上的二维码绑定设备 48 | 3. 打开 SENSORO 微信公众号,进入IOT页面 49 | 4. 当设备连接成功后,语音输入命令 50 | 5. 开发者套件响应命令 51 | 52 | #####已支持的命令: 53 | 蓝色、红色、绿色、变、闪、熄灭。 54 | 转、加速、减速、停。 55 | 温度、湿度。 56 | 57 | 58 | ##开始动手 59 | ####相关资源 60 | 开发者套件中的 智能硬件开发板 兼容 Arduino。 61 | * Arduino 官网 http://arduino.cc/ 62 | * Arduino 中文社区 http://www.arduino.cn/ 63 | * Arduino IDE链接 http://arduino.cc/en/Main/Software 64 | 65 | ####如何开发 66 | 1. 打开 IDE 67 | 2. 打开 DEMO 工程 wechat\wechat_hardware\wechat_hardware.ino 68 | 3. 导入库:项目-->导入库-->添加库-->添加wechat\lib下的各个压缩包。 69 | 4. 添加指令:查找需要添加的中文指令的GB2312码,添加到宏定义处。 70 | (提示:直接用微信公众号说指令,页面上会有相应的GB2312码) 71 | 72 | //Cmd, which is the GB2312 codes of the Chinese character 73 | #define GB_XIMIE "CFA8C3F0" 74 | #define GB_LANSE "C0B6C9AB" 75 | ... 76 | 5. 添加相应的指令解析执行代码 77 | 78 | ... 79 | if(!memcmp(cmd.data,GB_XIMIE,cmd.len)){ 80 | flag_rgb_blink=false; 81 | flag_rgb_rainbow=false; 82 | rgbLed.setColorRGB(0,0,0); 83 | } 84 | else if(!memcmp(cmd.data,GB_LANSE,cmd.len)){ 85 | flag_rgb_blink=false; 86 | flag_rgb_rainbow=false; 87 | rgbLed.setColorRGB(0,0,255); 88 | } 89 | ... 90 | 6. 验证、上传代码至 智能硬件开发板 91 | 7. 测试 92 | 93 | ##重要提示 94 | 扩展板上的按键不要按! 95 | 原因:由于 智能硬件开发板 只有一个串口,向板子里下载程序要用此串口。微信硬件蓝牙模块也要用串口和智能硬件开发板通信,假如模块也使用此串口的话,就会出现一个问题,当模块插在板子上时,就无法下载程序。然后咱就使用软串口SoftSerial与模块通信,由于扩展板是采购的,相关硬件限制,只好把SoftSerial的两根线接到了按键上。按按键将会影响微信与智能硬件开发板板的通信 96 | 97 | 98 | 99 | 100 | ##开发者支持 101 | 官网:http://www.sensoro.com/zh/iot 102 | 103 | 中国,北京(总部) 104 | 邮箱:beijing@sensoro.com 105 | 地址:北京市朝阳区望京SOHO T1号楼 B座 2807 106 | 107 | 开发者 QQ 群 :361891407 108 | 400电话 :400 - 686 - 3180 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /wechat/lib/DHT11.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/wechat/lib/DHT11.zip -------------------------------------------------------------------------------- /wechat/lib/DHT11/DHT11.cpp: -------------------------------------------------------------------------------- 1 | #include "DHT11.h" 2 | #include "Arduino.h" 3 | 4 | DHT11::DHT11(int pin){ 5 | _pin = pin; 6 | } 7 | 8 | /**@brief: Read the temperature and the humidity data 9 | * 10 | * @retval DHTLIB_OK DHT11 read success 11 | * @retval DHTLIB_ERROR_CHECKSUM DHT11 result check error 12 | * @retval DHTLIB_ERROR_TIMEOUT DHT11 read time out 13 | */ 14 | int DHT11::read(void) 15 | { 16 | // BUFFER TO RECEIVE 17 | uint8_t bits[5]; 18 | uint8_t cnt = 7; 19 | uint8_t idx = 0; 20 | 21 | // EMPTY BUFFER 22 | for (int i=0; i< 5; i++) bits[i] = 0; 23 | 24 | // REQUEST SAMPLE 25 | pinMode(_pin, OUTPUT); 26 | digitalWrite(_pin, LOW); 27 | delay(18); 28 | digitalWrite(_pin, HIGH); 29 | delayMicroseconds(40); 30 | pinMode(_pin, INPUT); 31 | 32 | // ACKNOWLEDGE or TIMEOUT 33 | unsigned int loopCnt = 10000; 34 | while(digitalRead(_pin) == LOW) 35 | if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT; 36 | 37 | loopCnt = 10000; 38 | while(digitalRead(_pin) == HIGH) 39 | if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT; 40 | 41 | // READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT 42 | for (int i=0; i<40; i++) 43 | { 44 | loopCnt = 10000; 45 | while(digitalRead(_pin) == LOW) 46 | if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT; 47 | 48 | unsigned long t = micros(); 49 | 50 | loopCnt = 10000; 51 | while(digitalRead(_pin) == HIGH) 52 | if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT; 53 | 54 | if ((micros() - t) > 40) bits[idx] |= (1 << cnt); 55 | if (cnt == 0) // next byte? 56 | { 57 | cnt = 7; // restart at MSB 58 | idx++; // next byte! 59 | } 60 | else cnt--; 61 | } 62 | 63 | // WRITE TO RIGHT VARS 64 | // as bits[1] and bits[3] are allways zero they are omitted in formulas. 65 | humidity = bits[0]; 66 | temperature = bits[2]; 67 | 68 | uint8_t sum = bits[0] + bits[2]; 69 | 70 | if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM; 71 | return DHTLIB_OK; 72 | } 73 | -------------------------------------------------------------------------------- /wechat/lib/DHT11/DHT11.h: -------------------------------------------------------------------------------- 1 | #ifndef DHT11_H 2 | #define DHT11_H 3 | 4 | #define DHTLIB_OK 0 5 | #define DHTLIB_ERROR_CHECKSUM -1 6 | #define DHTLIB_ERROR_TIMEOUT -2 7 | 8 | class DHT11 9 | { 10 | private: 11 | int _pin; 12 | public: 13 | DHT11(int pin); 14 | int read(void); 15 | 16 | int humidity; 17 | int temperature; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /wechat/lib/DHT11/examples/DHT11/DHT11.ino: -------------------------------------------------------------------------------- 1 | #include "DHT11.h" 2 | 3 | #define DHT11_PIN 3 4 | 5 | DHT11 dht11(DHT11_PIN); 6 | void setup() 7 | { 8 | Serial.begin(9600); 9 | Serial.println("DHT11 TEST PROGRAM "); 10 | } 11 | 12 | void loop() 13 | { 14 | Serial.println("\n"); 15 | 16 | int chk = dht11.read(); 17 | 18 | Serial.print("Read sensor: "); 19 | switch (chk) 20 | { 21 | case DHTLIB_OK: 22 | Serial.println("OK"); 23 | break; 24 | case DHTLIB_ERROR_CHECKSUM: 25 | Serial.println("Checksum error"); 26 | break; 27 | case DHTLIB_ERROR_TIMEOUT: 28 | Serial.println("Time out error"); 29 | break; 30 | default: 31 | Serial.println("Unknown error"); 32 | break; 33 | } 34 | 35 | Serial.print("Humidity (%): "); 36 | Serial.println((float)dht11.humidity, 2); 37 | 38 | Serial.print("Temperature (oC): "); 39 | Serial.println((float)dht11.temperature, 2); 40 | 41 | Serial.print("Temperature (oF): "); 42 | Serial.println(Fahrenheit(dht11.temperature), 2); 43 | 44 | Serial.print("Temperature (K): "); 45 | Serial.println(Kelvin(dht11.temperature), 2); 46 | 47 | Serial.print("Dew Point (oC): "); 48 | Serial.println(dewPoint(dht11.temperature, dht11.humidity)); 49 | 50 | Serial.print("Dew PointFast (oC): "); 51 | Serial.println(dewPointFast(dht11.temperature, dht11.humidity)); 52 | 53 | delay(2000); 54 | } 55 | 56 | double Fahrenheit(double celsius) 57 | { 58 | return 1.8 * celsius + 32; 59 | } //摄氏温度度转化为华氏温度 60 | 61 | double Kelvin(double celsius) 62 | { 63 | return celsius + 273.15; 64 | } //摄氏温度转化为开氏温度 65 | 66 | // 露点(点在此温度时,空气饱和并产生露珠) 67 | // 参考: http://wahiduddin.net/calc/density_algorithms.htm 68 | double dewPoint(double celsius, double humidity) 69 | { 70 | double A0= 373.15/(273.15 + celsius); 71 | double SUM = -7.90298 * (A0-1); 72 | SUM += 5.02808 * log10(A0); 73 | SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ; 74 | SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ; 75 | SUM += log10(1013.246); 76 | double VP = pow(10, SUM-3) * humidity; 77 | double T = log(VP/0.61078); // temp var 78 | return (241.88 * T) / (17.558-T); 79 | } 80 | 81 | // 快速计算露点,速度是5倍dewPoint() 82 | // 参考: http://en.wikipedia.org/wiki/Dew_point 83 | double dewPointFast(double celsius, double humidity) 84 | { 85 | double a = 17.271; 86 | double b = 237.7; 87 | double temp = (a * celsius) / (b + celsius) + log(humidity/100); 88 | double Td = (b * temp) / (a - temp); 89 | return Td; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /wechat/lib/Moto.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/wechat/lib/Moto.zip -------------------------------------------------------------------------------- /wechat/lib/Moto/Moto.cpp: -------------------------------------------------------------------------------- 1 | #include "Moto.h" 2 | #include "Arduino.h" 3 | 4 | Moto::Moto(int anodePin,int cathodePin){ 5 | _anodePin = anodePin; 6 | _cathodePin = cathodePin; 7 | } 8 | void Moto::begin(void){ 9 | pinMode(_anodePin,OUTPUT); 10 | pinMode(_cathodePin,OUTPUT); 11 | _state = STOP; 12 | } 13 | void Moto::rotate(int power){ 14 | if(_state!=ROTATE) 15 | { 16 | _state = ROTATE; 17 | _power = power; 18 | digitalWrite(_cathodePin,LOW); 19 | analogWrite(_anodePin,power); 20 | } 21 | } 22 | void Moto::reversal(void){ 23 | if(_state != REVERSAL) 24 | { 25 | _state = REVERSAL; 26 | digitalWrite(_cathodePin,HIGH); 27 | digitalWrite(_anodePin,LOW); 28 | } 29 | } 30 | void Moto::stop(void){ 31 | if(_state != STOP) 32 | { 33 | _state = STOP; 34 | digitalWrite(_anodePin,LOW); 35 | digitalWrite(_cathodePin,LOW); 36 | } 37 | } 38 | void Moto::speedup(void){ 39 | if(_state ==ROTATE) 40 | { 41 | _power +=SPEEPUP_STEP; 42 | if(_power >=255) 43 | _power =255; 44 | analogWrite(_anodePin,_power); 45 | } 46 | } 47 | 48 | void Moto::speedown(void){ 49 | if(_state ==ROTATE) 50 | { 51 | _power -= SPEEPUP_STEP; 52 | if(_power<=10) 53 | _power = 10; 54 | analogWrite(_anodePin,_power); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /wechat/lib/Moto/Moto.h: -------------------------------------------------------------------------------- 1 | #ifndef MOTO_H 2 | #define MOTO_H 3 | 4 | #define SPEEPUP_STEP 20 5 | 6 | typedef enum{ 7 | ROTATE, 8 | REVERSAL, 9 | STOP 10 | }moto_state_t; 11 | /* 12 | * The _anodePin must has the PWM function 13 | */ 14 | class Moto{ 15 | private: 16 | int _anodePin; 17 | int _cathodePin; 18 | int _power; 19 | moto_state_t _state; 20 | public: 21 | Moto(int _anodePin,int _cathodePin); 22 | void begin(void); 23 | void rotate(int power); 24 | void reversal(void); 25 | void speedup(void); 26 | void speedown(void); 27 | void stop(void); 28 | }; 29 | #endif 30 | -------------------------------------------------------------------------------- /wechat/lib/Moto/example/MotoTest/MotoTest.ino: -------------------------------------------------------------------------------- 1 | 2 | #include "Moto.h" 3 | 4 | #define MOTO_CATHODE 4 5 | #define MOTO_ANODE 5 6 | 7 | Moto moto(MOTO_ANODE,MOTO_CATHODE); 8 | 9 | void setup() { 10 | // put your setup code here, to run once: 11 | moto.begin(); 12 | 13 | } 14 | void loop() { 15 | // put your main code here, to run repeatedly: 16 | moto.rotate(10); 17 | delay(500); 18 | moto.stop(); 19 | delay(500); 20 | moto.reversal(); 21 | delay(500); 22 | moto.stop(); 23 | delay(500); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /wechat/lib/RGBLED.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/wechat/lib/RGBLED.zip -------------------------------------------------------------------------------- /wechat/lib/RGBLED/RGBLED.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Paulo Marques (pjp.marques@gmail.com) 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | * this software and associated documentation files (the "Software"), to deal in 6 | * the Software without restriction, including without limitation the rights to 7 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | * the Software, and to permit persons to whom the Software is furnished to do so, 9 | * subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in all 12 | * copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | /* Information about the P9813 protocol obtained from: 23 | * http://www.seeedstudio.com/wiki/index.php?title=Twig_-_Chainable_RGB_LED 24 | * 25 | * HSB to RGB routine adapted from: 26 | * http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript 27 | */ 28 | 29 | 30 | // -------------------------------------------------------------------------------------- 31 | 32 | #include "RGBLED.h" 33 | 34 | // Forward declaration 35 | float hue2rgb(float p, float q, float t); 36 | 37 | // -------------------------------------------------------------------------------------- 38 | 39 | RGBLED::RGBLED(byte clk_pin, byte data_pin) : 40 | _clk_pin(clk_pin), _data_pin(data_pin) 41 | { 42 | } 43 | 44 | // -------------------------------------------------------------------------------------- 45 | 46 | void RGBLED::begin(void) 47 | { 48 | pinMode(_clk_pin, OUTPUT); 49 | pinMode(_data_pin, OUTPUT); 50 | 51 | setColorRGB(0, 0, 0); 52 | } 53 | 54 | void RGBLED::clk(void) 55 | { 56 | digitalWrite(_clk_pin, LOW); 57 | delayMicroseconds(_CLK_PULSE_DELAY); 58 | digitalWrite(_clk_pin, HIGH); 59 | delayMicroseconds(_CLK_PULSE_DELAY); 60 | } 61 | 62 | void RGBLED::sendByte(byte b) 63 | { 64 | // Send one bit at a time, starting with the MSB 65 | for (byte i=0; i<8; i++) 66 | { 67 | // If MSB is 1, write one and clock it, else write 0 and clock 68 | if ((b & 0x80) != 0) 69 | digitalWrite(_data_pin, HIGH); 70 | else 71 | digitalWrite(_data_pin, LOW); 72 | clk(); 73 | 74 | // Advance to the next bit to send 75 | b <<= 1; 76 | } 77 | } 78 | 79 | void RGBLED::sendColor(byte red, byte green, byte blue) 80 | { 81 | // Start by sending a byte with the format "1 1 /B7 /B6 /G7 /G6 /R7 /R6" 82 | byte prefix = B11000000; 83 | if ((blue & 0x80) == 0) prefix|= B00100000; 84 | if ((blue & 0x40) == 0) prefix|= B00010000; 85 | if ((green & 0x80) == 0) prefix|= B00001000; 86 | if ((green & 0x40) == 0) prefix|= B00000100; 87 | if ((red & 0x80) == 0) prefix|= B00000010; 88 | if ((red & 0x40) == 0) prefix|= B00000001; 89 | sendByte(prefix); 90 | 91 | // Now must send the 3 colors 92 | sendByte(blue); 93 | sendByte(green); 94 | sendByte(red); 95 | } 96 | 97 | void RGBLED::setColorRGB(byte red, byte green, byte blue) 98 | { 99 | // Send data frame prefix (32x "0") 100 | sendByte(0x00); 101 | sendByte(0x00); 102 | sendByte(0x00); 103 | sendByte(0x00); 104 | 105 | sendColor(red,green,blue); 106 | 107 | // Terminate data frame (32x "0") 108 | sendByte(0x00); 109 | sendByte(0x00); 110 | sendByte(0x00); 111 | sendByte(0x00); 112 | } 113 | 114 | void RGBLED::setColorHSB(float hue, float saturation, float brightness) 115 | { 116 | float r, g, b; 117 | 118 | constrain(hue, 0.0, 1.0); 119 | constrain(saturation, 0.0, 1.0); 120 | constrain(brightness, 0.0, 1.0); 121 | 122 | if(saturation == 0.0) 123 | { 124 | r = g = b = brightness; 125 | } 126 | else 127 | { 128 | float q = brightness < 0.5 ? 129 | brightness * (1.0 + saturation) : brightness + saturation - brightness * saturation; 130 | float p = 2.0 * brightness - q; 131 | r = hue2rgb(p, q, hue + 1.0/3.0); 132 | g = hue2rgb(p, q, hue); 133 | b = hue2rgb(p, q, hue - 1.0/3.0); 134 | } 135 | 136 | setColorRGB((byte)(255.0*r), (byte)(255.0*g), (byte)(255.0*b)); 137 | } 138 | 139 | // -------------------------------------------------------------------------------------- 140 | 141 | float hue2rgb(float p, float q, float t) 142 | { 143 | if (t < 0.0) 144 | t += 1.0; 145 | if(t > 1.0) 146 | t -= 1.0; 147 | if(t < 1.0/6.0) 148 | return p + (q - p) * 6.0 * t; 149 | if(t < 1.0/2.0) 150 | return q; 151 | if(t < 2.0/3.0) 152 | return p + (q - p) * (2.0/3.0 - t) * 6.0; 153 | 154 | return p; 155 | } 156 | -------------------------------------------------------------------------------- /wechat/lib/RGBLED/RGBLED.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2012 Paulo Marques (pjp.marques@gmail.com) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | /* 23 | * Library for controlling a chain of RGB LEDs based on the P9813 protocol. 24 | * E.g., supports the Grove Chainable RGB LED product. 25 | * 26 | * Information about the P9813 protocol obtained from: 27 | * http://www.seeedstudio.com/wiki/index.php?title=Twig_-_Chainable_RGB_LED 28 | */ 29 | 30 | 31 | 32 | #ifndef RGBLED_H 33 | #define RGBLED_H 34 | 35 | #include "Arduino.h" 36 | 37 | #define _CLK_PULSE_DELAY 20 38 | 39 | class RGBLED 40 | { 41 | public: 42 | RGBLED(byte clk_pin, byte data_pin); 43 | 44 | void begin(void); 45 | void setColorRGB(byte red, byte green, byte blue); 46 | void setColorHSB(float hue, float saturation, float brightness); 47 | 48 | private: 49 | byte _clk_pin; 50 | byte _data_pin; 51 | 52 | void clk(void); 53 | void sendByte(byte b); 54 | void sendColor(byte red, byte green, byte blue); 55 | }; 56 | 57 | #endif 58 | 59 | -------------------------------------------------------------------------------- /wechat/lib/RGBLED/example/RGBLED_Test/RGBLED_Test.ino: -------------------------------------------------------------------------------- 1 | #include "RGBLED.h" 2 | RGBLED rgbled(A5,A4); 3 | void setup() { 4 | // put your setup code here, to run once: 5 | rgbled.begin(); 6 | } 7 | 8 | void loop() { 9 | // put your main code here, to run repeatedly: 10 | rgbled.setColorRGB(255,0,0); 11 | delay(200); 12 | rgbled.setColorRGB(0,255,0); 13 | delay(200); 14 | rgbled.setColorRGB(0,0,255); 15 | delay(200); 16 | } 17 | -------------------------------------------------------------------------------- /wechat/wechat_hardware/wechat_hardware.ino: -------------------------------------------------------------------------------- 1 | /* Because the UNO has only one Serail, and the wechat module will use a Serial. 2 | * If using the hardware serial, these is a upload problem when wechat module is on the board. 3 | * So in this demo,we select SoftwareSerial communicate with module. 4 | */ 5 | 6 | #include 7 | #include "Moto.h" 8 | #include "RGBLED.h" 9 | #include "DHT11.h" 10 | 11 | #define CMD_GB2312_CODE_MAX_LEN 32 12 | #define CMD_REC_TIME_OUT 2000 13 | //Cmd, which is the GB2312 codes of the Chinese character 14 | #define GB_LANSE "C0B6C9AB" 15 | #define GB_HONGSE "BAECC9AB" 16 | #define GB_LVSE "C2CCC9AB" 17 | #define GB_SHAN "C9C1" 18 | #define GB_BIAN "B1E4" 19 | #define GB_CAIHONG "B2CABAE7" 20 | #define GB_XIMIE "CFA8C3F0" 21 | #define GB_ZHUAN "D7AA" 22 | #define GB_TING "CDA3" 23 | #define GB_JIASU "BCD3CBD9" 24 | #define GB_JIANSU "BCF5CBD9" 25 | #define GB_WENDU "CEC2B6C8" 26 | #define GB_SHIDU "CAAAB6C8" 27 | /* 28 | Add your own cmd gb2312 code here 29 | */ 30 | 31 | // Definition of pins 32 | #define RGB_SCL A5 33 | #define RGB_SDA A4 34 | #define MOTO_ANODE 5 35 | #define MOTO_CATHODE 4 36 | #define DHT_PIN 3 37 | #define SOFTSERIAL_RX 6 38 | #define SOFTSERIAL_TX 7 39 | 40 | //New a RGB led 41 | RGBLED rgbLed(RGB_SCL,RGB_SDA); 42 | //New a moto 43 | Moto moto(MOTO_ANODE,MOTO_CATHODE); 44 | //New a DHT11 45 | DHT11 dht11(DHT_PIN); 46 | //New a SoftwareSerial 47 | SoftwareSerial mySerial(SOFTSERIAL_RX, SOFTSERIAL_TX); // RX, TX 48 | 49 | bool flag_rgb_blink=false; 50 | bool flag_rgb_rainbow=false; 51 | unsigned long previousMillis = 0; 52 | 53 | void setup() { 54 | //Hardware Serial 55 | Serial.begin(38400); 56 | while(!Serial); 57 | //SoftwareSerial 58 | mySerial.begin(38400); 59 | Serial.println("start"); 60 | rgbLed.begin(); 61 | moto.begin(); 62 | } 63 | void loop() { 64 | 65 | //SoftwareSerial receive the cmd 66 | if (mySerial.available()) 67 | { 68 | int len=0; 69 | // The buffer size is now 32. So the max length of Cmd is 8 Chinese characters. 70 | char buffer[CMD_GB2312_CODE_MAX_LEN]; 71 | unsigned long beforRecTime =millis(); 72 | unsigned long recTime = beforRecTime; 73 | 74 | Serial.print("all character:"); 75 | while(recTime - beforRecTime < CMD_REC_TIME_OUT){ 76 | buffer[len]=mySerial.read(); 77 | Serial.print(" "); 78 | Serial.print(buffer[len]); 79 | //if encounter '\n' or len large than max len ,break 80 | if(buffer[len]=='\n' || len>CMD_GB2312_CODE_MAX_LEN-1){ 81 | break; 82 | } 83 | len++; 84 | recTime= millis(); 85 | } 86 | Serial.print("rec cmd: "); 87 | Serial.write(buffer,len); 88 | Serial.println(""); 89 | if(!memcmp(buffer,GB_XIMIE,len)&&len==strlen(GB_XIMIE)){ 90 | flag_rgb_blink=false; 91 | flag_rgb_rainbow=false; 92 | rgbLed.setColorRGB(0,0,0); 93 | } 94 | else if(!memcmp(buffer,GB_LANSE,len)&&len==strlen(GB_LANSE)){ 95 | flag_rgb_blink=false; 96 | flag_rgb_rainbow=false; 97 | rgbLed.setColorRGB(0,0,255); 98 | } 99 | else if(!memcmp(buffer,GB_HONGSE,len)&&len==strlen(GB_HONGSE)){ 100 | flag_rgb_blink=false; 101 | flag_rgb_rainbow=false; 102 | rgbLed.setColorRGB(255,0,0); 103 | } 104 | else if(!memcmp(buffer,GB_LVSE,len)&&len==strlen(GB_LVSE)){ 105 | flag_rgb_blink=false; 106 | flag_rgb_rainbow=false; 107 | rgbLed.setColorRGB(0,255,0); 108 | } 109 | else if(!memcmp(buffer,GB_SHAN,len)&&len==strlen(GB_SHAN)){ 110 | flag_rgb_blink=true; 111 | flag_rgb_rainbow=false; 112 | } 113 | else if(!memcmp(buffer,GB_BIAN,len)&&len==strlen(GB_BIAN)){ 114 | flag_rgb_blink=false; 115 | flag_rgb_rainbow=true; 116 | } 117 | else if(!memcmp(buffer,GB_ZHUAN,len)&&len==strlen(GB_ZHUAN)){ 118 | moto.rotate(50); 119 | } 120 | else if(!memcmp(buffer,GB_JIASU,len)&&len==strlen(GB_JIASU)){ 121 | moto.speedup(); 122 | } 123 | else if(!memcmp(buffer,GB_JIANSU,len)&&len==strlen(GB_JIANSU)){ 124 | moto.speedown(); 125 | } 126 | else if(!memcmp(buffer,GB_TING,len)&&len==strlen(GB_TING)){ 127 | moto.stop(); 128 | } 129 | else if(!memcmp(buffer,GB_WENDU,len)&&len==strlen(GB_WENDU)){ 130 | dht11.read(); 131 | mySerial.print("Temperature (oC): "); 132 | mySerial.print((float)dht11.temperature, 2); 133 | mySerial.print("\n"); 134 | } 135 | else if(!memcmp(buffer,GB_SHIDU,len)&&len==strlen(GB_SHIDU)){ 136 | dht11.read(); 137 | mySerial.print("Humidity (%): "); 138 | mySerial.print((float)dht11.humidity, 2); 139 | mySerial.print("\n"); 140 | } 141 | /* 142 | Add your own code of cmd decoding here 143 | */ 144 | } 145 | if(flag_rgb_blink) 146 | { 147 | unsigned long currentMillis = millis(); 148 | static unsigned long rgb= 0x000000ff; 149 | if(currentMillis - previousMillis >= 200) { 150 | previousMillis = currentMillis; 151 | rgbLed.setColorRGB(rgb&0xff,(rgb&0x0000ff00)>>8,(rgb&0x00ff0000)>>16); 152 | rgb = rgb<<8; 153 | if(rgb==0xff000000) 154 | rgb=0x000000ff; 155 | } 156 | } 157 | else if(flag_rgb_rainbow) 158 | { 159 | static float hue = 0.0; 160 | static bool up = true; 161 | unsigned long currentMillis = millis(); 162 | if(currentMillis - previousMillis >= 200) { 163 | previousMillis = currentMillis; 164 | rgbLed.setColorHSB(hue,1.0,0.5); 165 | if (up) 166 | hue+= 0.025; 167 | else 168 | hue-= 0.025; 169 | if (hue>=1.0 && up) 170 | up = false; 171 | else if (hue<=0.0 && !up) 172 | up = true; 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /wechat_v2/doc/arduino_extend.PDF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/wechat_v2/doc/arduino_extend.PDF -------------------------------------------------------------------------------- /wechat_v2/lib/DHT11.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/wechat_v2/lib/DHT11.zip -------------------------------------------------------------------------------- /wechat_v2/lib/DHT11/DHT11.cpp: -------------------------------------------------------------------------------- 1 | #include "DHT11.h" 2 | #include "Arduino.h" 3 | 4 | DHT11::DHT11(int pin){ 5 | _pin = pin; 6 | } 7 | 8 | /**@brief: Read the temperature and the humidity data 9 | * 10 | * @retval DHTLIB_OK DHT11 read success 11 | * @retval DHTLIB_ERROR_CHECKSUM DHT11 result check error 12 | * @retval DHTLIB_ERROR_TIMEOUT DHT11 read time out 13 | */ 14 | int DHT11::read(void) 15 | { 16 | // BUFFER TO RECEIVE 17 | uint8_t bits[5]; 18 | uint8_t cnt = 7; 19 | uint8_t idx = 0; 20 | 21 | // EMPTY BUFFER 22 | for (int i=0; i< 5; i++) bits[i] = 0; 23 | 24 | // REQUEST SAMPLE 25 | pinMode(_pin, OUTPUT); 26 | digitalWrite(_pin, LOW); 27 | delay(18); 28 | digitalWrite(_pin, HIGH); 29 | delayMicroseconds(40); 30 | pinMode(_pin, INPUT); 31 | 32 | // ACKNOWLEDGE or TIMEOUT 33 | unsigned int loopCnt = 10000; 34 | while(digitalRead(_pin) == LOW) 35 | if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT; 36 | 37 | loopCnt = 10000; 38 | while(digitalRead(_pin) == HIGH) 39 | if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT; 40 | 41 | // READ OUTPUT - 40 BITS => 5 BYTES or TIMEOUT 42 | for (int i=0; i<40; i++) 43 | { 44 | loopCnt = 10000; 45 | while(digitalRead(_pin) == LOW) 46 | if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT; 47 | 48 | unsigned long t = micros(); 49 | 50 | loopCnt = 10000; 51 | while(digitalRead(_pin) == HIGH) 52 | if (loopCnt-- == 0) return DHTLIB_ERROR_TIMEOUT; 53 | 54 | if ((micros() - t) > 40) bits[idx] |= (1 << cnt); 55 | if (cnt == 0) // next byte? 56 | { 57 | cnt = 7; // restart at MSB 58 | idx++; // next byte! 59 | } 60 | else cnt--; 61 | } 62 | 63 | // WRITE TO RIGHT VARS 64 | // as bits[1] and bits[3] are allways zero they are omitted in formulas. 65 | humidity = bits[0]; 66 | temperature = bits[2]; 67 | 68 | uint8_t sum = bits[0] + bits[2]; 69 | 70 | if (bits[4] != sum) return DHTLIB_ERROR_CHECKSUM; 71 | return DHTLIB_OK; 72 | } 73 | -------------------------------------------------------------------------------- /wechat_v2/lib/DHT11/DHT11.h: -------------------------------------------------------------------------------- 1 | #ifndef DHT11_H 2 | #define DHT11_H 3 | 4 | #define DHTLIB_OK 0 5 | #define DHTLIB_ERROR_CHECKSUM -1 6 | #define DHTLIB_ERROR_TIMEOUT -2 7 | 8 | class DHT11 9 | { 10 | private: 11 | int _pin; 12 | public: 13 | DHT11(int pin); 14 | int read(void); 15 | 16 | int humidity; 17 | int temperature; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /wechat_v2/lib/DHT11/examples/DHT11/DHT11.ino: -------------------------------------------------------------------------------- 1 | #include "DHT11.h" 2 | 3 | #define DHT11_PIN 3 4 | 5 | DHT11 dht11(DHT11_PIN); 6 | void setup() 7 | { 8 | Serial.begin(9600); 9 | Serial.println("DHT11 TEST PROGRAM "); 10 | } 11 | 12 | void loop() 13 | { 14 | Serial.println("\n"); 15 | 16 | int chk = dht11.read(); 17 | 18 | Serial.print("Read sensor: "); 19 | switch (chk) 20 | { 21 | case DHTLIB_OK: 22 | Serial.println("OK"); 23 | break; 24 | case DHTLIB_ERROR_CHECKSUM: 25 | Serial.println("Checksum error"); 26 | break; 27 | case DHTLIB_ERROR_TIMEOUT: 28 | Serial.println("Time out error"); 29 | break; 30 | default: 31 | Serial.println("Unknown error"); 32 | break; 33 | } 34 | 35 | Serial.print("Humidity (%): "); 36 | Serial.println((float)dht11.humidity, 2); 37 | 38 | Serial.print("Temperature (oC): "); 39 | Serial.println((float)dht11.temperature, 2); 40 | 41 | Serial.print("Temperature (oF): "); 42 | Serial.println(Fahrenheit(dht11.temperature), 2); 43 | 44 | Serial.print("Temperature (K): "); 45 | Serial.println(Kelvin(dht11.temperature), 2); 46 | 47 | Serial.print("Dew Point (oC): "); 48 | Serial.println(dewPoint(dht11.temperature, dht11.humidity)); 49 | 50 | Serial.print("Dew PointFast (oC): "); 51 | Serial.println(dewPointFast(dht11.temperature, dht11.humidity)); 52 | 53 | delay(2000); 54 | } 55 | 56 | double Fahrenheit(double celsius) 57 | { 58 | return 1.8 * celsius + 32; 59 | } //摄氏温度度转化为华氏温度 60 | 61 | double Kelvin(double celsius) 62 | { 63 | return celsius + 273.15; 64 | } //摄氏温度转化为开氏温度 65 | 66 | // 露点(点在此温度时,空气饱和并产生露珠) 67 | // 参考: http://wahiduddin.net/calc/density_algorithms.htm 68 | double dewPoint(double celsius, double humidity) 69 | { 70 | double A0= 373.15/(273.15 + celsius); 71 | double SUM = -7.90298 * (A0-1); 72 | SUM += 5.02808 * log10(A0); 73 | SUM += -1.3816e-7 * (pow(10, (11.344*(1-1/A0)))-1) ; 74 | SUM += 8.1328e-3 * (pow(10,(-3.49149*(A0-1)))-1) ; 75 | SUM += log10(1013.246); 76 | double VP = pow(10, SUM-3) * humidity; 77 | double T = log(VP/0.61078); // temp var 78 | return (241.88 * T) / (17.558-T); 79 | } 80 | 81 | // 快速计算露点,速度是5倍dewPoint() 82 | // 参考: http://en.wikipedia.org/wiki/Dew_point 83 | double dewPointFast(double celsius, double humidity) 84 | { 85 | double a = 17.271; 86 | double b = 237.7; 87 | double temp = (a * celsius) / (b + celsius) + log(humidity/100); 88 | double Td = (b * temp) / (a - temp); 89 | return Td; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /wechat_v2/lib/Moto.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/wechat_v2/lib/Moto.zip -------------------------------------------------------------------------------- /wechat_v2/lib/Moto/Moto.cpp: -------------------------------------------------------------------------------- 1 | #include "Moto.h" 2 | #include "Arduino.h" 3 | 4 | Moto::Moto(int anodePin,int cathodePin){ 5 | _anodePin = anodePin; 6 | _cathodePin = cathodePin; 7 | } 8 | void Moto::begin(void){ 9 | pinMode(_anodePin,OUTPUT); 10 | pinMode(_cathodePin,OUTPUT); 11 | _state = STOP; 12 | } 13 | void Moto::rotate(int power){ 14 | if(_state!=ROTATE) 15 | { 16 | _state = ROTATE; 17 | _power = power; 18 | digitalWrite(_cathodePin,LOW); 19 | analogWrite(_anodePin,power); 20 | } 21 | } 22 | void Moto::reversal(void){ 23 | if(_state != REVERSAL) 24 | { 25 | _state = REVERSAL; 26 | digitalWrite(_cathodePin,HIGH); 27 | digitalWrite(_anodePin,LOW); 28 | } 29 | } 30 | void Moto::stop(void){ 31 | if(_state != STOP) 32 | { 33 | _state = STOP; 34 | digitalWrite(_anodePin,LOW); 35 | digitalWrite(_cathodePin,LOW); 36 | } 37 | } 38 | void Moto::speedup(void){ 39 | if(_state ==ROTATE) 40 | { 41 | _power +=SPEEPUP_STEP; 42 | if(_power >=255) 43 | _power =255; 44 | analogWrite(_anodePin,_power); 45 | } 46 | } 47 | 48 | void Moto::speedown(void){ 49 | if(_state ==ROTATE) 50 | { 51 | _power -= SPEEPUP_STEP; 52 | if(_power<=10) 53 | _power = 10; 54 | analogWrite(_anodePin,_power); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /wechat_v2/lib/Moto/Moto.h: -------------------------------------------------------------------------------- 1 | #ifndef MOTO_H 2 | #define MOTO_H 3 | 4 | #define SPEEPUP_STEP 20 5 | 6 | typedef enum{ 7 | ROTATE, 8 | REVERSAL, 9 | STOP 10 | }moto_state_t; 11 | /* 12 | * The _anodePin must has the PWM function 13 | */ 14 | class Moto{ 15 | private: 16 | int _anodePin; 17 | int _cathodePin; 18 | int _power; 19 | moto_state_t _state; 20 | public: 21 | Moto(int _anodePin,int _cathodePin); 22 | void begin(void); 23 | void rotate(int power); 24 | void reversal(void); 25 | void speedup(void); 26 | void speedown(void); 27 | void stop(void); 28 | }; 29 | #endif 30 | -------------------------------------------------------------------------------- /wechat_v2/lib/Moto/example/MotoTest/MotoTest.ino: -------------------------------------------------------------------------------- 1 | 2 | #include "Moto.h" 3 | 4 | #define MOTO_CATHODE 4 5 | #define MOTO_ANODE 5 6 | 7 | Moto moto(MOTO_ANODE,MOTO_CATHODE); 8 | 9 | void setup() { 10 | // put your setup code here, to run once: 11 | moto.begin(); 12 | 13 | } 14 | void loop() { 15 | // put your main code here, to run repeatedly: 16 | moto.rotate(10); 17 | delay(500); 18 | moto.stop(); 19 | delay(500); 20 | moto.reversal(); 21 | delay(500); 22 | moto.stop(); 23 | delay(500); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /wechat_v2/lib/MsTimer2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/wechat_v2/lib/MsTimer2.zip -------------------------------------------------------------------------------- /wechat_v2/lib/MsTimer2/MsTimer2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | MsTimer2.h - Using timer2 with 1ms resolution 3 | Javier Valencia 4 | 5 | https://github.com/PaulStoffregen/MsTimer2 6 | 7 | History: 8 | 6/Jun/14 - V0.7 added support for Teensy 3.0 & 3.1 9 | 29/Dec/11 - V0.6 added support for ATmega32u4, AT90USB646, AT90USB1286 (paul@pjrc.com) 10 | some improvements added by Bill Perry 11 | note: uses timer4 on Atmega32u4 12 | 29/May/09 - V0.5 added support for Atmega1280 (thanks to Manuel Negri) 13 | 19/Mar/09 - V0.4 added support for ATmega328P (thanks to Jerome Despatis) 14 | 11/Jun/08 - V0.3 15 | changes to allow working with different CPU frequencies 16 | added support for ATMega128 (using timer2) 17 | compatible with ATMega48/88/168/8 18 | 10/May/08 - V0.2 added some security tests and volatile keywords 19 | 9/May/08 - V0.1 released working on ATMEGA168 only 20 | 21 | 22 | This library is free software; you can redistribute it and/or 23 | modify it under the terms of the GNU Lesser General Public 24 | License as published by the Free Software Foundation; either 25 | version 2.1 of the License, or (at your option) any later version. 26 | 27 | This library is distributed in the hope that it will be useful, 28 | but WITHOUT ANY WARRANTY; without even the implied warranty of 29 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 30 | Lesser General Public License for more details. 31 | 32 | You should have received a copy of the GNU Lesser General Public 33 | License along with this library; if not, write to the Free Software 34 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 35 | */ 36 | 37 | #include 38 | 39 | unsigned long MsTimer2::msecs; 40 | void (*MsTimer2::func)(); 41 | volatile unsigned long MsTimer2::count; 42 | volatile char MsTimer2::overflowing; 43 | volatile unsigned int MsTimer2::tcnt2; 44 | #if defined(__arm__) && defined(TEENSYDUINO) 45 | static IntervalTimer itimer; 46 | #endif 47 | 48 | void MsTimer2::set(unsigned long ms, void (*f)()) { 49 | float prescaler = 0.0; 50 | 51 | if (ms == 0) 52 | msecs = 1; 53 | else 54 | msecs = ms; 55 | 56 | func = f; 57 | 58 | #if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 59 | TIMSK2 &= ~(1<= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64 66 | TCCR2B |= (1< 16Mhz, prescaler set to 128 74 | TCCR2B |= ((1<= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64 85 | TCCR2 |= (1< 16Mhz, prescaler set to 128 93 | TCCR2 |= ((1<= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64 103 | TCCR2 |= ((1< 16Mhz, prescaler set to 256 111 | TCCR2 |= (1<= 16000000L) { 122 | TCCR4B = (1<= 8000000L) { 125 | TCCR4B = (1<= 4000000L) { 128 | TCCR4B = (1<= 2000000L) { 131 | TCCR4B = (1<= 1000000L) { 134 | TCCR4B = (1<= 500000L) { 137 | TCCR4B = (1<= msecs && !overflowing) { 194 | overflowing = 1; 195 | count = count - msecs; // subtract ms to catch missed overflows 196 | // set to 0 if you don't want this. 197 | (*func)(); 198 | overflowing = 0; 199 | } 200 | } 201 | 202 | #if defined (__AVR__) 203 | #if defined (__AVR_ATmega32U4__) 204 | ISR(TIMER4_OVF_vect) { 205 | #else 206 | ISR(TIMER2_OVF_vect) { 207 | #endif 208 | #if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) 209 | TCNT2 = MsTimer2::tcnt2; 210 | #elif defined (__AVR_ATmega128__) 211 | TCNT2 = MsTimer2::tcnt2; 212 | #elif defined (__AVR_ATmega8__) 213 | TCNT2 = MsTimer2::tcnt2; 214 | #elif defined (__AVR_ATmega32U4__) 215 | // not necessary on 32u4's high speed timer4 216 | #endif 217 | MsTimer2::_overflow(); 218 | } 219 | #endif // AVR 220 | 221 | -------------------------------------------------------------------------------- /wechat_v2/lib/MsTimer2/MsTimer2.h: -------------------------------------------------------------------------------- 1 | #ifndef MsTimer2_h 2 | #define MsTimer2_h 3 | 4 | #ifdef __AVR__ 5 | #include 6 | #elif defined(__arm__) && defined(TEENSYDUINO) 7 | #include 8 | #else 9 | #error MsTimer2 library only works on AVR architecture 10 | #endif 11 | 12 | namespace MsTimer2 { 13 | extern unsigned long msecs; 14 | extern void (*func)(); 15 | extern volatile unsigned long count; 16 | extern volatile char overflowing; 17 | extern volatile unsigned int tcnt2; 18 | 19 | void set(unsigned long ms, void (*f)()); 20 | void start(); 21 | void stop(); 22 | void _overflow(); 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /wechat_v2/lib/MsTimer2/README.md: -------------------------------------------------------------------------------- 1 | #MsTimer2 Library# 2 | 3 | Run a function every millisecond. 4 | 5 | http://www.pjrc.com/teensy/td_libs_MsTimer2.html 6 | 7 | Originally written by Javier Valencia 8 | -------------------------------------------------------------------------------- /wechat_v2/lib/MsTimer2/examples/FlashLed/FlashLed.pde: -------------------------------------------------------------------------------- 1 | /* 2 | MsTimer2 is a small and very easy to use library to interface Timer2 with 3 | humans. It's called MsTimer2 because it "hardcodes" a resolution of 1 4 | millisecond on timer2 5 | For Details see: http://www.arduino.cc/playground/Main/MsTimer2 6 | */ 7 | #include 8 | 9 | // Switch on LED on and off each half second 10 | 11 | #if ARDUINO >= 100 12 | const int led_pin = LED_BUILTIN; // 1.0 built in LED pin var 13 | #else 14 | const int led_pin = 13; // default to pin 13 15 | #endif 16 | 17 | 18 | void flash() 19 | { 20 | static boolean output = HIGH; 21 | 22 | digitalWrite(led_pin, output); 23 | output = !output; 24 | } 25 | 26 | void setup() 27 | { 28 | pinMode(led_pin, OUTPUT); 29 | 30 | MsTimer2::set(500, flash); // 500ms period 31 | MsTimer2::start(); 32 | } 33 | 34 | void loop() 35 | { 36 | } 37 | -------------------------------------------------------------------------------- /wechat_v2/lib/MsTimer2/keywords.txt: -------------------------------------------------------------------------------- 1 | MsTimer2 KEYWORD1 2 | set KEYWORD2 3 | start KEYWORD2 4 | stop KEYWORD2 5 | -------------------------------------------------------------------------------- /wechat_v2/lib/MsTimer2/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MsTimer2", 3 | "keywords": "timer, callback", 4 | "description": "MsTimer2 is a small and very easy to use library to interface Timer2 with humans. It's called MsTimer2 because it \"hardcodes\" a resolution of 1 millisecond on timer2.", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/PaulStoffregen/MsTimer2.git" 8 | }, 9 | "authors": [{ 10 | "name": "Javier Valencia", 11 | "email": "javiervalencia80@gmail.com", 12 | "url": "http://www.pjrc.com/teensy/td_libs_MsTimer2.html" 13 | }, { 14 | "name": "Paul Stoffregen", 15 | "url": "https://www.pjrc.com/about/", 16 | "maintainer": true 17 | }], 18 | "frameworks": [ 19 | "arduino" 20 | ], 21 | "platforms": [ 22 | "atmelavr", 23 | "teensy" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /wechat_v2/lib/MsTimer2/library.properties: -------------------------------------------------------------------------------- 1 | name=MsTimer2 2 | version=1.1 3 | author=Javier Valencia 4 | maintainer=Paul Stoffregen 5 | sentence=Run an interrupt function using Timer2 6 | paragraph= 7 | category=Timing 8 | url=http://playground.arduino.cc/Main/MsTimer2 9 | architectures=* 10 | 11 | -------------------------------------------------------------------------------- /wechat_v2/lib/RGB_Led_P9823.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/wechat_v2/lib/RGB_Led_P9823.zip -------------------------------------------------------------------------------- /wechat_v2/lib/RGB_Led_P9823/RGB_Led.cpp: -------------------------------------------------------------------------------- 1 | #include "RGB_Led.h" 2 | #include "p9823.h" 3 | 4 | float hue2rgb(float p, float q, float t); 5 | 6 | RGB_Led::RGB_Led(int data_pin) :_data_pin(data_pin) 7 | { 8 | } 9 | 10 | void RGB_Led::begin(void) 11 | { 12 | drv_data_pin_cfg(_data_pin); 13 | } 14 | 15 | void RGB_Led::setColorRGB(uint8_t red, uint8_t green, uint8_t blue) 16 | { 17 | 18 | drv_send_byte(red); 19 | drv_send_byte(green); 20 | drv_send_byte(blue); 21 | drv_reset(); 22 | } 23 | 24 | void RGB_Led::setColorHSB(float hue, float saturation, float brightness) 25 | { 26 | float r, g, b; 27 | 28 | constrain(hue, 0.0, 1.0); 29 | constrain(saturation, 0.0, 1.0); 30 | constrain(brightness, 0.0, 1.0); 31 | 32 | if(saturation == 0.0) 33 | { 34 | r = g = b = brightness; 35 | } 36 | else 37 | { 38 | float q = brightness < 0.5 ? 39 | brightness * (1.0 + saturation) : brightness + saturation - brightness * saturation; 40 | float p = 2.0 * brightness - q; 41 | r = hue2rgb(p, q, hue + 1.0/3.0); 42 | g = hue2rgb(p, q, hue); 43 | b = hue2rgb(p, q, hue - 1.0/3.0); 44 | } 45 | 46 | setColorRGB((uint8_t)(255.0*r), (uint8_t)(255.0*g), (uint8_t)(255.0*b)); 47 | } 48 | 49 | float hue2rgb(float p, float q, float t) 50 | { 51 | if (t < 0.0) 52 | t += 1.0; 53 | if(t > 1.0) 54 | t -= 1.0; 55 | if(t < 1.0/6.0) 56 | return p + (q - p) * 6.0 * t; 57 | if(t < 1.0/2.0) 58 | return q; 59 | if(t < 2.0/3.0) 60 | return p + (q - p) * (2.0/3.0 - t) * 6.0; 61 | 62 | return p; 63 | } 64 | -------------------------------------------------------------------------------- /wechat_v2/lib/RGB_Led_P9823/RGB_Led.h: -------------------------------------------------------------------------------- 1 | #ifndef RGB_LED_H 2 | #define RGB_LED_H 3 | 4 | #include "Arduino.h" 5 | #include "stdint.h" 6 | 7 | class RGB_Led 8 | { 9 | public: 10 | RGB_Led(int data_pin); 11 | 12 | void begin(void); 13 | void setColorRGB(uint8_t red, uint8_t green, uint8_t blue); 14 | void setColorHSB(float hue, float saturation, float brightness); 15 | 16 | private: 17 | int _data_pin; 18 | }; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /wechat_v2/lib/RGB_Led_P9823/example/RGB_Led_Example/RGB_Led_Example.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "RGB_Led.h" 4 | 5 | #define RGB_LED_DPIN 10 6 | 7 | RGB_Led rgb_led(10); 8 | unsigned long previousMillis = 0; 9 | 10 | static float hue = 0.0; 11 | static bool up = true; 12 | 13 | void setup() { 14 | rgb_led.begin(); 15 | //rgb_led.setColorRGB(255, 0, 0); 16 | } 17 | 18 | void loop() { 19 | rgb_led.setColorHSB(hue,1,0.1); 20 | if (up) 21 | hue+= 0.025; 22 | else 23 | hue-= 0.025; 24 | if (hue>=1.0 && up) 25 | up = false; 26 | else if (hue<=0.0 && !up) 27 | up = true; 28 | delay(200); 29 | } 30 | -------------------------------------------------------------------------------- /wechat_v2/lib/RGB_Led_P9823/p9823.cpp: -------------------------------------------------------------------------------- 1 | #include "p9823.h" 2 | #include "Arduino.h" 3 | 4 | #define DIN_HIGH *mp_out |= m_bit 5 | #define DIN_LOW *mp_out &= ~m_bit 6 | #define DELAYUS delayMicroseconds 7 | 8 | #define DELAY_LONG_NS {_NOP();_NOP();_NOP();_NOP();_NOP();\ 9 | _NOP();_NOP();_NOP();_NOP();_NOP();\ 10 | _NOP();_NOP();_NOP();_NOP();_NOP();\ 11 | _NOP();_NOP();_NOP();} 12 | 13 | #define DELAY_SHORT_NS {_NOP();} 14 | 15 | #define DELAY_RESET DELAYUS(50) 16 | 17 | static uint8_t m_bit; 18 | static volatile uint8_t *mp_out; 19 | 20 | static __inline void send_high_bit(void); 21 | static __inline void send_low_bit(void); 22 | 23 | void drv_data_pin_cfg(uint8_t pin) 24 | { 25 | uint8_t port; 26 | pinMode(pin, OUTPUT); 27 | 28 | m_bit = digitalPinToBitMask(pin); 29 | port = digitalPinToPort(pin); 30 | mp_out = portOutputRegister(port); 31 | 32 | } 33 | 34 | void drv_send_byte(uint8_t data) 35 | { 36 | uint8_t i; 37 | for(i=0;i<8;i++) 38 | { 39 | if(data&0x80) 40 | { 41 | send_high_bit(); 42 | } 43 | else 44 | { 45 | send_low_bit(); 46 | } 47 | data <<= 1; 48 | } 49 | } 50 | 51 | void drv_reset(void) 52 | { 53 | DIN_LOW; 54 | DELAY_RESET; 55 | } 56 | 57 | static __inline void send_high_bit(void) 58 | { 59 | DIN_HIGH; 60 | DELAY_LONG_NS; 61 | 62 | DIN_LOW; 63 | DELAY_SHORT_NS; 64 | } 65 | 66 | static __inline void send_low_bit(void) 67 | { 68 | DIN_HIGH; 69 | DELAY_SHORT_NS; 70 | 71 | DIN_LOW; 72 | DELAY_LONG_NS; 73 | } 74 | -------------------------------------------------------------------------------- /wechat_v2/lib/RGB_Led_P9823/p9823.h: -------------------------------------------------------------------------------- 1 | #ifndef P9823_H 2 | #define P9823_H 3 | 4 | #include "stdint.h" 5 | void drv_reset(void); 6 | 7 | void drv_data_pin_cfg(uint8_t pin); 8 | 9 | void drv_send_byte(uint8_t data); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /wechat_v2/readme.md: -------------------------------------------------------------------------------- 1 | ##一.快速体验 2 | ### 重要说明 3 | * 扩展板上的按键不要按! 4 | * 解释:由于Arduino Uno R3 只有一个串口,向板子里下载程序要用此串口。微信硬件蓝牙模块也要用串口和arduino通信,假如模块也使用此串口的话,就会出现一个问题,当模块插在板子上时,就无法下载程序。然后咱就使用软串口SoftSerial与模块通信,由于扩展板是采购的,相关硬件限制,只好把SoftSerial的两根线接到了按键上。按按键将会影响微信与arduino板的通信 5 | ### 体验步骤 6 | 1.上电:用usb线为板子上电 7 | 2.关注微信公众号 8 | 3.打开微信公众号, 9 | 4.向公众号发命令,如 蓝色,或者进入语音界面,说出指令 10 | 现支持指令:蓝色,红色,绿色,闪,变,熄灭,转,加速,减速,停,温度,湿度 11 | 12 | ##二.动手改之! 13 | ###相关资源 14 | * Arduino 官网 http://arduino.cc/ 15 | * Arduino 中文社区 http://www.arduino.cn/ 16 | * Arduino IDE链接 http://arduino.cc/en/Main/Software 17 | ### 开始动手(使用demo实验) 18 | 1.打开IDE 19 | 2.打开demo工程 wechat\wechat_hardware\wechat_hardware.ino 20 | 3.导入库:项目-->导入库-->添加库-->添加wechat\lib下的各个压缩包 21 | 4.添加指令:查找需要添加的中文指令的GB2312码,添加到宏定义处 22 | (简便方法:直接用微信公众号说指令,页面上会有相应的GB2312码,抄之) 23 | 5.添加相应的指令解析代码 24 | 6.添加自定义动作程序 -------------------------------------------------------------------------------- /wechat_v2/wechat_hardware/wechat_hardware.ino: -------------------------------------------------------------------------------- 1 | /* Because the UNO has only one Serail, and the wechat module will use a Serial. 2 | * If using the hardware serial, these is a upload problem when wechat module is on the board. 3 | * So in this demo,we select SoftwareSerial communicate with module. 4 | */ 5 | #include 6 | #include 7 | #include "Moto.h" 8 | #include "RGB_Led.h" 9 | #include "DHT11.h" 10 | 11 | #define CMD_GB2312_CODE_MAX_LEN 32 12 | #define CMD_REC_TIME_OUT 2000 13 | 14 | //Cmd, which is the GB2312 codes of the Chinese character 15 | #define GB_BLUE "C0B6C9AB" //"蓝色" 16 | #define GB_RED "BAECC9AB" //"红色" 17 | #define GB_GREEN "C2CCC9AB" //"绿色" 18 | #define GB_BLINK "C9C1" //"闪" 19 | #define GB_CHANGE "B1E4" //"变" 20 | #define GB_EXTINGUISH "CFA8C3F0" //"熄灭" 21 | #define GB_ROTATE "D7AA" //"转" 22 | #define GB_STOP "CDA3" //"停" 23 | #define GB_SPEEDUP "BCD3CBD9" //"加速" 24 | #define GB_SPEEDDOWN "BCF5CBD9" //"减速" 25 | #define GB_TEMP "CEC2B6C8" //"温度" 26 | #define GB_HUMI "CAAAB6C8" //"湿度" 27 | #define GB_BUZZ "B5CE" //"滴" 28 | /* 29 | Add your own cmd gb2312 code here 30 | */ 31 | 32 | // Definition of pins 33 | #define RGB_LED_PIN 8 34 | #define MOTO_ANODE_PIN 5 35 | #define MOTO_CATHODE_PIN 6 36 | #define DHT_PIN 2 37 | #define SOFTSERIAL_RX_PIN 10 38 | #define SOFTSERIAL_TX_PIN 11 39 | #define BUZZER_PIN 3 40 | #define KEY1_PIN 7 41 | #define KEY2_PIN 4 42 | 43 | #define RGB_RATIO 25 // 255(100%),here sets about %10,<免得亮瞎> 44 | #define MOTO_DEF_SPEED 50 // 255(100%),default 50 45 | 46 | typedef enum 47 | { 48 | RGB_STATE_EXTINGUISH, 49 | RGB_STATE_SINGLE, 50 | RGB_STATE_BLINK, 51 | RGB_STATE_RAINBOW 52 | }rgb_state_t; 53 | 54 | //New a RGB led 55 | RGB_Led rgbLed(RGB_LED_PIN); 56 | 57 | //New a moto 58 | Moto moto(MOTO_ANODE_PIN,MOTO_CATHODE_PIN); 59 | 60 | //New a DHT11 61 | DHT11 dht11(DHT_PIN); 62 | 63 | //New a SoftwareSerial 64 | SoftwareSerial mySerial(SOFTSERIAL_RX_PIN, SOFTSERIAL_TX_PIN); // RX, TX 65 | 66 | 67 | rgb_state_t rgb_led_state = RGB_STATE_EXTINGUISH; 68 | unsigned long previousMillis = 0; 69 | 70 | void setup() { 71 | //Hardware Serial 72 | Serial.begin(38400); 73 | while(!Serial); 74 | 75 | //SoftwareSerial 76 | mySerial.begin(38400); 77 | Serial.println("start"); 78 | 79 | rgbLed.begin(); 80 | rgbLed.setColorRGB(0,0,0); 81 | 82 | moto.begin(); 83 | 84 | pinMode(BUZZER_PIN,OUTPUT); 85 | pinMode(KEY1_PIN,INPUT_PULLUP); 86 | pinMode(KEY2_PIN,INPUT_PULLUP); 87 | 88 | MsTimer2::set(200, rgb_timeout_handler); 89 | MsTimer2::start(); 90 | 91 | } 92 | void loop() { 93 | 94 | //SoftwareSerial receive the cmd 95 | if (mySerial.available()) 96 | { 97 | int len=0; 98 | // The buffer size is now 32. So the max length of Cmd is 8 Chinese characters. 99 | char buffer[CMD_GB2312_CODE_MAX_LEN]; 100 | unsigned long startRecTimePoint = millis(); 101 | unsigned long recTime = startRecTimePoint; 102 | 103 | Serial.print("all character:"); 104 | while(recTime - startRecTimePoint < CMD_REC_TIME_OUT){ //If there is no timeout 105 | buffer[len]=mySerial.read(); 106 | Serial.print(" "); 107 | Serial.print(buffer[len]); 108 | //if encounter '\n' or len large than max len ,break 109 | if(buffer[len]=='\n' ||buffer[len]=='\r'|| len>=CMD_GB2312_CODE_MAX_LEN){ 110 | break; 111 | } 112 | len++; 113 | recTime= millis(); 114 | } 115 | Serial.print("rec cmd: "); 116 | Serial.write(buffer,len); 117 | Serial.println(""); 118 | if(!memcmp(buffer,GB_EXTINGUISH,len)&&len==strlen(GB_EXTINGUISH)){ 119 | rgb_led_state = RGB_STATE_EXTINGUISH; 120 | rgbLed.setColorRGB(0,0,0); 121 | } 122 | else if(!memcmp(buffer,GB_BLUE,len)&&len==strlen(GB_BLUE)){ 123 | rgb_led_state = RGB_STATE_SINGLE; 124 | rgbLed.setColorRGB(0,0,RGB_RATIO); 125 | } 126 | else if(!memcmp(buffer,GB_RED,len)&&len==strlen(GB_RED)){ 127 | rgb_led_state = RGB_STATE_SINGLE; 128 | rgbLed.setColorRGB(RGB_RATIO,0,0); 129 | } 130 | else if(!memcmp(buffer,GB_GREEN,len)&&len==strlen(GB_GREEN)){ 131 | rgb_led_state = RGB_STATE_SINGLE; 132 | rgbLed.setColorRGB(0,RGB_RATIO,0); 133 | } 134 | else if(!memcmp(buffer,GB_BLINK,len)&&len==strlen(GB_BLINK)){ 135 | rgb_led_state = RGB_STATE_BLINK; 136 | } 137 | else if(!memcmp(buffer,GB_CHANGE,len)&&len==strlen(GB_CHANGE)){ 138 | rgb_led_state = RGB_STATE_RAINBOW; 139 | } 140 | else if(!memcmp(buffer,GB_ROTATE,len)&&len==strlen(GB_ROTATE)){ 141 | moto.rotate(MOTO_DEF_SPEED); 142 | } 143 | else if(!memcmp(buffer,GB_SPEEDUP,len)&&len==strlen(GB_SPEEDUP)){ 144 | moto.speedup(); 145 | } 146 | else if(!memcmp(buffer,GB_SPEEDDOWN,len)&&len==strlen(GB_SPEEDDOWN)){ 147 | moto.speedown(); 148 | } 149 | else if(!memcmp(buffer,GB_STOP,len)&&len==strlen(GB_STOP)){ 150 | moto.stop(); 151 | } 152 | else if(!memcmp(buffer,GB_TEMP,len)&&len==strlen(GB_TEMP)){ 153 | dht11.read(); 154 | mySerial.print("Temperature (oC): "); 155 | mySerial.print((float)dht11.temperature, 2); 156 | mySerial.print("\n"); 157 | } 158 | else if(!memcmp(buffer,GB_HUMI,len)&&len==strlen(GB_HUMI)){ 159 | dht11.read(); 160 | mySerial.print("Humidity (%): "); 161 | mySerial.print((float)dht11.humidity, 2); 162 | mySerial.print("\n"); 163 | } 164 | else if(!memcmp(buffer,GB_BUZZ,len)&&len==strlen(GB_BUZZ)){ 165 | digitalWrite(BUZZER_PIN,HIGH); 166 | delay(100); 167 | digitalWrite(BUZZER_PIN,LOW); 168 | } 169 | /* 170 | Add your own code of cmd decoding here 171 | */ 172 | } 173 | 174 | if(digitalRead(KEY1_PIN)==LOW){ 175 | digitalWrite(BUZZER_PIN,HIGH); 176 | while(digitalRead(KEY1_PIN)==LOW); //blocking!! 177 | digitalWrite(BUZZER_PIN,LOW); 178 | } 179 | if(digitalRead(KEY2_PIN)==LOW){ 180 | digitalWrite(BUZZER_PIN,HIGH); 181 | while(digitalRead(KEY2_PIN)==LOW); //blocking!! 182 | digitalWrite(BUZZER_PIN,LOW); 183 | } 184 | } 185 | 186 | void rgb_timeout_handler(){ 187 | if(RGB_STATE_BLINK == rgb_led_state){ 188 | static unsigned long rgb= 0x00000019; //0x19 = 25 189 | rgbLed.setColorRGB(rgb&0x19,(rgb&0x00001900)>>8,(rgb&0x00190000)>>16); 190 | rgb = rgb<<8; 191 | if(rgb==0x19000000){ 192 | rgb=0x00000019; 193 | } 194 | } 195 | if(RGB_STATE_RAINBOW == rgb_led_state){ 196 | static float hue = 0.0; 197 | static bool up = true; 198 | rgbLed.setColorHSB(hue,1.0,0.1); 199 | if (up) 200 | hue+= 0.025; 201 | else 202 | hue-= 0.025; 203 | if (hue>=1.0 && up) 204 | up = false; 205 | else if (hue<=0.0 && !up) 206 | up = true; 207 | } 208 | } 209 | 210 | -------------------------------------------------------------------------------- /串口驱动/Mac OS X/CH341SER_MAC.ZIP: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/串口驱动/Mac OS X/CH341SER_MAC.ZIP -------------------------------------------------------------------------------- /串口驱动/Mac OS X/安装说明.md: -------------------------------------------------------------------------------- 1 | 1. 安装驱动 2 | 2. 执行命令 3 | sudo nvram boot-args="kext-dev-mode=1" 4 | 3. 重启系统 5 | 6 | 参考链接:http://javacolors.blogspot.com/2014/08/dccduino-usb-drivers-ch340-ch341-chipset.html -------------------------------------------------------------------------------- /串口驱动/Windows/CH341SER.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/串口驱动/Windows/CH341SER.zip -------------------------------------------------------------------------------- /串口驱动/Windows/HL-340.EXE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/串口驱动/Windows/HL-340.EXE -------------------------------------------------------------------------------- /串口驱动/Windows/支持Win7-Win8的驱动程序.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/串口驱动/Windows/支持Win7-Win8的驱动程序.jpg -------------------------------------------------------------------------------- /原理图/IOT 体验板原理图.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/原理图/IOT 体验板原理图.pdf -------------------------------------------------------------------------------- /原理图/SMART TAG 插槽原理图.PDF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sensoro/Wechat-IoT/4347e97e4450c0f1578fe0c742a396aa0e1baff8/原理图/SMART TAG 插槽原理图.PDF --------------------------------------------------------------------------------