zoukankan      html  css  js  c++  java
  • (二 -3-1) 天猫精灵接入Home Assistant-自动发现Mqtt设备--灯系列 实战

    #本片教程介绍了具体如何实现天猫精灵控制一个灯。

    前提:

    HASS平台

    1. 你已经搭建一个可以在公网IP访问到的HASS平台--- 我用的是租了阿里云服务器,买了个域名,ubuntu1604系统
    2. 你已经搭建一个可以在公网IP访问到的MQTT服务器----没有好的话也可以使用官方测试用的服务器凑合下
    3. 在HASS论坛注册一个账户和密码---- 一般人不给注册,你需要给管理员发送邮件证明你会基本的HASS搭建(这都不会玩个蛇)

    天猫精灵

    1. 花60元在咸鱼买个二手的 天猫精灵-方糖  (官网89元新的)
    2. 下载天猫精灵手机APP,绑定自己的 天猫精灵-方糖

    ESP8266模块

    1. 随便找个能够使用arduino ide 开发的ESP8266(这里使用的是  esp8266 d1 pro min  14元)
    2. 一个继电器,控制台灯开和关

    运行服务器

    1. 远程登录阿里云服务器

    2 为了防止关闭远程访问,而导致正在运行的程序跟着关闭,开启一个screen背后运行

     首先查一下正在运行的screen

    screen -ls

     这里发现已经有一个背后运行的screen(里面是我之前开启的mqtt和hass程序)

    screen -r 1102   # 查询指定编号的screen里运行的程序  

    然后来到 编号为1102的screen下面

    • 如果想创建一个也可以
    • screen -r 1102
    • exit    
    • 执行完上面两句,代号1102的screen就被销毁了
    • screen -S hass_mqtt    #开启一个名字为hass_mqtt   的screen的背后运行
    •  所有在hass_mqtt   下面开启的程序不会随着远程访问断开而跟随关闭,会独立运行。

    3运行 mqtt 服务器

    上一步,我们已经来到 编号为1102的screen下面(或者你新建的screen下面)

    进入 emqtt 文件路径下

    cd Dongdong/emqttd
    

      

    命令行进入路径,开启mqtt服务

    ./bin/emqttd start
    

      

    •  ./bin/emqttd stop   关闭命令

    4 运行hass

    hass
    

      

    回车开始运行

    5 查看hass

    打开谷歌游览器

    输入   域名:8123

    密码

    看到自己的页面

    图中是我默认添加的两个测试设备

    一 HASS配置-发现灯设备

    目的:告诉HASS平台,现在有一个新的设备---灯要被你控制管理

    手动添加模式

    0 打开配置文件手动配置HASS要连接的MQTT服务器

    这里两个选择

    一 蹭一下别人的mqtt服务器

    二 直接在HASS的服务器上运行一个,这里我安装了EMQ版本的MQTT服务器,所以网址是本地的MQTT服务器  127.0.0.1:1883

    # configuration.yaml配置样例
    mqtt:
      # MQTT Broker的IP地址或者域名,这里蹭的官网测试服务器
      #broker: broker.mqtt-dashboard.com
    #我在hass同一个服务器上,开了一个MQTT服务器
    broker: 127.0.0.1
    # MQTT Broker的端口号,缺省为1883 port: 1883 #client_id: home-assistant-1 # 用户名 不用设置 #username: homeassistant # 密码 不用设置 #password: 123456

      

    1 打开配置文件手动增加一个设备

    platform: mqtt
        name: "light_on"
        state_topic: "hachina/rgb1/light/status"
        command_topic: "hachina/rgb1/light/switch"
        brightness_state_topic: "hachina/rgb1/brightness/status"
        brightness_command_topic: "hachina/rgb1/brightness/set"
        rgb_state_topic: "hachina/rgb1/rgb/status"
        rgb_command_topic: "hachina/rgb1/rgb/set"
        state_value_template: "{{ value_json.state }}"
        brightness_value_template: "{{ value_json.brightness }}"
        rgb_value_template: "{{ value_json.rgb | join(',') }}"
        qos: 0
        payload_on: "ON"
        payload_off: "OFF"
        optimistic: false
    

      手动添加的需要重启 hass服务。

    自动添加模式

    0 HASS配置要连接的MQTT服务器

    1 HASS配置文件中开启自动发现设备。

    # configuration.yaml配置样例
    mqtt:
      # MQTT Broker的IP地址或者域名,这里蹭的官网测试服务器
      #broker: broker.mqtt-dashboard.com
      #我在hass同一个服务器上,开了一个MQTT服务器
      broker: 127.0.0.1
      # MQTT Broker的端口号,缺省为1883
      port: 1883
      #client_id: home-assistant-1
      # 用户名 不用设置
      #username: homeassistant
      # 密码  不用设置
      #password: 123456
    

      

      

    2 ESP8266 WIFI模块(灯)发送自己的配置信息给HASS的配置话题。

    hass配置话题 位置

    homeassistant/light/garden/config
    

    garden可以随意换--设备ID

    发送的配置信息

    {"name": "light_on", "command_topic": "hachina/rgb1/light/switch", "state_topic": "hachina/rgb1/light/status","brightness_command_topic": "hachina/rgb1/brightness/set", "brightness_state_topic": "hachina/rgb1/brightness/status","rgb_command_topic": "hachina/rgb1/rgb/set","rgb_state_topic": "hachina/rgb1/rgb/status","state_value_template": "{{ value_json.state }}","brightness_value_template": "{{ value_json.brightness }}","rgb_value_template": "{{ value_json.rgb | join(',') }}","optimistic": false}
    

      

      

     然后可以看到 HASS平台上多了一个灯   light_on(其他两个设备忽略)

     light_on是我用esp8266自动注册的一个只有开关状态的灯

    TestLed2_light_MQTT是我手动在配置文件中添加的灯,具备开关  颜色 亮度

    上述两个灯除了名字不一样,其他接收开关的话题我设置成一摸一样。

    可以直接用HASS来控制灯

    手机HASS app

    编辑--添加设备--里面有个我们自定义的灯设备 light_on--添加进来

    短按开关,长按跳出颜色控制板块

    下一步,接入天猫精灵,使用语音间接控制HASS的设备(HASS自带语音识别和播放服务,也可使用)

    二 天猫精灵添加灯设备--将HASS上发现的灯设备添加到天猫精灵上,从而确保猫精间接通过HASS来控制灯

    疑问: 为何猫精不直接控制灯?

    世界灯种类千千万,鬼知道你这是什么灯,所以具体控制业务由专门开发智能家居的公司来搞,猫精只负责把语音控制解析信息给智能家居平台公司,由他们自己去控制自己平台下的灯。

    1 登陆hass论坛,注册账户和密码   

    https://bbs.hassbian.com

    2打开天猫精灵APP,在智能家居---绑定平台账号----绑定HASS账户和密码

      这样猫精就和HASS这个具体的智能家居公司对接起来了(然而HASS不是一个公司,是一个开源项目,申请成为开发合作者)

    3将HASS上已有的设备同步到天猫精灵手机APP-智能家居控制列表里,从而使得猫精间接通过HASS控制我们的灯

    具体过程:

    打开HASS论坛架设的配置网址

    https://bbs.hassbian.com/tmall/discovery.php

    输入自己的HASS地址和密码信息,进入自己的HASS设备管理

    将第一步HASS发现的ID为 light_on的灯添加到天猫精灵设备管理中。

    选择增加--真实设备

     

    设置灯的信息

    这里 天猫精灵看到hass上有三个设备

    只具备 开关 不具备颜色 亮度支持

    只具备 开关 不具备颜色 亮度支持

    具备 开关 颜色 亮度

     这里我们先添加个功能完全的

     

     完成后,多出一个彩灯设备

     

     打开天猫精灵APP,在智能家居中发现,多出一个彩灯设备(我已经在app里重新改名字,截图不是)

    为了提高语音识别准确度,我按照天猫精灵APP的设置重新取了名字 --- 卧室的灯。

    就这样,语音告诉猫精开灯,猫精解析语音后告诉HASS平台,去开哪盏灯。

    -------------------------------------------------------------------------

    hass是个智能家居管理平台,可以介入各种设备,具体怎么控制灯,这里需要借助MQTT通信协议和服务。

    MQTT服务典型: 我想和女朋友说“我爱你”,并不是我直接告诉她,而是我在 “love”这个话题下,发布了“我爱你”这个消息,她订阅“love”话题,这样每次从“love”这个话题下,接收到“我爱你”的消息

    这种服务好在哪: 凡是订阅这个话题的人,都能收到同样的消息,反之,也都可以往这个话题发消息。就像QQ和微信讨论组一样。

    -------------------------------------------------------------------------

    HASS接收到开哪个灯命令后,找到这个灯的信息,把开关,颜色,亮度控制命令通过MQTT放在指定话题上,等待灯来这个话题上取消息。

    这个灯如何取到消息?

    1能联网----这里选择ESP8266  wifi模块

    2能使用MQTT--  esp8266 在 aruino ide开发平台 下有现成的MQTT通信库。使用这个库可以很轻易从对应话题拿到想要的数据。

    3能当单片机控制-- ESP8266可以当一块单片机 开发,外接继电器可以控制220V的开和关。

    三 对接现实世界------ESP8266程序

     烧录时板型选择信息(根据自己使用的ESP866  wifi板类型)

    两种控制模式:

    1 使用HASS网页版或者手机APP直接控制

    开关

    亮度

    颜色

    2 天猫精灵语音控制hass,间接控制灯

    天猫精灵 打开卧室的的灯

    天猫精灵 关闭卧室的的灯

    天猫精灵 将卧室的的灯颜色调成红色

    天猫精灵 将卧室的的灯亮度调为60

    ESP8266串口打印输出:

     

    程序功能:

    1. 连接指定MQTT服务器
    2. 在hass约定好的配置话题上发送ESP8266自己的配置信息,从而HASS注册这个灯设备
    3. HASS注册设备后,将开灯关闭,颜色,亮度等控制信息发送到对应约定好的话题上,ESP8266wifi模块到对应话题取出命令,控制继电器开关台灯

    未来扩展:

    1. 增加一键配网,可灵活修改WIFI信息
    2. 增加flash保存WIFI联网信息,断后电重新自动连接上次记录的WIFI信息
    3. 增加触摸开关,从而开关本身+HASS软件+天猫语音三者都能独立控制开关,同时彼此更新开关状态
    4. 完善电路,可控硅代替继电器,电路微薄化处理,做成玻璃面板,好看美观

    目前bug

     由于ESP本身内存小,无法发送太多信息。只能发送简单的开关

    警告:

     自动发现设备的时候,一定要改配置话题第三个参数ID,

    • 跟换设备名没关系。设备名重复,ID不重复,可以添加。
    • ID重复,不管设备名重复不重复,只能有一个

    第一个设备 名字 RGBlight  ID garden   存在

    homeassistant/light/garden/config

    {"name": "RGBlight", "command_topic": "hachina/rgb1/light/switch",

    第二个设备 名字light   ID garden1   存在

    homeassistant/light/garden1/config

    {"name": "light", "command_topic": "hachina/rgb1/light/switch",

    第三个设备 名字light   ID garden2   存在

    homeassistant/light/garden2/config

    {"name": "light", "command_topic": "hachina/rgb1/light/switch",

    第四个设备 名字light   ID garden    不存在

    homeassistant/light/garden/config

    {"name": "light", "command_topic": "hachina/rgb1/light/switch",

    ID和第一个配置ID冲突,只能存在一个

    esp8266烧录代码

    /***************************************************
    
     ****************************************************/
    #include <ESP8266WiFi.h>
    #include "Adafruit_MQTT.h"
    #include "Adafruit_MQTT_Client.h"
    
    /*------------------------------------------------------------------------------------------- 
     * 配置WIFI信息
     *------------------------------------------------------------------------------------------*/
    
    #define WLAN_SSID       "dongdong"
    #define WLAN_PASS       "ldd123456"
    
    /*------------------------------------------------------------------------------------------- 
     * 配置MQTT服务器信息
     *------------------------------------------------------------------------------------------*/
    
    //#define AIO_SERVER      "io.adafruit.com"  // 不稳定
    //#define AIO_SERVER      "broker.mqtt-dashboard.com" // 稳定
    #define AIO_SERVER      "自己的mqtt服务器地址"
    #define AIO_SERVERPORT  1883                   // use 8883 for SSL
    #define AIO_USERNAME    ""
    #define AIO_KEY         ""
    
    /*------------------------------------------------------------------------------------------- 
     * 配置外接设备
     *------------------------------------------------------------------------------------------*/
    //  灯的接口  D4口-继电器
    int Light_d1 = D4; 
    
    
    /*------------------------------------------------------------------------------------------- 
     * 开启MQTT服务
     *------------------------------------------------------------------------------------------*/
    
    // Create an ESP8266 WiFiClient class to connect to the MQTT server.
    WiFiClient client;
    
    // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
    Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_USERNAME, AIO_KEY);
    
    /*------------------------------------------------------------------------------------------- 
    -由于MQTT发布信息有长度限制 130个左右,不能一次性发送太多自身配置信息,因此发杂的设备无法注册
    */
    
    // 发送自身配置信息  开关
    //  名字
    String name_s="light_on";
    // 接收开关命令话题
    String command_topic_s="hachina/rgb1/light/switch";
    // 自身开关状态发布话题
    String state_topic_s = "hachina/rgb1/light/status";
    // 接收亮度命令话题
    String brightness_command_topic_s="hachina/rgb1/brightness/set";
    // 自身亮度发布话题
    String brightness_state_topic_s="hachina/rgb1/brightness/status";
    // 接收颜色命令话题
    String rgb_command_topic_s="hachina/rgb1/rgb/set";
    // 自身颜色状态发布话题
    String rgb_state_topic_s="hachina/rgb1/rgb/status";
    // 话题可以性
    String optimistic_c="false";
    
    
    // 可用1  注册一个只有开关的灯  没有亮度和颜色
      String my_config_s=
      String("{"name":"")+  name_s 
     +String("","command_topic":"")+command_topic_s
     +String("","state_topic":"")+state_topic_s
    //+String("","brightness_command_topic":"")+brightness_command_topic_s
    //+String("","brightness_state_topic":"")+brightness_state_topic_s
    //+String("","rgb_command_topic_topic":"")+rgb_command_topic_s
    //+String("","rgb_state_topic":"")+rgb_state_topic_s
    +String("","optimistic":"")+optimistic_c
    +String(""}");
    
    String hass_config_s1="homeassistant/light/garden/config";
    
    // 发布自己的配置信息
    Adafruit_MQTT_Publish  hass_config = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "homeassistant/light/garden/config");
    
    // 发布自己的开关信息
    Adafruit_MQTT_Publish state_topic = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "hachina/rgb1/light/status");
    
    //发布自己的亮度信息
    Adafruit_MQTT_Publish brightness_state_topic = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "hachina/rgb1/brightness/status");
    
    //发布自己的颜色信息
    Adafruit_MQTT_Publish rgb_state_topic = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "hachina/rgb1/rgb/status");
    
    /*------------------------------------------------------------------------------------------- 
     * 功能:订阅开关信息
     * 输入:颜色数据
     * 输出:空
     *------------------------------------------------------------------------------------------*/
     
    //订阅开关命令
    Adafruit_MQTT_Subscribe command_topic = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "hachina/rgb1/light/switch", MQTT_QOS_1);
    //订阅亮度命令
    Adafruit_MQTT_Subscribe brightness_command_topic = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "hachina/rgb1/brightness/set", MQTT_QOS_1);
    //订阅颜色命令
    Adafruit_MQTT_Subscribe rgb_command_topic = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "hachina/rgb1/rgb/set", MQTT_QOS_1);
    
    /*************************** 接受信息订阅函数 ************************************/
    
    
    /*------------------------------------------------------------------------------------------- 
     * 功能:接收开关命令回掉函数
     *       on  开灯    off  关灯
     * 输入:接收数据+数据长度
     * 输出:空
     *------------------------------------------------------------------------------------------*/
    void command_topic_call(char *data, uint16_t len) {
      Serial.print("the button value is: ");
      Serial.println(data);
    
    
      String msg=String(data);
      
      if(msg=="ON") { Serial.println("light is open");
      digitalWrite(Light_d1, HIGH);
      
      if (! state_topic.publish("ON")) {
        Serial.println(F("state_topic.publish Failed"));
      } else {
        Serial.println(F("state_topic.publish ON!"));
      }
      
      }
      
      if(msg=="OFF") {  Serial.println("light is close");
      digitalWrite(Light_d1, LOW);
      
      if (! state_topic.publish("OFF")) {
        Serial.println(F("state_topic.publish Failed"));
      } else {
        Serial.println(F("state_topic.publish OFF!"));
      }
      
      }
    
      
    }
    /*------------------------------------------------------------------------------------------- 
     * 功能:接收亮度命令回掉函数
     *       向电脑打印输出亮度值   0-255
     * 输入:亮度数据
     * 输出:空
     *------------------------------------------------------------------------------------------*/
    void brightness_command_topic_call(double x) {
      Serial.print("Hey we're in a slider callback, the slider value is: ");
      Serial.println(x);
    
        if (! brightness_state_topic.publish(x)) {
        Serial.println(F("brightness_state_topic.publish Failed"));
      } else {
        Serial.print(F("brightness_state_topic.publish "));Serial.println(x);
      }
      
    }
    /*------------------------------------------------------------------------------------------- 
     * 功能:接收颜色命令回掉函数
     *       向电脑打印输出亮度值   255,255,255
     * 输入:颜色数据
     * 输出:空
     *------------------------------------------------------------------------------------------*/
    void rgb_command_topic_call(char *data, uint16_t len) {
      Serial.print("the button value is: ");
      Serial.println(data);
      
    
      
    }
    
    
    void setup() {
      
     pinMode(Light_d1, OUTPUT);
     digitalWrite(Light_d1, LOW);
       
      Serial.begin(115200);
      delay(10);
    
      Serial.println(F("Adafruit MQTT demo"));
    
      // Connect to WiFi access point.
      Serial.println(); Serial.println();
      Serial.print("Connecting to ");
      Serial.println(WLAN_SSID);
    
      WiFi.begin(WLAN_SSID, WLAN_PASS);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println();
    
      Serial.println("WiFi connected");
      Serial.println("IP address: "); Serial.println(WiFi.localIP());
    
    
    // 配置信息转换
    // strcpy( my_config_c, my_config.c_str()); 
     
    // 回掉函数
      command_topic.setCallback(command_topic_call);
      brightness_command_topic.setCallback(brightness_command_topic_call);
      rgb_command_topic.setCallback(rgb_command_topic_call);
     // 订阅话题注册
    
      mqtt.subscribe(&command_topic);
      mqtt.subscribe(&brightness_command_topic);
      mqtt.subscribe(&rgb_command_topic);
      
    
    
    
    }
    
    uint32_t x=0;
    
    void loop() {
    
      MQTT_connect();
    
    
    
      // this is our 'wait for incoming subscription packets and callback em' busy subloop
      // try to spend your time here:
      mqtt.processPackets(10000);
      
      // ping the server to keep the mqtt connection alive
      // NOT required if you are publishing once every KEEPALIVE seconds
      
      if(! mqtt.ping()) {
        mqtt.disconnect();
      }
    }
    
    // Function to connect and reconnect as necessary to the MQTT server.
    // Should be called in the loop function and it will take care if connecting.
    void MQTT_connect() {
      int8_t ret;
    
      // Stop if already connected.
      if (mqtt.connected()) {
        return;
      }
    
      Serial.print("Connecting to MQTT... ");
    
      uint8_t retries = 3;
      while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
           Serial.println(mqtt.connectErrorString(ret));
           Serial.println("Retrying MQTT connection in 3 seconds...");
           mqtt.disconnect();
           delay(3000);  // wait 10 seconds
           retries--;
           if (retries == 0) {
             // basically die and wait for WDT to reset me
             while (1);
    
             //  ESP.wdtFeed();
           }
      }
      Serial.println("MQTT Connected!");
      
      
     
        hass_config.publish(my_config_s.c_str());
       // 内存不够大 ,一直重启 只能注册个简单的有开关功能
        Serial.println(my_config_s);
     
    
      
    }
    

      

    程序烧录后,ESP一直触发看门狗重启,是MQTT库默认允许发送数据最大长度引起的.

    打开mqttq库文件源代码,修改。

    注意修改 esp8266  mqtt库允许发送最大的 数据长度(默认 150),修改为1024 

     然后还是没什用,报错 但是最大只能传送约 130个char

    这意味着通过MQTT自动配置,只能发送 开关的信息,颜色和亮度信息发送不了。需手动添加,后者使用手机MQTT调试助手发过去,长度最大限制1024。

  • 相关阅读:
    新院址运行统计
    游标使用之四
    游标使用之三
    css基础知识
    javascript基础知识
    [每日一题2020.06.20]BFS
    白嫖一个免费域名并解析到博客园
    [每日一题2020.06.19]leetcode #84 #121 单调栈
    操作系统---文件管理
    [每日一题2020.06.18]leetcode #3 hash_map实现滑动窗口
  • 原文地址:https://www.cnblogs.com/kekeoutlook/p/9484859.html
Copyright © 2011-2022 走看看