2020-03-14 12:18:07 qq_36243942 阅读数 3285
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    702 人正在学习 去看看 陈贤能

前言:在前面做了一个简易的远程空调控制器(点我查看),刚好现在家里有一个闲置的天猫精灵,于是乎就想让电视机也接入语音控制。在Blinker官网详细介绍了天猫精灵是如何接入的,有了前面简易远程空调控制器的制作基础,这个例程就很好做了。只需要就上几行简单的代码
备注:

演示视频

ESP8266接入天猫精灵控制电视机

1.准备工作

1.1 原理

----本实验的原理比较简单,使用Arduino开发软件的第三方库(IRremoteESP8266)的示例,读取空调/电视,红外遥控的原始数据,把需要控制的按键红外键值的原始数据保存到数组中(红外协议不同,原始数据的长度有差异)。

---- 把ESP8266接入Blinker(点灯科技),使用Blinker的app去配置UI界面,然后在Arduino开发软件编写简单的控制逻辑,通过app的按钮发送指定的红外指令或接受天猫精灵的指令,间接达到控制的目的。

1.2 使用的硬件以及硬件连接图

  • 天猫精灵(方糖)
  • ESP8266 NodeMCU
  • 红外发射模块、红外接收模块(HX1838)
  • 接收红外控制的电视机
  • 电视机顶盒
    备注:在这里说明一下,因为家里的电视是连接天猫魔盒的,因此如果想开启或关闭电视,必须同时打开/关闭电视和天猫魔盒(所以需要发送两个红外指令,在这里使用了两个红外发射管(非必须)。一个对准电视红外接收管,一个对准天猫精灵红外接收管)。
    在这里使用的硬件很简单(红外接收头未给出)。如下所示:
    在这里插入图片描述

1.3 开发环境准备

备注:安装1.8.7或更新版本,这个软件是免费使用的,直接在官网下载安装最新版本即可。

  • 安装ESP8266的扩展
    方法一:如果你的电脑能够科学上网的话,使用这个方法很简便,在首选项中输入一个网址,然后添加库即可。否则参考方法二。
  1. 启动Arduino并打开“首选项”窗口。
  2. 输入https://arduino.esp8266.com/stable/package_esp8266com_index.json
    在这里插入图片描述
  3. 从工具>主板菜单打开Boards Manager并安装esp8266平台(安装后不要忘记从工具>主板菜单中选择ESP8266主板)。
    在这里插入图片描述
    方法二:下载打包的esp8266安装包,直接运行并解压即可。

链接:https://pan.baidu.com/s/1Eu0qhlP5xu6GgQMdwflfAw 提取码:3x1f

备注:如果安装过其他版本的esp8266sdk,请先删除,再使用本安装包,解压完成后,再打开Arduino IDE,即可在 菜单栏>工具>开发板 中找到你使用的esp8266开发板

  • 安装 IRremoteESP8266 库
    这个库中有关于ESP8266 接收红外解码,以及发送红外数据的函数。是这个例程的一个核心函数
    安装方法:如果直接在Anduino IDE中安装,也是需要科学上网的,否则速度会很慢。
    方法一:直接在IDE中安装
    在这里插入图片描述
    方法二:离线安装
    下载IRremoteESP8266安装包

链接:https://pan.baidu.com/s/1RlHPts_dNj6MVR9pARxLuA 提取码:0n6t

下载完成之后,把它解压缩在项目文件夹的library文件夹中
项目文件夹在这里插入图片描述

  • 安装blinker Arduino库
    安装方法,同IRmoteESP8266库安装的方法二相同。

链接:https://pan.baidu.com/s/1k5tED9HxgiRaqNtKrTJcRg 提取码:87lw

安装后如下图所示:
在这里插入图片描述
安装成功之后重启Arduino软件,可以在示例的第三方库库中找到。
在这里插入图片描述

  • 安装blinker APP
  • Android下载:点我进入
    或 在android应用商店搜索“blinker”下载安装
  • IOS下载:在app store中搜索“blinker”下载

小结:完成了准备工作之后,就可以进入下一步。可以使用 IRremoteESP8266的示例,对电视机的开关红外红外进行解码。

2.解码空调红外键值

2.1 把ESP8266红外接收的实例,上传到NodeMCU中

  • 打开红外接收的示例
    在这里插入图片描述
  • 选择所使用的开发版和连接的COM口(根据实际情况选择)
    在这里插入图片描述
  • 把红外接收模块的数据段连接到GPIO14(Node MCU 对应D5引脚)

在这里插入图片描述

  • 上传程序到 Node MCU 上
    在这里插入图片描述

2.2 读取红外键值

  • 打开Arduino 调试 串口监视器
    在这里插入图片描述
  • 电视遥控器对准红外接收管(这里以TCL电视和天猫精灵为准)
    在这里插入图片描述
  • 捕获红外键值
    读取两个开关键(通过串口打印发现,无论是打开或者是关闭电视机/天猫魔盒,其发送的红外指令都是同样的)。
    在串口中打印获取的rowData数据如下:
