本片教程介绍了具体如何实现天猫精灵控制一个灯。
前提:
HASS平台
- 你已经搭建一个可以在公网IP访问到的HASS平台--- 我用的是租了阿里云服务器,买了个域名,ubuntu1604系统
- 你已经搭建一个可以在公网IP访问到的MQTT服务器----没有好的话也可以使用官方测试用的服务器凑合下
- 在HASS论坛注册一个账户和密码---- 一般人不给注册,你需要给管理员发送邮件证明你会基本的HASS搭建(这都不会玩个蛇)
天猫精灵
- 花60元在咸鱼买个二手的 天猫精灵-方糖 (官网89元新的)
- 下载天猫精灵手机APP,绑定自己的 天猫精灵-方糖
ESP8266模块
- 随便找个能够使用arduino ide 开发的ESP8266(这里使用的是 esp8266 d1 pro min 14元)
- 一个继电器,控制台灯开和关
一 HASS配置-发现灯设备
目的:告诉HASS平台,现在有一个新的设备---灯要被你控制管理
手动添加模式
0 打开配置文件手动配置HASS要连接的MQTT服务器
# configuration.yaml配置样例 mqtt: # MQTT Broker的IP地址或者域名,这里蹭的官网测试服务器 broker: broker.mqtt-dashboard.com # MQTT Broker的端口号,缺省为1883 port: 1883 #client_id: home-assistant-1 # 用户名 不用设置 #username: homeassistant # 密码 不用设置 #password: 123456
1 打开配置文件手动增加一个设备
platform: mqtt name: "Office Light RGB" 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
自动添加模式
0 HASS配置要连接的MQTT服务器
1 HASS配置文件中开启自动发现设备。
# configuration.yaml配置样例 mqtt: # MQTT Broker的IP地址或者域名 broker: broker.mqtt-dashboard.com # MQTT Broker的端口号,缺省为1883 port: 1883 #client_id: home-assistant-1 # 用户名 #username: homeassistant # 密码 #password: 123456 # 配置自动发现 discovery: true # 自动发现使用的主题位置前缀,缺省为homeassistant discovery_prefix: homeassistant
2 ESP8266 WIFI模块(灯)发送自己的配置信息给HASS的配置话题。
hass配置话题 位置
homeassistant/light/garden/config
garden可以随意换--设备ID
发送的配置信息
{"name": "RGBlight", "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平台上多了一个灯--RGBlight(其他两个设备忽略)
可以直接用HASS来控制灯
电脑HASS网页版
普通的灯点击是不会出现颜色版的
手机HASS app
编辑--添加设备--里面有个我们自定义的灯设备RGBlight--添加进来
短按开关,长按跳出颜色控制板块
下一步,接入天猫精灵,使用语音间接控制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为RGBlight的灯添加到天猫精灵设备管理中。
选择增加--真实设备
设置灯的信息
设备ID : 选择
设备类型:灯
设备名称:彩灯 (这地方随意取名,但是到天猫精灵手机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串口打印输出:
程序功能:
- 连接指定MQTT服务器
- 在hass约定好的配置话题上发送ESP8266自己的配置信息,从而HASS注册这个灯设备
- HASS注册设备后,将开灯关闭,颜色,亮度等控制信息发送到对应约定好的话题上,ESP8266wifi模块到对应话题取出命令,控制继电器开关台灯
未来扩展:
- 增加一键配网,可灵活修改WIFI信息
- 增加flash保存WIFI联网信息,断后电重新自动连接上次记录的WIFI信息
- 增加触摸开关,从而开关本身+HASS软件+天猫语音三者都能独立控制开关,同时彼此更新开关状态
- 完善电路,可控硅代替继电器,电路微薄化处理,做成玻璃面板,好看美观
目前bug
无法直接发送自身配置信息
if (! hass_config.publish("sssssssssss")) { // 这是个bug 应该发送的是 自身配置信息 但是 *char和string 在这个函数不兼容,就随便发送个 “ssssss“ ,可以正常收到
esp8266烧录代码
/*************************************************** ****************************************************/ #include <ESP8266WiFi.h> #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" /************************* WiFi Access Point *********************************/ #define WLAN_SSID "dongdong" #define WLAN_PASS "ldd123456" /************************* Adafruit.io Setup *********************************/ //#define AIO_SERVER "io.adafruit.com" #define AIO_SERVER "broker.mqtt-dashboard.com" #define AIO_SERVERPORT 1883 // use 8883 for SSL #define AIO_USERNAME "" #define AIO_KEY "" int Light_d1 = D4; /************ Global State (you don't need to change this!) ******************/ // 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); /****************************** Feeds ***************************************/ // 发布自己的配置信息 Adafruit_MQTT_Publish hass_config = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "homeassistant/light/garden/config"); const char *my_config = "{\"name\":\"RGBlight\", \"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}" ; // 发布自己的开关信息 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); /*************************** Sketch Code ************************************/ 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(msg=="OFF") { Serial.println("light is close"); digitalWrite(Light_d1, LOW);} } void brightness_command_topic_call(double x) { Serial.print("Hey we're in a slider callback, the slider value is: "); Serial.println(x); } 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()); // 回掉函数 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); } } Serial.println("MQTT Connected!"); if (! hass_config.publish("sssssssssss")) { // 这是个bug 应该发送的是 自身配置信息 但是 *char和string 在这个函数不兼容 Serial.println(F("Failed")); } else { Serial.println(F("OK!")); } }