CubieBoard中文论坛

 找回密码
 立即注册
搜索
热搜: unable
查看: 14427|回复: 5

DIY一个具有远程控制功能的智能家居原型系统

[复制链接]
发表于 2016-9-22 23:39:31 | 显示全部楼层 |阅读模式
smarthome 0.1是一个智能家居系统的雏形。主要实现局域网、因特网远程控制家里的电器;下一步要实现根据传感器数据控制家电功能;远景要实现根据人工智能自己控制电器功能;现在初步实现第一个功能。长得大概是这个样子。
系统框图如下。
远程控制主要实现方式:局域网或者手机登录架设在cubieboard2上的网页界面,点击开关、输入数字、输入文字提交之后,系统将数据交给后台python程序;由python程序提交给串口通信。串口数据发送到连接在cubieboard2上的arduino模块。arduino模块解析串口数据,控制相应的LED,伺服器和LCD显示器。
系统运行视频在这里http://v.youku.com/v_show/id_XMTcyNjk1MjY3Mg==.html。cubieboard2未出镜,他是系统主核心,完成web服务器架设,与arduino串口通信的功能,同时肩负arduino模块供电。
启动服务器pythonweb_manual.py 1234
访问相应服务器http://ip:1234就可以看到控制界面如图。
提交相应动作后,挂在Arduino上的各种设备会做出反应。
以后的文章会逐步复述这个小系统是怎么搭建起来的。
frame.JPG
real.jpg
web.PNG
回复

使用道具 举报

发表于 2016-9-26 20:43:41 | 显示全部楼层
我也做了一个,我的架构比较简单:
      cb上架设的apache+php,用于本地控制,而且我没有外接模块,直接是cb的gpio接继电器实现的,控制音响、自动浇花、加湿器、电风扇等。php通过system韩式实现调用shell。
      远程控制方面,我用的腾讯云,同样是架设的apache+php,通过向数据库写入需要执行的内容,必须定时浇花、打开加湿器等等动作,然后cb这边也是很简单的一个shell脚本curl去获取信息然后执行即可。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-9-29 17:22:25 | 显示全部楼层
Crazykiss 发表于 2016-9-26 20:43
我也做了一个,我的架构比较简单:
      cb上架设的apache+php,用于本地控制,而且我没有外接模块,直接 ...

嗯,我原来也这样干过,怕烧了CB,所以就把CB当成大脑,也方便以后扩展wifi模块什么的
回复 支持 反对

使用道具 举报

发表于 2016-10-11 13:51:55 | 显示全部楼层
很早以前也做个类似的系统。还接了入侵检测摄像头,烟雾火警,门窗防盗。。。有个异常就能在手机上收到短信告警,还可以通过云服务查看室内的摄像头呢。用的就是CB+一堆AVR单片机
回复 支持 反对

使用道具 举报

 楼主| 发表于 2016-10-18 10:50:38 | 显示全部楼层
本帖最后由 gongqingkui 于 2016-10-18 11:00 编辑

Arduino的LED、servo和LCD1602
这个系统可以识别三种指令:二值型、整数型和字符串型。
LED开关、闪烁显然是二值型的指令控制的。命令首字母为b,为b0或者b1,标示二值型的关和开。这里以控制Arduino板子上的LED为例:只用一句话digitalWrite(13, HIGH);或者digitalWrite(13, LOW);。这个LED的引脚接在13脚上,所以控制它高低电平就可以实现闪烁或者亮灭的功能。同理,如果不接Arduino板上的LED而另外接诸如继电器之类的元件,就可以实现控制外围高压电路的功能。
数值型指令发送一个整数,命令首字母为d,为 dIntNUM。这里用伺服器作为实例。伺服器根据收到的0-180的数据进行角度调整。语句也很简单。引入并且实例化Servo:
#include <Servo.h>
Servo servo1;
在setup()函数中servo1.attach(10);设定伺服器1的数据引脚接到10脚上。
在程序loop中进行接收和处理指令,之后发送角度到伺服器1:servo1.write(ans);
字符型的指令发送一条字符串给Arduino主机,命令首字母为s,为sString。这里用1602液晶屏做例子,把收到的字符串显示到液晶屏上。语句基本是:
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
初始化setup时:lcd.begin(16, 2);在随便输出点什么看看:lcd.print("SmartHome");。接收到相关字符串后,先设定显示位置lcd.setCursor(0, 0);然后输出数据lcd.print(data + 1);
以上,实现了接收指令后解析,发送到相应的设备或者控制外围硬件做出反应的功能。下面说明如何给Arduino发送指令。
串口
这个小系统Arduino的串口接收消息并解析、控制硬件。接收的三种消息分别用不同字母开头,Arduino判断首字母并解析出相应数据,发送控制命令给硬件。
在setup中打开和初始化串口。  Serial.begin(9600);
  Serial.flush();