/*电视电源*/
uint16_t tv_power[207] = {3976, 4024,  500, 2008,  498, 2006,  476, 2032,  476, 2030,  474, 1030,  476, 1030,  500, 2010,  476, 1030,  474, 2032,  478, 1030,  474, 2034,  498, 1006,  474, 1032,  474, 1032,  474, 1032,  474, 1030,  476, 2030,  476, 2032,  474, 1030,  500, 2010,  474, 1032,  474, 2032,  474, 1032,  476, 2028,  476, 8494,  3976, 4026,  500, 2006,  476, 2032,  476, 2030,  476, 2030,  476, 1032,  474, 1032,  476, 2032,  498, 1030,  450, 2034,  474, 1028,  476, 2034,  498, 1008,  498, 1008,  476, 1032,  472, 1032,  474, 1032,  474, 2032,  502, 2008,  474, 1030,  476, 2032,  500, 1030,  452, 2032,  474, 1030,  476, 2026,  498, 8476,  3972, 4024,  476, 2032,  476, 2032,  474, 2034,  472, 2056,  452, 1032,  474, 1056,  450, 2034,  500, 1030,  452, 2056,  450, 1032,  474, 2034,  472, 1056,  450, 1032,  474, 1056,  450, 1034,  472, 1034,  472, 2034,  500, 2006,  474, 1032,  496, 2012,  474, 1056,  448, 2058,  476, 1006,  474, 2028,  476, 8494,  3998, 4000,  474, 2036,  472, 2032,  474, 2056,  474, 2008,  474, 1056,  450, 1056,  448, 2036,  474, 1034,  472, 2036,  472, 1056,  450, 2036,  470, 1034,  472, 1058,  450, 1032,  474, 1032,  498, 1030,  450, 2032,  474, 2034,  498, 1032,  448, 2036,  472, 1058,  450, 2034,  478, 1054,  472, 2008,  472};  // NIKAI D5F2A

/*天猫精灵电源*/
uint16_t timo_power[67] = {9010, 4476,  580, 552,  580, 554,  578, 550,  578, 552,  582, 552,  578, 554,  572, 558,  578, 552,  582, 1656,  582, 1656,  582, 1654,  580, 1658,  580, 1658,  580, 554,  578, 552,  578, 1660,  580, 1658,  580, 1656,  580, 1658,  584, 552,  578, 1658,  582, 552,  578, 1656,  582, 554,  576, 554,  580, 552,  578, 554,  580, 1658,  580, 552,  554, 1682,  582, 552,  580, 1658,  560};  // NEC F9EA15


备注:保存下来,待会程序中需要用到。

3. 配置Blinker App的UI界面

  • 注册账号
    使用手机号码即可注册账号。
  • 添加设备->wifi接入–>得到产品密钥(Secret Key)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 修改设备名字和图标
    在这里插入图片描述
  • 编辑UI界面
    在这里添加两个按钮即可,一个打开/关闭电视、一个打开/关闭空调。
    在这里插入图片描述
    设置按键属性
    在这里插入图片描述
    效果如下:
    在这里插入图片描述
    这样一来,简单的控制界面就设置好了。

4.Arduino程序的编写

具体如何编写Arduino程序,可以在Blinker官网中有介绍:点我查看

4.1 控制逻辑

控制的逻辑很简单,当Node MCU 连接上WiFi并显示在线状态时,通过按手机app上的按键。程序发送指令的红外指定达到控制电视的目的。还有就是天猫精灵的控制,当天猫精灵接受到指令,并在程序中解析之后,发送指定的红外指令达到控制电视的目的,后面详细介绍如何操作。
备注:在进行操作之前,先连接好红外发射模块所连接的IO口,在这里使用的是GPIO4(即Node MCU的 D2引脚)

4.2 新建一个Arduino程序,编写控制逻辑

新建一个文件->另存为mIRremote_control(程序名随意)
在这里插入图片描述
根据Blinker官网给出的接入天猫精灵的教程
在这里插入图片描述
直接贴上程序,程序比较简单且有注解:

//串口打印相关
#define BLINKER_PRINT Serial
//Blinker使用wifi接入
#define BLINKER_WIFI
//天猫精灵控制的为插座(单个)
#define BLINKER_ALIGENIE_OUTLET
//红外接收解析头文件
#include <IRremoteESP8266.h>
//红外发送头文件
#include <IRsend.h>
//Blinker相关程序头文件
#include <Blinker.h>

//这里输入自己的密钥,wifi账号密码(注意大小写)。
char auth[] = "*****";
char ssid[] = "*****";
char pswd[] = "*****";
//定义红外发射的管脚
const uint16_t kIrLed = 4;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).
//定义GPIO4的管脚为红外发射管脚
IRsend irsend(kIrLed);  // Set the GPIO to be used to sending the message.

/*电视电源红外原始数据*/
uint16_t tv_power[207] = {3976, 4024,  500, 2008,  498, 2006,  476, 2032,  476, 2030,  474, 1030,  476, 1030,  500, 2010,  476, 1030,  474, 2032,  478, 1030,  474, 2034,  498, 1006,  474, 1032,  474, 1032,  474, 1032,  474, 1030,  476, 2030,  476, 2032,  474, 1030,  500, 2010,  474, 1032,  474, 2032,  474, 1032,  476, 2028,  476, 8494,  3976, 4026,  500, 2006,  476, 2032,  476, 2030,  476, 2030,  476, 1032,  474, 1032,  476, 2032,  498, 1030,  450, 2034,  474, 1028,  476, 2034,  498, 1008,  498, 1008,  476, 1032,  472, 1032,  474, 1032,  474, 2032,  502, 2008,  474, 1030,  476, 2032,  500, 1030,  452, 2032,  474, 1030,  476, 2026,  498, 8476,  3972, 4024,  476, 2032,  476, 2032,  474, 2034,  472, 2056,  452, 1032,  474, 1056,  450, 2034,  500, 1030,  452, 2056,  450, 1032,  474, 2034,  472, 1056,  450, 1032,  474, 1056,  450, 1034,  472, 1034,  472, 2034,  500, 2006,  474, 1032,  496, 2012,  474, 1056,  448, 2058,  476, 1006,  474, 2028,  476, 8494,  3998, 4000,  474, 2036,  472, 2032,  474, 2056,  474, 2008,  474, 1056,  450, 1056,  448, 2036,  474, 1034,  472, 2036,  472, 1056,  450, 2036,  470, 1034,  472, 1058,  450, 1032,  474, 1032,  498, 1030,  450, 2032,  474, 2034,  498, 1032,  448, 2036,  472, 1058,  450, 2034,  478, 1054,  472, 2008,  472};  // NIKAI D5F2A

