gongqingkui 发表于 2016-9-22 23:39:31

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

smarthome 0.1是一个智能家居系统的雏形。主要实现局域网、因特网远程控制家里的电器;下一步要实现根据传感器数据控制家电功能;远景要实现根据人工智能自己控制电器功能;现在初步实现第一个功能。长得大概是这个样子。系统框图如下。http://www.cubie.cc/forum.php?mod=image&aid=4259&size=300x300&key=fe7a40b5387ea5cd&nocache=yes&type=fixnone远程控制主要实现方式:局域网或者手机登录架设在cubieboard2上的网页界面,点击开关、输入数字、输入文字提交之后,系统将数据交给后台python程序;由python程序提交给串口通信。串口数据发送到连接在cubieboard2上的arduino模块。arduino模块解析串口数据,控制相应的LED,伺服器和LCD显示器。 http://www.cubie.cc/forum.php?mod=image&aid=4260&size=300x300&key=185bf73bceb4bb30&nocache=yes&type=fixnone系统运行视频在这里http://v.youku.com/v_show/id_XMTcyNjk1MjY3Mg==.html。cubieboard2未出镜,他是系统主核心,完成web服务器架设,与arduino串口通信的功能,同时肩负arduino模块供电。程序代码:https://github.com/gongqingkui/smarthome启动服务器pythonweb_manual.py 1234访问相应服务器http://ip:1234就可以看到控制界面如图。http://www.cubie.cc/forum.php?mod=image&aid=4261&size=300x300&key=29da40c593619254&nocache=yes&type=fixnone提交相应动作后,挂在Arduino上的各种设备会做出反应。以后的文章会逐步复述这个小系统是怎么搭建起来的。

Crazykiss 发表于 2016-9-26 20:43:41

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

gongqingkui 发表于 2016-9-29 17:22:25

Crazykiss 发表于 2016-9-26 20:43 static/image/common/back.gif
我也做了一个,我的架构比较简单:
      cb上架设的apache+php,用于本地控制,而且我没有外接模块,直接 ...

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

soloforce 发表于 2016-10-11 13:51:55

很早以前也做个类似的系统。还接了入侵检测摄像头,烟雾火警,门窗防盗。。。有个异常就能在手机上收到短信告警,还可以通过云服务查看室内的摄像头呢。用的就是CB+一堆AVR单片机

gongqingkui 发表于 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比较简单:import serial
def serialSend(str):
    t = serial.Serial('/dev/ttyUSB1',9600)
    with t:
      n = t.write(str)
    t.close()
    return n
引入serial包后,新建一个发送函数serialSend,以待发送指令作为参数。语句很简单,返回发送的指令长度。这里唯一需要注意的是ttyUSB的编号,要在/dev/里查询得到。那么接收的程序serialRead.py是这样的:import serial
def serialRead():
    t = serial.Serial('/dev/ttyUSB1',9600)
    print t.isOpen()
with t:
      while(1):
            s = t.readline()
            print s
#todo save to DB or web
if __name__ == '__main__':
    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既可以访问到这个简单的网站,实现局域网内查看和控制设备的能力。# encoding: utf-8
import web
import os
import sqlite3
import time
import serial
from actuatorModule import execute
from web import form
# templete floder
render = web.template.render('templates/')

# url tables
urls = ('/', 'index',
      '/manualcontroller', 'manualcontroller',
      '/temperature', 'temperature',
      '/humidity', 'humidity'
      )


class index:
    def GET(self):
      return render.index()


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


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


class manualcontroller:

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

    def POST(self):
      i = web.input()
      print i.switcher1, i.servor1, i.led1
      if i.servor1 != "":
            if int(i.servor1)>=0 and int(i.servor1) <=180:
                execute("d",i.servor1)
      elif i.led1 != "":   
            if i.led1 !="":
                execute("s",i.led1)
      elif i.switcher1 != "":
            if i.switcher1 == "1" or i.switcher1 == "0" :
                execute("b",i.switcher1)
      return web.seeother('/')

class db:
    def __init__(self):
      self.db = sqldb()
    def insert(self,table,values):
      return
    def delete(self,table,index):
      return
    def update(self,table,index,values):
      return
    def select(self,table,index):
      i = (table,index)
      sql = 'select * from %s where id = %d'%(table,index)
      self.db.cu.execute(sql)
      rs = self.db.cu.fetchall()
      self.db.conn.commit()
      return rs
    def execute(self,sql):
      self.db.cu.execute(sql)
      rs = self.db.cu.fetchall()
      self.db.conn.commit()
      return rs
   
   
class sqldb:

    def __init__(self):
      self.db = 'db.db'
      if os.path.exists(self.db):
            self.conn = sqlite3.connect(self.db)
            self.cu = self.conn.cursor()
      else:
            self.conn = sqlite3.connect(self.db)
            self.cu = self.conn.cursor()
            self.cu.execute(
                'create table sensors(id integer primary key autoincrement,date text,value text)')
            self.cu.execute(
                'insert into sensors values(null,\'2016-1-1 12:00:00\',\'32\')')
            self.cu.execute(
                'create table actuators(id integer primary key autoincrement,date text,value text)')
            self.cu.execute(
                'insert into actuators values(null,\'2016-1-1 12:00:02\',\'open AC ato 26\')')
            self.conn.commit()


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

翼京/ka 发表于 2016-12-13 21:05:09

给力:):):):):)
页: [1]
查看完整版本: DIY一个具有远程控制功能的智能家居原型系统