在loop中接收串口发来的消息,存进buffer中,并调用splitString函数处理数据,再调用setLED完成对硬件发送控制指令的操作。
在测试时,可以使用Arduino自带的串口监视器,自己手动发送以b、d、s开头的测试信号。下面再连到Cubieboard上去。
Cubieboard串口链接
在这个小系统的设计中,Arduino负责硬件控制,接受解析指令。而另外一台Cubieboard2负责构建IOT服务器。这个服务器现在主要完成web接口和发送指令给Arduino的功能,未来还要完成自动控制和智能控制的功能。之所以不直接用Arduino做中心,也是考虑为未来自动和智能控制的留空间。
首先Cubieboard最简单先要和Arduino用串口连起来。插上USB转串口线之后,进到/dev/中ls下,可以看到以ttyUSB开头的设备,例如ttyUSB0,就表示串口线的名字。然后把TX和RX脚连到Arduino的0和1脚上。
用minicom软件测试下连上Arduino没有。首先下载安装sudo apt-get install minicom然后再配置下sudo minicom –s主要是把串口设置中的名字修改为USB串口线名字,关闭硬件流控制功能。然后就可以打开minicom测试了。直接输入相应的控制指令并且回车,就会将指令发送到Arduino中,如果有错的话,可以试下把串口线rx和tx对调。
Python串口
Minicom串口测试正常之后,就可以写Python程序通过串口发送指令了。写好串口收发程序也是为了下一步web封装和与在线物联网服务连接。
发送程序serialPortModule.py比较简单:
  1. import serial
  2. def serialSend(str):
  3.     t = serial.Serial('/dev/ttyUSB1',9600)
  4.     with t:
  5.         n = t.write(str)
  6.     t.close()
  7.     return n
复制代码
引入serial包后,新建一个发送函数serialSend,以待发送指令作为参数。语句很简单,返回发送的指令长度。这里唯一需要注意的是ttyUSB的编号,要在/dev/里查询得到。那么接收的程序serialRead.py是这样的:
  1. import serial
  2. def serialRead():
  3.     t = serial.Serial('/dev/ttyUSB1',9600)
  4.     print t.isOpen()
  5. with t:
  6.         while(1):
  7.             s = t.readline()
  8.             print s
  9. #todo save to DB or web
  10. if __name__ == '__main__':
  11.     serialRead()