/*天猫精灵电源原始数据*/
uint16_t timo_power[67] = {9010, 4476,  580, 552,  580, 554,  578, 550,  578, 552,  582, 552,  578, 554,  572, 558,  578, 552,  582, 1656,  582, 1656,  582, 1654,  580, 1658,  580, 1658,  580, 554,  578, 552,  578, 1660,  580, 1658,  580, 1656,  580, 1658,  584, 552,  578, 1658,  582, 552,  578, 1656,  582, 554,  576, 554,  580, 552,  578, 554,  580, 1658,  580, 552,  554, 1682,  582, 552,  580, 1658,  560};  // NEC F9EA15


// 新建Blinker组件对象(app上的按键)
BlinkerButton Button3("btn-pwr2");
BlinkerButton Button4("btn-pwr3");
//天猫精灵插座的状态
bool oState = false;

//天猫精灵电源的状态
void aligeniePowerState(const String & state)
{
    BLINKER_LOG("need set power state: ", state);

    if (state == BLINKER_CMD_ON) {
        digitalWrite(LED_BUILTIN, HIGH);

        BlinkerAliGenie.powerState("off");
        BlinkerAliGenie.print();
        //打开电视和天猫魔盒
        irsend.sendRaw(tv_power, 207, 38);  // Send a raw data capture at 38kHz.
        Button3.print("电视机打开");
        irsend.sendRaw(timo_power, 67, 38);  // Send a raw data capture at 38kHz.
        Button4.print("天猫魔盒打开");
        oState = true;
    }
    else if (state == BLINKER_CMD_OFF) {
        digitalWrite(LED_BUILTIN, LOW);

        BlinkerAliGenie.powerState("on");
        BlinkerAliGenie.print();
        
        //关闭电视和天猫魔盒
        irsend.sendRaw(tv_power, 207, 38);  // Send a raw data capture at 38kHz.
        Button3.print("电视机关闭");
        irsend.sendRaw(timo_power, 67, 38);  // Send a raw data capture at 38kHz.
        Button4.print("天猫魔盒关闭");
        oState = false;
    }
}
//天猫精灵状态查询
void aligenieQuery(int32_t queryCode)
{
    BLINKER_LOG("AliGenie Query codes: ", queryCode);

    switch (queryCode)
    {
        case BLINKER_CMD_QUERY_ALL_NUMBER :
            BLINKER_LOG("AliGenie Query All");
            BlinkerAliGenie.powerState(oState ? "on" : "off");
            BlinkerAliGenie.print();
            break;
        case BLINKER_CMD_QUERY_POWERSTATE_NUMBER :
            BLINKER_LOG("AliGenie Query Power State");
            BlinkerAliGenie.powerState(oState ? "on" : "off");
            BlinkerAliGenie.print();
            break;
        default :
            BlinkerAliGenie.powerState(oState ? "on" : "off");
            BlinkerAliGenie.print();
            break;
    }
}

void dataRead(const String & data)
{
    BLINKER_LOG("Blinker readString: ", data);

    Blinker.vibrate();

    uint32_t BlinkerTime = millis();
    Blinker.print(BlinkerTime);
    Blinker.print("millis", BlinkerTime);
}

void setup()
{
    Serial.begin(115200);

    #if defined(BLINKER_PRINT)
        BLINKER_DEBUG.stream(BLINKER_PRINT);
    #endif

    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);

    Blinker.begin(auth, ssid, pswd);
    Blinker.attachData(dataRead);
    //注册回调函数/
    Button3.attach(Button3_callback);
    Button4.attach(Button4_callback);

    //红外初始化
    irsend.begin();
    
    BlinkerAliGenie.attachPowerState(aligeniePowerState);
    BlinkerAliGenie.attachQuery(aligenieQuery);
    //注册心跳包
    Blinker.attachHeartbeat(heartbeat);
}

void loop()
{
    Blinker.run();
}

//心跳包回调函数
void heartbeat()
{
  if (oState){
      Button3.print("on");
   } 
  else {
    BUILTIN_SWITCH.print("off");
  }
}

//回调函数
void Button3_callback(const String &state)
{
  BLINKER_LOG("get button state: ", state);
  //检测到btn-pwroff按钮按下
  if (state == BLINKER_CMD_BUTTON_TAP)
  {
   
    Button2.print("电视机电源按下");
     //串口打印
    BLINKER_LOG("电视机电源", "按下");
    //打开
    irsend.sendRaw(tv_power, 207, 38);  // Send a raw data capture at 38kHz.
  }

}
//回调函数
void Button4_callback(const String &state)
{
  BLINKER_LOG("get button state: ", state);
  //检测到btn-pwroff按钮按下
  if (state == BLINKER_CMD_BUTTON_TAP)
  {
   
    Button2.print("天猫魔盒按下");
     //串口打印
    BLINKER_LOG("天猫魔盒电源", "按下");
     //打开
    irsend.sendRaw(timo_power, 67, 38);  // Send a raw data capture at 38kHz.
  }

}

注意事项

1.设备密钥和wifi账号密码换成自己的
在这里插入图片描述
2.把读取的红外键值的rowDate数组换成自己需要控制的红外键值数组(数组名称可以随意,注意发送时的数据长度,这里是199)。
3.使用函数 irsend.sendRaw(power_off, 199, 38); 进行红外命令的发送,表示以38kHz的频率,发送power_off数组。数组长度为199.

4.3 上传程序到ESP8266

在这里插入图片描述
程序上传成功之后,复位Node MCU之后就可以开始使用Blinker App进行操作啦。(注意连接好红外发射的模块,引脚为GPIO4(D2))。

