『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 26512|回复: 20

[进阶教程] HA反向控制米家思考_______esp8266控制小米无线开关

[复制链接]

2

主题

7

帖子

150

积分

注册会员

Rank: 2

积分
150
金钱
143
HASS币
0
发表于 2020-10-11 13:46:20 | 显示全部楼层 |阅读模式
本帖最后由 xiaolong123 于 2020-10-12 17:09 编辑

需要具备一定的基础,至少要配置了mqtt服务器.要用arduino软件编译,修改地址等.
==================
1.主要是homeassistant可以直接快速触发米家自动化操作.比如离家模式,回家模式等等.
因灯光都是蓝牙mesh,无法接入homeassistant.

----------------------------------------------------
2.实现方法:esp8266与小米无线开关共用电源,然后按键检测引脚接上拉的引脚.我暂时使用的是nodemcu板子,按键接的jpio2.这个引脚带了上拉电阻.
----------------------------------------------------
  如图

1

1
IMG_4365.JPG

```
#include <Regexp.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ArduinoJson.h>
#include <RemoteDebug.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>

#define SWITCH_OFF 0
#define SWITCH_ON 1

const char* ssid = "xxxxxxx";          //Wi-Fi热点
const char* password = "xxxxxxxx";  //Wi-Fi密码
const char* mqtt_server = "192.168.xxxx.xxx";    //服务器网址或者IP地址

const char* TOPIC_CONFIG =  "ESP-01/switch/config";                    
const char* TOPIC_COMMAND = "ESP-01/switch/set";                    
const char* TOPIC_STATE =   "ESP-01/switch/state";

const char* client_id = "client-001";     // 标识当前设备的客户端编号
const char* device_name = "esp_01_2_switch_1";

const char* mqtt_user = "homeassistant";
const char* mqtt_password = "home";

WiFiClient espClient;
PubSubClient client(espClient);

const int PIN_SWITCH = 2;
const int PIN_BUTTON = 0;

long last_msg = 0;
char msg[64];

int switch_value = SWITCH_OFF;
String set_str = "";

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
  pinMode(PIN_SWITCH, OUTPUT);
  digitalWrite(PIN_SWITCH, SWITCH_ON);
  pinMode(PIN_BUTTON, INPUT);
}

void setup_wifi() {
  delay(100);
  WiFi.begin(ssid, password);           // 连接到WiFi网络
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
  }
  Serial.println("WiFi connected");
  // Print the IP address
  Serial.println(WiFi.localIP());
  Serial.println(WiFi.macAddress());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);   
  Serial.print("] ");

  set_str = "";
  for (int i = 0; i < length; i++) {
    set_str += (char)payload;
  }  

  String topic_str = topic;
  Serial.println(set_str);

  if (topic_str.equals(TOPIC_COMMAND)) {
    set_switch(set_str);
  }
}
void reconnect( ) {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi is not connected, retry setup");
    setup_wifi();
  }

  while (!client.connected()) {
    Serial.println("MQTT connecting...");
    if (client.connect(client_id, mqtt_user, mqtt_password)) {              
      Serial.println("MQTT connect success.");  
      mqtt_config();
      client.subscribe(TOPIC_COMMAND);      
    } else {
      delay(5000);  
    }
  }
}

void loop() {
  static bool  i=true;
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  long now = millis();
  if (now - last_msg > 5000) {
    last_msg = now;
    pub_mqtt_state();
  }

int buttonState = digitalRead(PIN_BUTTON);
  if (buttonState == LOW) {
    if(i)
      set_switch("ON");
     else
       set_switch("OFF");
     i=!i;
     delay(1000);  
  }
  delay(100);  
}

char* get_state(){
  if (switch_value == SWITCH_ON) {
    return "ON";
  } else {
    return "OFF";
  }
}

boolean set_switch(String set_str) {
  client.publish(TOPIC_STATE, set_str.c_str());
  Serial.print("Recv command:");
  Serial.println(set_str.c_str());
pub_mqtt_state();
if (set_str.equals("0OFF")){
    switch_value = SWITCH_OFF;
    digitalWrite(PIN_SWITCH, SWITCH_OFF);
    delay(20);
    digitalWrite(PIN_SWITCH, SWITCH_ON);
  } else if (set_str.equals("1OFF"))
  {
    digitalWrite(PIN_SWITCH, SWITCH_OFF);
    delay(1000);
    digitalWrite(PIN_SWITCH, SWITCH_ON);   
  }else if (set_str.equals("2OFF"))
  {
    digitalWrite(PIN_SWITCH, SWITCH_OFF);
    delay(20);
    digitalWrite(PIN_SWITCH, SWITCH_ON);
    delay(20);
    digitalWrite(PIN_SWITCH, SWITCH_OFF);
    delay(20);
    digitalWrite(PIN_SWITCH, SWITCH_ON);   
  }


  return true;
}

void pub_mqtt_state() {
//if(switch_value == SWITCH_ON){
    client.publish(TOPIC_STATE, "0ON");
    client.publish(TOPIC_STATE, "1ON");
    client.publish(TOPIC_STATE, "2ON");     
  //} else {
    //client.publish(TOPIC_STATE, "OFF");   
  //}  
}

void mqtt_config() {
  String head = "{";
  String name_str = "name: " + String(device_name) + ", ";
  String cmd_topic = "command_topic: " + String(TOPIC_COMMAND) + ", ";
  String state_topic = "state_topic: " + String(TOPIC_STATE) ;
  String end_str = "}";
  String config = "{" + name_str + ", " + state_topic + ", " + cmd_topic + "}";
  Serial.println(config.c_str());

  int msgLen = head.length() + name_str.length() + cmd_topic.length() + state_topic.length() + end_str.length();
  //发送长文本需要另外处理
  client.beginPublish(TOPIC_CONFIG, msgLen, false);
  client.print(head);
  client.print(name_str);
  client.print(cmd_topic);
  client.print(state_topic);
  client.print(end_str);
  client.endPublish();
}

```
configuration.yaml中添加
```
switch: !include switchs.yaml
```
homeassistant中单独用了一个文件switchs.yaml

