本帖最后由 jesson 于 2018-3-23 22:05 编辑
Esp8266与homeassistant 很早以前就有想法,可以遥控家里的各种电器,健康家里的环境。然而条件技术有限,没有再进行下去。偶然的机会看到了esp8266,这是个好东西,便宜又强大好还可以用arduino开发,真是我等业余爱好者的福音。然后又有home assistant这个集成环境,可以连接各种设备,作为人机界面接口并且这些又都是开源的。 要让esp8266与home assistant 合体需要一个中间桥梁,也是一个开源项目MQTT协议,实现这个协议的软件有很多,我选了mosquitto这个款软件。 我的思路是这样: Esp8266负责物理层控制硬件,例如灯或者实体开关。 Homeassistant负责显示状态或者远程控制硬件实体,如显示环境温度,控制灯。 Mosquito负责连接esp8266和homeassistant,是一个中间桥梁。 后面用hass 代替homeassistan。
后面我主要以esp8266开发为重点,假如hass和mqtt都配置好了,能正常运行了。 Esp8266推荐买nodemcu v3这款,尤其是开发初期直接一根usb线就可以下载程序了,免了很多没必要的硬件接线。 首先配置arduino使其能够兼容esp8266配置好了安装用到的两个库,一个是<PubSubClient.h>负责MQTT通讯,另一个<DHT.H>使用dht11温湿度传感器(选择安装) Pubsubclient.h 这个库有几个重要的函数先介绍一下 const char* mqtt_server = "192.168.1.4"; 连接一个mqtt服务器 PubSubClientclient(esp8266); 定义一个类 这是几个初始设置放到程序开头定义变量位置 client.connected() 判断是否连接到服务器 client.connect("ESP8266Client") 一个叫ESP8266Client的客户端连接mqtt服务器,没用密码。 client.publish("esp8266", "mqttconnected!"); 往服务器推送一个主题esp8266及内容 client.subscribe("light"); 订阅一个主题 这几个可以上面列出的顺序放到一起先判断是否连接到mqtt服务器,否就连接服务器成功发送一个连接成功的主题,然后订阅主题接受信息。 callback(char*intopic, byte* payload, unsigned int length) 接受订阅的主题内容的回调函数 这个函数有client.loop()调用,可以放到任意位置,这里可以写控制灯的程序 client.setServer(mqtt_server,1883); 设置mqtt 服务器 client.setCallback(callback); 设置回调函数名为callback 上面这两个放到setup()中执行一次就可以 client.loop(); 一直循环调用回调函数callback,放到loop()中 这就是这个库用到的几个函数更具体全面准确的介绍看官方文档。我也是折腾出来的 第二个是<ESP8266WiFi.h> 这个是esp8266的主要库,这是必须要包含的头文件 再说一说modemcu这个板子,要用gpio的序号,不要看D0D1这类的看图 例如想用D1这个引脚在程序中要用5,digitalRead(5),但是读取模拟量是用A0. 现在用一个例子来说明一下。 现在有一个灯,墙上有一个开关,开关控制灯亮灯灭。现在我们要改造一下,保留原来开关的功能,添加上hass控制并能显示灯的亮灭状态。 1 连接硬件 Esp8266 D1控制一个继电器模块,继电器一组常开触点控制灯的火线,原来的开关也要改掉接到esp8266D2上示意图如下 2 设置hass 添加一个light 灯是否在线 lighta onlineoffline 灯状态 lights ON OFF 灯开关 light ON OFF 这都是默认值可以修改。 3 编写代码,如下 #include<ESP8266WiFi.h> #include<PubSubClient.h> #defineLAMP5 5 #defineSW4 4 const char* mqtt_server = "192.168.1.1";//your mqtt server ip,you can use a domain const char* ssid = "hass"; //your wifi ssid const char* password = ""; // your wifi password long now; booleanlight_state, old_key; WiFiClientesp8266; PubSubClientclient(esp8266); voidreconnectwifi() { delay(10); Serial.print("\nConnecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nWiFi connected\nIPaddress: "); Serial.println(WiFi.localIP()); } voidreconnectmqtt() { while (!client.connected()) { Serial.print("Attempting MQTTconnection..."); if(client.connect("ESP8266Client")) { Serial.println("\nMQTTconnected"); // Once connected, publish anannouncement... client.publish("esp8266","MQTT connected!"); client.publish("lighta","online"); //availability client.subscribe("light"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 2seconds"); // Wait 5 seconds before retrying delay(2000); } } } voidcallback(char* intopic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(intopic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload); //debuginfo } if (!strcmp(intopic, "light")) { if ((char)payload[0] == 'O' &&(char)payload[1] == 'N') light_state =1; if ((char)payload[0] == 'O' &&(char)payload[1] == 'F') light_state =0; } /*if (!strcmp(intopic, "curtain")){ //another topic if ((char)payload[0] == 'O' &&(char)payload[1] == 'N') client.publish("curtains", "ON"); if ((char)payload[0] == 'O' &&(char)payload[1] == 'F') client.publish("curtains", "OFF"); }*/ } voidcontral_light() { if (digitalRead(SW4) != old_key) { delay(20); if (digitalRead(SW4) != old_key) { old_key = digitalRead(SW4); light_state = !light_state; } } } voidsetup() { old_key = digitalRead(SW4); Serial.begin(115200); delay(20); reconnectwifi(); pinMode(SW4, INPUT_PULLUP); //light button pinMode(LAMP5, OUTPUT); //LAMP client.setServer(mqtt_server, 1883); client.setCallback(callback); } voidloop() { if (WiFi.status() != WL_CONNECTED)reconnectwifi(); if (!client.connected()) reconnectmqtt(); client.loop();//callback(); if (millis() - now > 5000) { client.publish("lighta","online"); now = millis(); } contral_light(); if (light_state) { client.publish("lights","ON"); digitalWrite(LAMP5,HIGH); } else { client.publish("lights","OFF"); digitalWrite(LAMP5,LOW); } } 然后下载到esp8266,接好电路就可以了。 快去体验一把吧! arduino 文件下载
example1.zip
(1.17 KB, 下载次数: 80)
|