5.App控制

这个例程主要还是验证天猫精灵的控制方式,这里也简单说一个app的控制方式

  • 打开 Blinker App
    如果程序中设备密钥,以及Wifi账户密码无误的话,此时可以在app中看到设备的状态是在线的。
    在这里插入图片描述
    在这里插入图片描述
  • 操作设备
    点击电视开关按钮:如果有回调信息,说明红外命令成功发出,可以看到电视开启/关闭。
    在这里插入图片描述
    通过这个app即可实现电视的控制,当时这个不是最终的目的,还需要把它接入天猫精灵呢。

6.天猫精灵控制

在这里插入图片描述
步骤详情
在这里插入图片描述
返回设备界面之后,就可以看到已经绑定的Blinker设备啦。
在这里插入图片描述
此时,如果你的天猫精灵正常联网,对着天猫精灵说:

我: 天猫精灵,打开客厅的插座。 天猫精灵: 插座已打开,注意操作哦
我:天猫精灵,关闭客厅的插座。天猫精灵:已为您关闭客厅的插座。

咦,但是我们控制的电视机啊,叫插座好像有点low吧。好吧,在天猫精灵app中可以对设备进行别名操作,当我们呼叫天猫精灵的别名时也可以对设备进行操作。
我把这个设备重命名为 电视机(我也想命名为“电视”,但是提示这个别名已经存在,应该是官方的限制吧或者是一个bug)

  • 别名修改
    在这里插入图片描述
    修改别名了之后,就可以对天猫精灵说:天猫精灵,打开电视机,此时,天猫精灵就会帮你打开电视机啦。

总结

到这里这个例程就结束了,其实这个只是做一个抛砖引玉的作用,通过小小的例子,就可以扩展出很多东西,比如空调的控制,或任何需要红外控制的地方。因为IRremoteESP8266红外解码的示例可以支持解析很多种红外协议,有了这个实例,我们并不需要去关心不同红外信号的协议,只需要读取红外键值的原生数据,然后把相同的红外数据发出即可。

2015-02-11 13:39:00 weixin_30588827 阅读数 37
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    702 人正在学习 去看看 陈贤能

 

1、先来段视频看看效果

 

 

 

 

2、基本原理

(1)几个控制器通过wifi连接到AP上,组成局域网。

(2)控制器基于arduion,使用了串口转wifi模块,它在控制器上建立了一个TCP服务器。控制端通过调用TCP服务来达到控制的目的。

  下面分别介绍各个控制器。

 

3、电灯控制器

1)硬件构成

 arduino模块+wifi模块+继电器模块。

 

继电器模块的AC端接到零线开关上。

 

2Arduino代码

void setup()
{
    Serial.begin(115200);
    pinMode(2,OUTPUT);
    digitalWrite(2, HIGH);   // switch off
}

void loop()
{
    // delay(500);
   if (Serial.available() > 0)
   {
       char val;
       val = Serial.read();     // read serial data
       if(val == '1')
       {
          digitalWrite(2, LOW);    // switch on
      } 
      else if(val == '0')
       {
          digitalWrite(2, HIGH);   // switch off 
      }
        Serial.print(val);  //将收到是数据再通过串口发送出去
       //delay(1000);
  }
 
}
View Code

3PC端代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net.Sockets;
using System.Diagnostics;
using System.Timers;
using System.Net;


namespace WiseHouse.SI
{
    public class LightController
    {

        // ***********************************************  全局字段 ******************************************************


        TcpClient tcp = new TcpClient();
        NetworkStream stream;


        System.Timers.Timer tmrConnecting = new System.Timers.Timer();    // 连线的周期。 若断线,在10秒后尝试建立连接 



        // ***********************************************  事件 ******************************************************


        // ***********************************************  属性 ******************************************************
        /// <summary>
        ///  IP地址
        /// </summary>
        public string IP
        {
            get
            {
                return _IP;
            }
            set
            {
            }

        }
        string _IP;



        /// <summary>
        /// 是否在线
        /// </summary>
        public bool IsOnline
        {
            get
            {
                return _IsOnline;
            }
            set
            {
            }
        }
        bool _IsOnline = false;




        /// <summary>
        /// 信号强度
        /// </summary>
        public int SignalStrength
        {
            get
            {
                return GetSignalStrength();
            }
            set
            {
            }
        }
        //  int _SignalStrength;


        // ***********************************************  构造函数 ******************************************************
        /// <summary>
        /// 以IP地址为参数实例化一个对象
        /// </summary>
        /// <param name="ip"></param>
        public LightController( string ip )
        {
            _IP = ip;

            // 计时器1
            tmrConnecting.Elapsed += new ElapsedEventHandler( tmrConnecting_Elapsed );
            tmrConnecting.Interval = 10000; // 每10秒种尝试连接一次 
            tmrConnecting.Enabled = true;

            // 首次连接
            Open();
        }



        // ***********************************************  公共方法 ******************************************************

        // 打开灯1
        public void TurnOnLight1()
        {
            try
            {
                if( tcp.Connected == true )
                {
                    // 发送
                    byte[] command = Encoding.ASCII.GetBytes( "1" );
                    stream.Write( command, 0, command.Length );      // 写入
                    System.Threading.Thread.Sleep( 100 ); // 
                    // 接收
                    int bufferSize = 30; // 13个,00.00;00.00   // 接收字节数组
                    byte[] buffer = new byte[ bufferSize ];
                    int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer
                    string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串
                    //  Console.WriteLine( data );
                }
                else
                {
                }
            }
            catch
            {
                Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
            }

        }



