本帖最后由 放了假的人 于 2015-11-9 22:57 编辑
被队友安利来了这次的Hack上海,本着蹭吃蹭喝蹭妹子(并没有)的想法我们四个就这么来到了现场。没有想到的是我们有幸借到了设备,惊喜地打开了新世界的大门←_←
在没有读取办法USB MODEM的情况下能成功调试真的很开心
项目假设的应用场景是大家放在寝室放在家里的植物。光照不够番茄不好吃怎么办?寝室太热捕蝇草闷死了怎么办?万一植物逃跑了怎么办?(咳咳,只是在现场看到三轴加速度计开的脑洞)其实对项目加以扩展的话,是可以在一台数据服务器下形成庞大的传感器网络,并且供给产业用途的喔~
硬件部分的构建比较简单,隔一段时间读取一次传感器数据传到数据服务器,再响应服务器控制信号就可以了。之后网页服务器的队友会用一种叫拉格朗日XXX的机器学习算法处理数据,判断温度是不是过高,光照是不是不够,然后返回相应的控制信号。最后通过网页端和移动端App的页面,用户可以看到实时反馈和数据统计,并且关闭自动控制,人工控制设备(模拟光照强度的灯条,模拟通风系统的电动机,etc)
如何将开发版和数据服务器连接起来呢?考虑到只有24小时,我们果断选择了比较成熟的WLAN。而具体上传下载的问题,也是选择了一个TRICK,即GET方法利用Query String形式上传数据,再让服务器把控制信号当Response Body回传,就用简单的几秒一次的GET请求解决了数据的传输。
//然而会场WIFI信号实在不稳定,终端和网络都很多,丢包严重,设备之间的链接经常出问题
最后长这个样子,传感器加数据线加WIFI天线刚好八根,八爪鱼(章鱼哥)的名字也取自它
网页端实时数据与数据统计页面
移动端数据统计页面
感谢Hack[上海]/NYUSH
感谢DFROBOT
感谢相互调用相互传参其乐融融的队友
感谢MTK, node, Java, ionic
Arduino源代码
- #include <LWiFi.h>
- #include <LWiFiClient.h>
-
- #include <Wire.h>
- #include <Suli.h>
- #include "Seeed_LED_Bar_Arduino.h"
- #include "DHT.h"
- #include "Barometer.h"
- #include <Servo.h>
-
- #define WIFI_AP "WLAN-SSID"
- #define WIFI_PASSWORD "WLAN-PWD"
- #define SITE_URL "数据服务器IP地址"
-
- const int PIN_LED= 13;
- const int LEF_BAR_CLK = 8;
- const int LEF_BAR_DTA = 7;
- const int PIN_LIGHT_SENSOR = A0;
- #define DHTPIN 2
- #define DHTTYPE DHT22
- const int PIN_UV_SENSOR = A1;
- const int PIN_DUST_SENSOR = 3;
- const unsigned long DUST_SENSOR_SAMPLETIME = 60000;
- const int PIN_SERVO = 8;
-
- LWiFiClient c;
- SeeedLedBar bar(LEF_BAR_CLK, LEF_BAR_DTA);
- int controlled_light_level;
- DHT dht(DHTPIN, DHTTYPE);
- Barometer myBarometer;
- int timestamp;
- unsigned long dust_duration_sum;
- Servo myservo;
-
- void blink(int i){ //控制LED闪烁的函数,没有Modem都是泪
- for(int k=0;k<i;k++){
- digitalWrite(PIN_LED, LOW); // turn the LED off by making the voltage LOW
- delay(200); // wait for a second
- digitalWrite(PIN_LED, HIGH); // turn the LED on (HIGH is the voltage level)
- delay(200); // wait for a second
- }
- }
-
- void setup() {
- pinMode(PIN_LED, OUTPUT);
- digitalWrite(PIN_LED, HIGH);
- Serial1.begin(9600);
- LWiFi.begin();
- Serial1.println();
- Serial1.print("Connecting to AP...");
- if(LWiFi.connectWPA(WIFI_AP, WIFI_PASSWORD) < 0)
- {
- Serial1.println("FAIL!");
- blink(5);
- return;
- }
- blink(1);
- Serial1.println("ok");
- Serial1.print("Connecting to site...");
- bar.begin(LEF_BAR_CLK, LEF_BAR_DTA);
- bar.setLevel(0);
- bar.setLevel(10);
- delay(500);
- bar.setLevel(0);
- myBarometer.init();
- timestamp = millis();
- dust_duration_sum = 0.0;
- }
-
- void loop() {
- if(!c.connect(SITE_URL, 4040))
- {
- Serial1.println("FAIL!");
- blink(7);
- bar.setLevel(0);
- bar.setLevel(5);
- delay(500);
- bar.setLevel(0);
- return;
- }
- Serial1.println("ok");
- blink(4);
- Serial1.println("send HTTP GET request");
-
- int light_value = analogRead(PIN_LIGHT_SENSOR);
- float temperature = 0.0;
- float humidity = 0.0;
- float pressure = myBarometer.bmp085GetPressure(myBarometer.bmp085ReadUP());
- // float altitude = myBarometer.calcAltitude(pressure);
- long uv_sum = 0;
- for(int i=0; i<32; i++)
- {
- uv_sum += analogRead(PIN_UV_SENSOR);
- delay(10);
- }
- uv_sum = (uv_sum >> 5) * 4980.0 / 1023.0;
- dust_duration_sum += pulseIn(PIN_DUST_SENSOR, LOW);
-
- c.print("GET /sensor/update?");
- c.print("light=");
- c.print(light_value);
- if(dht.readHT(&temperature, &humidity)){
- c.print("&");
- c.print("temperature=");
- c.print(temperature);
- c.print("&");
- c.print("humidity=");
- c.print(humidity);
- }
- c.print("&");
- c.print("pressure=");
- c.print(pressure);
- c.print("&");
- c.print("uv=");
- c.print(uv_sum);
- if ((millis() - timestamp) > DUST_SENSOR_SAMPLETIME){
- c.print("&");
- c.print("dust=");
- c.print(dust_duration_sum);
- dust_duration_sum = 0;
- timestamp = millis();
- }
- c.println(" HTTP/1.1");
- c.println("Host: " SITE_URL);
- c.println("Connection: close");
- c.println();
- blink(4);
-
- if (c.available()){
- char v = 0;
- while(c.available()){
- v = c.read();
- if(v < 0)
- break;
- else{
- controlled_light_level = v - '0';
- }
- }
- if (controlled_light_level) bar.setLevel(controlled_light_level - 1);
- }
- delay(1000);
- }
复制代码
数据服务器源代码(Node.js)
index.js
- /**
- * Author: rapidehere@gmail.com
- * Maintainer: rapidhere@gmail.com
- */
-
- 'use strict';
-
- var server = require('./lib/server').server;
-
- server.listen(4040, '0.0.0.0');
- console.log('server start on 0.0.0.0:4040');
- console.log('# PRESS CTRL-C TO STOP #');
-
- process.on('SIGINT', function() {
- server.close();
- process.exit(0);
- });
复制代码
/lib/Server.js
- /**
- * Author: rapidhere@gmail.com
- * Maintainer: rapidhere@gmail.com
- */
- 'use strict';
-
- var http = require('http');
- var url = require('url');
- var util = require('util');
-
- var sensorData = {
- light: 0,
- temperature: 0,
- humidity: 0,
- pressure: 0,
- uv: 0,
- dust: 0,
- };
-
- var currentLightLevel = 0;
- var nextLightLevel = 0;
-
- var _log = function(msg) {
- var date = new Date();
- console.log('[' + date.toISOString() + ']' + ' ' + msg);
- };
-
- var httpLogger = function(req, message) {
- _log(req.socket.remoteAddress + ' ' + req.method + ' ' + req.url + ': ' + message);
- };
-
- var send200Body = function(req, res, content) {
- res.writeHead(200, 'OK', {
- 'Content-Type': 'application/json',
- 'Content-Length': content.length
- });
- res.end(content, function() {
- httpLogger(req, '200 OK: content: ' + content);
- });
- };
-
- var server = http.createServer(function(req, res) {
- httpLogger(req, 'get request');
-
- // only handle GET method
- if(req.method !== 'GET') {
- res.writeHead(405, 'METHOD NOT ALLOWED');
- res.end(function() {
- httpLogger(req, '405 METHOD NOT ALLOWED');
- });
- return;
- }
-
- // parse url
- var tmp = url.parse(req.url, true, false);
-
- var pathname = tmp.pathname;
- var query = tmp.query;
-
- // return sensor data
- if(pathname === '/sensor/get_data') {
- send200Body(req, res, JSON.stringify(sensorData));
- }
- else if(pathname === '/light/level') {
- nextLightLevel = parseInt(query.level || nextLightLevel);
- send200Body(req, res, JSON.stringify({
- 'old_light_level': currentLightLevel
- }));
- }
- // echo for debug usage
- else if(pathname === '/sensor/echo') {
- var msg = query.message || 'NO MESSAGE';
- send200Body(req, res, msg);
- }
- // sensor message update
- else if(pathname === '/sensor/update') {
- sensorData.light = parseFloat(query.light || sensorData.light);
- sensorData.humidity = parseFloat(query.humidity || sensorData.humidity);
- sensorData.temperature = parseFloat(query.temperature || sensorData.temperature);
- sensorData.pressure = parseFloat(query.pressure || sensorData.pressure);
- sensorData.uv = parseFloat(query.uv || sensorData.uv);
- sensorData.dust = parseFloat(query.dust || sensorData.dust);
-
- httpLogger(req, 'update done: sensorData: ' + JSON.stringify(sensorData));
-
- var returnContent = '0';
- if(nextLightLevel !== currentLightLevel) {
- currentLightLevel = nextLightLevel;
- returnContent = String.fromCharCode(48 + currentLightLevel + 1);
- httpLogger(req, 'turn light level to ' + currentLightLevel);
- }
-
- send200Body(req, res, returnContent);
- }
- // default url, return 404
- else {
- res.writeHead(404, 'NOT FOUND');
- res.end(function() {
- httpLogger(req, '404 NOT FOUND');
- });
- return ;
- }
- });
-
- // server error handling
- server.on('clientError', function(err, socket) {
- _log('# HTTP ERROR: ' + ': ' + err + '\nsocket: ' + util.inspect(socket));
- });
-
- exports.server = server;
复制代码
服务端代码众多,补充中...
|