```
- platform: mqtt
  name: "ESP-01 switch_one"
  state_topic: "ESP-01/switch/state"
  command_topic: "ESP-01/switch/set"
  payload_on: "0ON"
  payload_off: "0OFF"
  state_on: "0ON"
  state_off: "0OFF"
  optimistic: false
  qos: 0
  retain: true
- platform: mqtt
  name: "ESP-01 switch_long"
  state_topic: "ESP-01/switch/state"
  command_topic: "ESP-01/switch/set"
  payload_on: "1ON"
  payload_off: "1OFF"
  state_on: "1ON"
  state_off: "1OFF"
  optimistic: false
  qos: 0
  retain: true
- platform: mqtt
  name: "ESP-01 switch_two"
  state_topic: "ESP-01/switch/state"
  command_topic: "ESP-01/switch/set"
  payload_on: "2ON"
  payload_off: "2OFF"
  state_on: "2ON"
  state_off: "2OFF"
  optimistic: false
  qos: 0
  retain: true

```

3

3


homeassistant界面

回复

使用道具 举报

2

主题

237

帖子

2378

积分

金牌会员

Rank: 6Rank: 6

积分
2378
金钱
2141
HASS币
0
发表于 2020-10-11 13:50:47 | 显示全部楼层
没搞懂这个做吗用。这二个不是都 可接入HA吗,还搞到一起。
回复

使用道具 举报

2

主题

7

帖子

150

积分

注册会员

Rank: 2

积分
150
金钱
143
HASS币
0
 楼主| 发表于 2020-10-11 13:53:34 | 显示全部楼层
zhongjiafa 发表于 2020-10-11 13:50
没搞懂这个做吗用。这二个不是都 可接入HA吗,还搞到一起。

homeassistant没法完全控制米家设备,比如蓝牙mesh灯,小米蓝牙音箱接入也很麻烦.
回复

使用道具 举报

3

主题

321

帖子

2895

积分

论坛积极会员

积分
2895
金钱
2574
HASS币
10
发表于 2020-10-12 11:08:57 | 显示全部楼层
zhongjiafa 发表于 2020-10-11 13:50
没搞懂这个做吗用。这二个不是都 可接入HA吗,还搞到一起。

看了半天明白了,是想从HA反向控制米家的一些不能接入HA的设备
回复