        /// <summary>
        /// 关闭灯1
        /// </summary>
        public void TurnOffLight1()
        {
            try
            {
                if( tcp.Connected == true )
                {
                    // 发送
                    byte[] command = Encoding.ASCII.GetBytes( "0" );
                    stream.Write( command, 0, command.Length );      // 写入
                    System.Threading.Thread.Sleep( 100 ); // 
                    // 接收
                    int bufferSize = 30; // 13个,00.00;00.00   // 接收字节数组
                    byte[] buffer = new byte[ bufferSize ];
                    int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer
                    string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串
                    //  Console.WriteLine( data );
                }
                else
                {
                }
            }
            catch
            {
                Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
            }

        }




        /// <summary>
        /// 释放资源
        /// </summary>
        public void Close()
        {
            stream.Close();
            tcp.Close();
        }



        // ***********************************************  私有方法 ******************************************************
        /// <summary>
        /// 定时进行连接。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void tmrConnecting_Elapsed( object sender, ElapsedEventArgs e )
        {
            Open();
        }


        /// <summary>
        /// 打开连接。
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        void Open()
        {
            try
            {
                if( tcp.Connected == false )  //若连线失败,则尝试进行连接
                {
                    // 若是连接断了,则先关闭当前的TCP client实例。然后再开启另一个TCP client实例
                    tcp.Close();
                    tcp = new TcpClientWithTimeout( _IP, 8000, 2000 ).Connect();
                    tcp.ReceiveTimeout = 1000;
                    tcp.SendTimeout = 1000; // timeout
                    stream = tcp.GetStream();

                    _IsOnline = true;

                    Console.WriteLine( _IP.PadRight( 20 ) + "灯连接成功!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
                }
            }
            catch
            {
                _IsOnline = false;
                Trace.WriteLine( _IP.PadRight( 20 ) + "灯连接失败!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
            }

        }






        /// <summary>
        /// 获得信号强度
        /// </summary>
        /// <returns></returns>
        int GetSignalStrength()
        {
            try
            {
                // 从页面中下载html文本
                WebClient client = new WebClient();
                client.Credentials = new NetworkCredential( "admin", "admin" ); // 认证
                string str1 = client.DownloadString( "http://" + _IP + "/station/link_status.asp" ); //?

                // 初次截取文本。
                int j1 = str1.IndexOf( "Link Quality" ) + 22;
                string str2 = str1.Substring( j1, 70 );  // 类似于:<td>Good&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;95%</td>\n    <td rowspan=\"4\"><

                // 再次截取文本。在str2的基础上截取
                int j2 = str2.LastIndexOf( ";" );   //信号值前的文本
                int j3 = str2.IndexOf( "%</td>" );  //信号值前的文本
                string str3 = str2.Substring( j2 + 1, j3 - j2 - 1 );  // 截取信号值。

                return int.Parse( str3 );
            }
            catch
            {
                return 0;  // 若读取失败,则返回 0
            }
        }


    }
}
View Code

 

 

4、空调控制器

1)硬件构成

arduino模块+wifi模块+红外LED灯管。

 

  我的空调是格力的,要控制空调首先需要捕获红外信号的原始码。关于如何捕获原始码,请参考本人的另一篇文章:http://www.cnblogs.com/dehai/p/3730156.html

2Arduino代码

 
#include <IRremote.h>

IRsend irsend; 
 
unsigned int open26[300] = {9040,4438,665,1643,701,508,697,508,698,1606,702,1606,696,1610,638,1670,638,571,697,508,696,1608,663,545,698,1606,700,509,698,508,700,506,698,507,701,505,696,509,698,507,696,509,665,541,699,1606,699,509,698,507,698,506,696,510,697,509,695,509,698,1606,664,545,697,1606,664,544,699,507,697,1608,667,542,697,19939,666,1643,699,508,698,508,698,507,698,1606,666,542,696,509,698,508,698,508,699,507,699,507,698,507,698,508,699,1606,699,509,699,507,698,507,700,506,697,508,698,508,696,509,697,508,698,507,698,507,699,507,697,509,700,506,698,507,699,506,696,509,697,508,696,510,698,39948,9041,4437,669,1640,664,543,696,509,698,1606,668,1639,666,1642,699,1607,701,507,698,508,698,1606,663,545,662,1642,701,507,697,509,699,507,699,507,697,507,697,508,696,510,698,508,696,510,699,1605,699,509,697,508,699,507,699,507,699,507,699,507,697,1608,665,1642,701,1605,701,507,700,506,698,1605,664,544,698,19938,700,507,698,507,697,509,698,508,697,508,699,507,698,507,697,509,697,509,698,507,697,508,698,508,699,506,699,507,696,510,695,510,698,507,697,508,696,509,697,508,699,1605,665,543,699,1605,667,543,699,506,698,507,699,507,698,507,698,507,696,1609,699,508,698,508,698};
unsigned int close27[279] = {9004,4499,699,1609,697,511,695,511,695,510,693,1611,697,1612,696,510,695,510,695,1610,696,1609,696,512,695,1609,696,512,695,511,695,511,694,512,694,511,695,510,694,512,694,512,694,511,695,1611,696,512,693,512,694,512,694,511,694,511,694,512,694,1611,696,512,694,1610,696,512,694,511,694,1609,698,510,694,19942,698,511,694,512,694,511,694,511,694,511,694,511,695,510,695,511,694,511,696,510,692,513,694,511,694,511,694,1611,696,511,693,512,694,511,693,512,694,512,695,511,694,512,694,511,694,511,695,511,694,511,694,512,695,511,694,511,693,512,694,511,695,511,695,1609,698,39952,9037,4443,698,1609,697,511,695,511,694,510,695,1610,696,1609,697,512,693,512,694,1610,698,1610,695,511,694,1611,696,512,695,511,694,512,694,512,692,512,694,511,695,511,694,512,695,511,695,1608,697,512,694,511,693,512,692,512,693,538,694,512,694,1610,697,1610,697,1612,697,511,694,511,694,1611,697,512,695,19941,698,511,694,511,693,512,693,512,695,511,693,512,696,510,694,511,695,511,695,510,695,511,693,512,694,511,695,511,694,511,694,511,694,512,693,512,694,511,693,512,694,1610,697,511,695,1610,695,513,694,511,693,512,694,511,693,512,693,1611,698,1610,697,511,695,1610,696};


void setup()
{
     Serial.begin(115200);
}
 
void loop()
{
   // irsend.sendRaw2(open26, 279, 38); 
  //delay(2000);
  if (Serial.available() > 0)
   {
       char val;
       val = Serial.read();     // read serial data
       if(val == '1')
       {
         irsend.sendRaw2(open26, 279, 38); 
       } 
       else if(val == '0')
       {
          irsend.sendRaw2(close27, 279, 38); 
       }
       Serial.print(val);  //将收到是数据再通过串口发送出去
       //delay(1000);
  }
  
}
View Code

3PC端代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net.Sockets;
using System.Diagnostics;
using System.Timers;
using System.Net;


namespace WiseHouse.SI
{
    public class AirConditioner
    {