复制代码
程序自动接收串口发送的字符串指令,解析后可以完成转发到在线服务器或者存储到数据库的操作。
Pythonweb封装
编写好串口发送函数后,可在命令行下进行简单测试。测试无误后,可以编写web程序,在web程序中,根据用户点击,来调用串口发送函数,进行指令的传递。Web服务器这里用的是python的web库。代码如下:
web_manual.py程序导入相应的包后,首先用render指明模板所在目录templates/,然后指定URL访问列表情况,最后根据URL中制定名字,编写相应的控制器。控制器中的GET和POST分别指代两种访问方法,用render.具体模板名来传值到相应模板。Db类和sqldb类用来访问本地sqlite3数据库。经过以上程序,在服务器中打开python web.py 1234,然后访问localhost:1234既可以访问到这个简单的网站,实现局域网内查看和控制设备的能力。
  1. # encoding: utf-8
  2. import web
  3. import os
  4. import sqlite3
  5. import time
  6. import serial
  7. from actuatorModule import execute
  8. from web import form
  9. # templete floder
  10. render = web.template.render('templates/')

  11. # url tables
  12. urls = ('/', 'index',
  13.         '/manualcontroller', 'manualcontroller',
  14.         '/temperature', 'temperature',
  15.         '/humidity', 'humidity'
  16.         )


  17. class index:
  18.     def GET(self):
  19.         return render.index()


  20. class temperature:
  21.     def GET(self):
  22.         db1 = db()
  23.         rs = db1.execute('select * from temperature order by id desc limit 20')
  24.         return render.temperature(rs)


  25. class humidity:
  26.     def GET(self):
  27.         db1 = db()
  28.         rs = db1.execute('select * from humidity order by id desc limit 20')
  29.         return render.humidity(rs)


  30. class manualcontroller:

  31.     def GET(self):
  32.         return web.seeother('/')

  33.     def POST(self):
  34.         i = web.input()
  35.         print i.switcher1, i.servor1, i.led1
  36.         if i.servor1 != "":
  37.             if int(i.servor1)>=0 and int(i.servor1) <=180:
  38.                 execute("d",i.servor1)
  39.         elif i.led1 != "":   
  40.             if i.led1 !="":
  41.                 execute("s",i.led1)
  42.         elif i.switcher1 != "":
  43.             if i.switcher1 == "1" or i.switcher1 == "0" :
  44.                 execute("b",i.switcher1)
  45.         return web.seeother('/')

  46. class db:
  47.     def __init__(self):
  48.         self.db = sqldb()
  49.     def insert(self,table,values):
  50.         return
  51.     def delete(self,table,index):
  52.         return
  53.     def update(self,table,index,values):
  54.         return
  55.     def select(self,table,index):
  56.         i = (table,index)
  57.         sql = 'select * from %s where id = %d'%(table,index)
  58.         self.db.cu.execute(sql)
  59.         rs = self.db.cu.fetchall()
  60.         self.db.conn.commit()
  61.         return rs
  62.     def execute(self,sql):
  63.         self.db.cu.execute(sql)
  64.         rs = self.db.cu.fetchall()
  65.         self.db.conn.commit()
  66.         return rs
  67.    
  68.    
  69. class sqldb:

  70.     def __init__(self):
  71.         self.db = 'db.db'
  72.         if os.path.exists(self.db):
  73.             self.conn = sqlite3.connect(self.db)
  74.             self.cu = self.conn.cursor()
  75.         else:
  76.             self.conn = sqlite3.connect(self.db)
  77.             self.cu = self.conn.cursor()
  78.             self.cu.execute(
  79.                 'create table sensors(id integer primary key autoincrement,date text,value text)')
  80.             self.cu.execute(
  81.                 'insert into sensors values(null,\'2016-1-1 12:00:00\',\'32\')')
  82.             self.cu.execute(
  83.                 'create table actuators(id integer primary key autoincrement,date text,value text)')
  84.             self.cu.execute(
  85.                 'insert into actuators values(null,\'2016-1-1 12:00:02\',\'open AC ato 26\')')
  86.             self.conn.commit()


  87. if __name__ == '__main__':
  88.     app = web.application(urls, globals())
  89.     app.run()
复制代码
采用上诉方法开启服务器之后,智能内网访问web服务,为了达到外网操作的能力,需要使用花生壳的动态IP的映射的服务。
花生棒
    一般家庭使用的网络均是动态变更IP地址的,外网访问不方便。这里使用花生棒来保证外网访问内网的能力。需要在oray注册账号,并购买花生棒,绑定账号,指定内网IP和Port对外共享,之后就可以在外网使用内网服务了。
DHT11
系统目前还只具备接受和解析指令控制外围设备的功能,不能从周围环境探测信号。现在我们增加个简单的温湿度探测器,连接到Arduino上,然后将接受的数据通过串口传递到cb上。
DHT引脚如图所示**,自左至右分别是+5V,data,nc,Gnd。连线比较简单,电源接好后,data线连接到Arduino的引脚9上就行了。需要添加的程序如下。
  1. #include <dht11.h>
  2. dht11 DHT11;
  3. #define DHT11PIN 9
  4. float humidity = 0.0;
  5. float temperature = 0.0;
  6. 主程序中:
  7. int chk = DHT11.read(DHT11PIN);  
  8. switch (chk)
  9. {
  10.   case DHTLIB_OK:
  11. break;
  12.   case DHTLIB_ERROR_CHECKSUM:
  13.     break;
  14.   case DHTLIB_ERROR_TIMEOUT:
  15.     break;
  16.   default:
  17.     break;
  18. }
  19. humidity = (float)DHT11.humidity;
  20. temperature = (float)DHT11.temperature;
复制代码
回复 支持 反对

使用道具 举报

发表于 2016-12-13 21:05:09 | 显示全部楼层
给力
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|粤ICP备13051116号|cubie.cc---深刻的嵌入式技术讨论社区

GMT+8, 2024-3-29 00:02 , Processed in 0.027770 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2012 Comsenz Inc. | Style by Coxxs

返回顶部