使用道具 举报

0

主题

9

帖子

73

积分

注册会员

Rank: 2

积分
73
金钱
64
HASS币
0
发表于 2020-10-12 16:55:28 | 显示全部楼层
滿特別的想法,可以想辦法直接入更好。
回复

使用道具 举报

1

主题

115

帖子

1632

积分

金牌会员

Rank: 6Rank: 6

积分
1632
金钱
1517
HASS币
0
发表于 2020-10-14 19:31:45 | 显示全部楼层
学习新内容!!!!!!!!!!1
回复

使用道具 举报

105

主题

2954

帖子

1万

积分

超级版主

智能家居&单板滑雪痴迷爱好者

Rank: 8Rank: 8

积分
12103
金钱
9084
HASS币
460

教程狂人突出贡献

发表于 2020-10-14 21:35:18 | 显示全部楼层
本帖最后由 XCray 于 2020-10-14 22:16 编辑

楼主的思路实难苟同,效率成本都不好。

我之前用过两年多的一个方法,不需要硬件,而是让HA模拟无线开关的单击、双击动作,从而触发米家自动化。


实现也很简单,只需要修改xiaomi_aqara目录下的__init__.py文件、增加一个服务即可(services.yaml也可以一道修改,不是必须)。

具体可参考:
https://github.com/xcray/xiaomi_ ... b7978712c03cfaf1ed2

(后来错误的删除了一些内容,github不太会玩儿,不知道咋恢复,好在历史版本都有)
    def simulate_button_service(call):
        '''Service to simulate click/double_click of the wireless button'''
        device_id = call.data.get(ATTR_DEVICE_ID)
        gateway = call.data.get(ATTR_GW_MAC)
        simu_status = call.data.get('status')
        gateway.write_to_hub(device_id, status=simu_status)

    hass.services.register(
        DOMAIN, SERVICE_SIMULATE_BUTTON, simulate_button_service,
        schema=_add_gateway_to_schema(xiaomi, SERVICE_SCHEMA_SIMULATE_BUTTON))


回复

使用道具 举报

2

主题

7

帖子

150

积分

注册会员

Rank: 2

积分
150
金钱
143
HASS币
0
 楼主| 发表于 2020-10-15 15:35:39 | 显示全部楼层
XCray 发表于 2020-10-14 21:35
楼主的思路实难苟同,效率成本都不好。

我之前用过两年多的一个方法,不需要硬件,而是让HA模拟无线开关的 ...

版主好,我之前看了你一个帖子有提到这个模拟实现,但是我的网关是多模网关,这个目前可以通过其他方式接入的,好像小米没有原生的支持,我的理解是实现不了,现有突破方式有可能通过修改代码实现么???
回复

使用道具 举报

105

主题

2954

帖子

1万

积分

超级版主

智能家居&单板滑雪痴迷爱好者

Rank: 8Rank: 8

积分
12103
金钱
9084
HASS币
460

教程狂人突出贡献

发表于 2020-10-15 19:01:08 | 显示全部楼层
xiaolong123 发表于 2020-10-15 15:35
版主好,我之前看了你一个帖子有提到这个模拟实现,但是我的网关是多模网关,这个目前可以通过其他方式接 ...

哦,多模网关啊!我还真没用过多模网关。不过我猜测应该可以复制我的思路。

首先多模网关已经有了比较好的接入方法,也算是原生的了(通过mqtt)。注意不是homekit反向接入,那个接入方法仅仅是聊胜于无。

然后,只要能控制子设备(比如智能插座),应该就可以模拟无线开关动作。

我当初也是本着试一下反正不会死的态度,试出来的这个方法。
回复

使用道具 举报

2

主题

16

帖子

188

积分

论坛分享达人

积分
188
金钱
172
HASS币
0
发表于 2020-10-29 22:00:57 | 显示全部楼层
xiaolong123 发表于 2020-10-15 15:35
版主好,我之前看了你一个帖子有提到这个模拟实现,但是我的网关是多模网关,这个目前可以通过其他方式接 ...

多模网关可以使用xiaomi gateway 3介入HA,HACS商店里面有这个插件
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-11-26 22:51 , Processed in 0.123084 second(s), 35 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表