        // ***********************************************  全局字段 ******************************************************


        TcpClient tcp = new TcpClient();
        NetworkStream stream;


        System.Timers.Timer tmrConnecting = new System.Timers.Timer();    // 连线的周期。 若断线,在10秒后尝试建立连接 



        // ***********************************************  事件 ******************************************************


        // ***********************************************  属性 ******************************************************
        /// <summary>
        ///  IP地址
        /// </summary>
        public string IP
        {
            get
            {
                return _IP;
            }
            set
            {
            }

        }
        string _IP;



        /// <summary>
        /// 是否在线
        /// </summary>
        public bool IsOnline
        {
            get
            {
                return _IsOnline;
            }
            set
            {
            }
        }
        bool _IsOnline = false;




        /// <summary>
        /// 信号强度
        /// </summary>
        public int SignalStrength
        {
            get
            {
                return GetSignalStrength();
            }
            set
            {
            }
        }
      //  int _SignalStrength;


        // ***********************************************  构造函数 ******************************************************
        /// <summary>
        /// 以IP地址为参数实例化一个对象
        /// </summary>
        /// <param name="ip"></param>
        public AirConditioner( string ip )
        {
            _IP = ip;

            // 计时器1
            tmrConnecting.Elapsed += new ElapsedEventHandler( tmrConnecting_Elapsed );
            tmrConnecting.Interval = 10000; // 每10秒种尝试连接一次 
            tmrConnecting.Enabled = true;

            // 首次连接
            Open();
        }



        // ***********************************************  公共方法 ******************************************************

        // 打开空调
        public void TurnOn()
        {
            try
            {
                if( tcp.Connected == true )
                {
                    // 发送
                    byte[] command = Encoding.ASCII.GetBytes( "1" ); 
                    stream.Write( command, 0, command.Length );      // 写入
                    System.Threading.Thread.Sleep( 100 ); // 
                    // 接收
                    int bufferSize = 30; // 13个,00.00;00.00   // 接收字节数组
                    byte[] buffer = new byte[ bufferSize ];
                    int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer
                    string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串
                    //  Console.WriteLine( data );
                }
                else
                {
                }
            }
            catch
            {
                Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
            }

        }



        /// <summary>
        /// 关闭空调
        /// </summary>
        public void TurnOff()
        {
            try
            {
                if( tcp.Connected == true )
                {
                    // 发送
                    byte[] command = Encoding.ASCII.GetBytes( "0" );
                    stream.Write( command, 0, command.Length );      // 写入
                    System.Threading.Thread.Sleep( 100 ); // 
                    // 接收
                    int bufferSize = 30; // 13个,00.00;00.00   // 接收字节数组
                    byte[] buffer = new byte[ bufferSize ];
                    int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer
                    string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串
                    //  Console.WriteLine( data );
                }
                else
                {
                }
            }
            catch
            {
                Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
            }

        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Close()
        {
            stream.Close();
            tcp.Close();
        }

       

        // ***********************************************  私有方法 ******************************************************
        /// <summary>
        /// 定时进行连接。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void tmrConnecting_Elapsed( object sender, ElapsedEventArgs e )
        {
            Open();
        }

        
        /// <summary>
        /// 打开连接。
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        void Open()
        {
            try
            {
                if( tcp.Connected == false )  //若连线失败,则尝试进行连接
                {
                    // 若是连接断了,则先关闭当前的TCP client实例。然后再开启另一个TCP client实例
                    tcp.Close();
                    tcp = new TcpClientWithTimeout( _IP, 8000, 2000 ).Connect();
                    tcp.ReceiveTimeout = 1000;
                    tcp.SendTimeout = 1000; // timeout
                    stream = tcp.GetStream();

                    _IsOnline = true;

                    Console.WriteLine( _IP.PadRight( 20 ) + "空调连接成功!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
                }
            }
            catch
            {
                _IsOnline = false;
                Trace.WriteLine( _IP.PadRight( 20 ) + "空调连接失败!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
            }

        }






        /// <summary>
        /// 获得信号强度
        /// </summary>
        /// <returns></returns>
        int GetSignalStrength()
        {
            try
            {
                // 从页面中下载html文本
                WebClient client = new WebClient();
                client.Credentials = new NetworkCredential( "admin", "admin" ); // 认证
                string str1 = client.DownloadString( "http://" + _IP + "/station/link_status.asp" ); //?

                // 初次截取文本。
                int j1 = str1.IndexOf( "Link Quality" ) + 22;
                string str2 = str1.Substring( j1, 70 );  // 类似于:<td>Good&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;95%</td>\n    <td rowspan=\"4\"><

                // 再次截取文本。在str2的基础上截取
                int j2 = str2.LastIndexOf( ";" );   //信号值前的文本
                int j3 = str2.IndexOf( "%</td>" );  //信号值前的文本
                string str3 = str2.Substring( j2 + 1, j3 - j2 - 1 );  // 截取信号值。

                return int.Parse( str3 );
            }
            catch
            {
                return 0;  // 若读取失败,则返回 0
            }
        }






    }
}
View Code

 

 

5、房门控制器

1)硬件构成

 arduino模块+wifi模块+场效管模块+自制的稳压模块。

 

   我的锁是电控锁,它里面有一个线圈,当线圈通电后,它中间的钢芯被磁化,吸位锁的卡扣,门就开了。由于线圈在通电时的瞬间电流较大,为避免它对电路的其它部分造成干扰(可能会造成控制器死机),加上一个自制的稳压模块。稳压模块由一些电感和电容组成。

2Arduino代码

void setup()
{
    Serial.begin(115200);
    pinMode(2,OUTPUT);
    digitalWrite(2, LOW);   // switch off
}

void loop()
{
    // delay(500);
   if (Serial.available() > 0)
   {
       char val;
       val = Serial.read();     // read serial data
       if(val == '1')
       {
        //  digitalWrite(2, LOW);    // switch on
         // delay(1000);
          digitalWrite(2, HIGH); // switch off 
      } 
      else if(val == '0')
       {
          digitalWrite(2, LOW);   // switch off 
      }
        Serial.print(val);  //将收到是数据再通过串口发送出去
       //delay(1000);
  }
 
}
View Code

3PC端代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Net.Sockets;
using System.Diagnostics;
using System.Timers;
using System.Net;


namespace WiseHouse.SI
{
    public class DoorController
    {

        // ***********************************************  全局字段 ******************************************************


        TcpClient tcp = new TcpClient();
        NetworkStream stream;


        System.Timers.Timer tmrConnecting = new System.Timers.Timer();    // 连线的周期。 若断线,在10秒后尝试建立连接 



        // ***********************************************  事件 ******************************************************


        // ***********************************************  属性 ******************************************************
        /// <summary>
        ///  IP地址
        /// </summary>
        public string IP
        {
            get
            {
                return _IP;
            }
            set
            {
            }

        }
        string _IP;



        /// <summary>
        /// 是否在线
        /// </summary>
        public bool IsOnline
        {
            get
            {
                return _IsOnline;
            }
            set
            {
            }
        }
        bool _IsOnline = false;




        /// <summary>
        /// 信号强度
        /// </summary>
        public int SignalStrength
        {
            get
            {
                return GetSignalStrength();
            }
            set
            {
            }
        }
        //  int _SignalStrength;


        // ***********************************************  构造函数 ******************************************************
        /// <summary>
        /// 以IP地址为参数实例化一个对象
        /// </summary>
        /// <param name="ip"></param>
        public DoorController( string ip )
        {
            _IP = ip;

            // 计时器1
            tmrConnecting.Elapsed += new ElapsedEventHandler( tmrConnecting_Elapsed );
            tmrConnecting.Interval = 10000; // 每10秒种尝试连接一次 
            tmrConnecting.Enabled = true;

            // 首次连接
            Open();
        }






        // ***********************************************  公共方法 ******************************************************

        // 打1号门
        public void OpenDoor1()
        {
            try
            {
                if( tcp.Connected == true )
                {
                    // 发送
                    byte[] command = Encoding.ASCII.GetBytes( "1" );
                    stream.Write( command, 0, command.Length );      // 写入
                    //  System.Threading.Thread.Sleep( 100 ); // 
                    // 接收
                    //  int bufferSize = 30; // 13个,00.00;00.00   // 接收字节数组
                    // byte[] buffer = new byte[ bufferSize ];
                    //  int bytesRead = stream.Read( buffer, 0, bufferSize ); //将值放入buffer
                    // string data = Encoding.ASCII.GetString( buffer ); // 将字节转换成字符串
                    //  Console.WriteLine( data );
                }
                else
                {
                }
            }
            catch
            {
                Trace.WriteLine( _IP.PadRight( 20 ) + "发送指令失败" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
            }

        }


        ///// <summary>
        ///// 释放资源
        ///// </summary>
        //public void  Close() 
        //{
        //    //stream.Close();
        //   // tcp.Close();
        //}






        // ***********************************************  私有方法 ******************************************************
        /// <summary>
        /// 定时进行连接。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void tmrConnecting_Elapsed( object sender, ElapsedEventArgs e )
        {
            Open();
        }


        /// <summary>
        /// 打开连接。
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        void Open()
        {
            try
            {
                if( tcp.Connected == false )  //若连线失败,则尝试进行连接
                {
                    // 若是连接断了,则先关闭当前的TCP client实例。然后再开启另一个TCP client实例
                    tcp.Close();
                    tcp = new TcpClientWithTimeout( _IP, 8000, 2000 ).Connect();
                    tcp.ReceiveTimeout = 1000;
                    tcp.SendTimeout = 1000; // timeout
                    stream = tcp.GetStream();

                    _IsOnline = true;

                    Console.WriteLine( _IP.PadRight( 20 ) + "门连接成功!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
                }
            }
            catch
            {
                _IsOnline = false;
                Trace.WriteLine( _IP.PadRight( 20 ) + "门连接失败!" + DateTime.Now.ToString( "yyyy-MM-dd hh:mm:ss" ) );
            }

        }






        /// <summary>
        /// 获得信号强度
        /// </summary>
        /// <returns></returns>
        int GetSignalStrength()
        {
            try
            {
                // 从页面中下载html文本
                WebClient client = new WebClient();
                client.Credentials = new NetworkCredential( "admin", "admin" ); // 认证
                string str1 = client.DownloadString( "http://" + _IP + "/station/link_status.asp" ); //?

                // 初次截取文本。
                int j1 = str1.IndexOf( "Link Quality" ) + 22;
                string str2 = str1.Substring( j1, 70 );  // 类似于:<td>Good&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;95%</td>\n    <td rowspan=\"4\"><

                // 再次截取文本。在str2的基础上截取
                int j2 = str2.LastIndexOf( ";" );   //信号值前的文本
                int j3 = str2.IndexOf( "%</td>" );  //信号值前的文本
                string str3 = str2.Substring( j2 + 1, j3 - j2 - 1 );  // 截取信号值。

                return int.Parse( str3 );
            }
            catch
            {
                return 0;  // 若读取失败,则返回 0
            }
        }






    }
}
View Code

 

6、控制端

     使用了微软的语音识别和合成库,命名空间是System.Speech.Recognition和 System.Speech.Synthesis

    核心代码:

 public partial class Frm控制台 : Form
    {


        // *********************************************  全局变量  **********************************************************************   
        SpeechRecognitionEngine _recognizer = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("zh-CN")); // 语音识别引擎
        SpeechSynthesizer speech = new SpeechSynthesizer();  // 语音合成器。默认使用女声Lily。

        AirConditioner airConditioner;  // 空调控制器
        LightController lightController;  // 电灯控制器
        DoorController doorController; // 门禁控制器

        bool IsStandingBy = false;   // 是否进入待命模式

        System.Threading.Timer tmrCurrent;   // 当前的
        System.Threading.Timer tmrPrevious;  // 之前的



        public Frm控制台()
        {
            InitializeComponent();
        }





        private void Frm控制台_Load(object sender, EventArgs e)
        {
            // 控制器初始化
            airConditioner = new AirConditioner("172.16.1.12");
            lightController = new LightController("172.16.1.13");
            doorController = new DoorController("172.16.1.14");

            // 添加语法
            GrammarBuilder gb1 = new GrammarBuilder(new Choices("小黑", "取消"));
            GrammarBuilder gb2 = new GrammarBuilder(new Choices("打开电灯", "关闭电灯"));
            GrammarBuilder gb3 = new GrammarBuilder(new Choices("打开空调", "关闭空调", "18度"));
            GrammarBuilder gb4 = new GrammarBuilder(new Choices("打开房门"));

            // 加载语法
            _recognizer.LoadGrammar(new Grammar(gb1));
            _recognizer.LoadGrammar(new Grammar(gb2));
            _recognizer.LoadGrammar(new Grammar(gb3));
            _recognizer.LoadGrammar(new Grammar(gb4));
            // 绑定事件
            _recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(_recognizer_SpeechRecognized);

            _recognizer.SpeechRecognitionRejected += new EventHandler<SpeechRecognitionRejectedEventArgs>(_recognizer_SpeechRecognitionRejected);

            _recognizer.SetInputToDefaultAudioDevice();   // 设置语音输入设备
            _recognizer.RecognizeAsync(RecognizeMode.Multiple); // 开启异步语音识别
      

        }







        /// <summary>
        /// 语音识别后的处理函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            // 关闭识别,防止speech说出来的话被误识别
            _recognizer.RecognizeAsyncStop();
            Thread.Sleep(30);

            if (e.Result.Confidence > 0.95)
            {
                Console.WriteLine(e.Result.Text);

                if (e.Result.Text == "计算机" || e.Result.Text == "小黑")
                {
                    speech.Speak("");
                    // 进入待命模式
                    IsStandingBy = true;  
                    Console.WriteLine("进入待命模式");
                    // 重新计时,10秒命令超时。
                    tmrPrevious = tmrCurrent;
                    tmrCurrent = new System.Threading.Timer(new TimerCallback(TimerCall), this, 10000, 0);  // 当前的,新的
                    if (tmrPrevious != null) // 取消前一个tmr.
                    {
                        tmrPrevious.Dispose();  
                    }
                }

                // 待命模式下的处理 
                if (IsStandingBy == true && e.Result.Text != "小黑")
                {
                    if (e.Result.Text == "打开电灯")
                    {
                        lightController.TurnOnLight1();
                        speech.Speak("灯成功打开");
                    }
                    else if (e.Result.Text == "关闭电灯")
                    {
                        lightController.TurnOffLight1();
                        speech.Speak("灯成功关闭");
                    }
                    else if (e.Result.Text == "打开空调")
                    {
                        airConditioner.TurnOn();
                        speech.Speak("空调成功打开");
                    }
                    else if (e.Result.Text == "关闭空调")
                    {
                        airConditioner.TurnOff();
                        speech.Speak("空调成功关闭");
                    }
                    else if (e.Result.Text == "18度")
                    {
                        speech.Speak("操作成功");
                    }
                    else if (e.Result.Text == "打开房门")
                    {
                        doorController.OpenDoor1();
                        speech.Speak("门成功打开");
                    }
                    else if (e.Result.Text == "取消")
                    {
                        speech.Speak("指令取消");
                    }
                    IsStandingBy = false; // 退出待命模式
                    tmrCurrent.Dispose();
                }
            }

            _recognizer.RecognizeAsync(RecognizeMode.Multiple); // 开启识别
        }


        void _recognizer_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            _recognizer.RecognizeAsyncStop();
            Thread.Sleep(30);
            speech.Speak("请再说一遍");
            _recognizer.RecognizeAsync(RecognizeMode.Multiple); // 开启识别
        }



        void TimerCall(object sender)
        {
            IsStandingBy = false;
            Console.WriteLine("退出待命模式");
            MediaHelper.Beep(); //蜂鸣声
        }



    }
View Code

 

转载于:https://www.cnblogs.com/dehai/p/4285749.html

没有更多推荐了,返回首页