三洋速捷淨冷氣(美的貼牌機)室內機有提供冷氣控制接口,經由控制器可將冷氣接入 HA 遠端控制與同步狀態
一、通訊架構
Midea 冷氣 <–UART–> ESP開發板(ESPhome) <–WIFI–> Home Assistant
二、材料準備
- XH2.54 4P(公頭) 轉杜邦線 2.54mm 4P(母頭)
有現成的轉換線可買,也能買材料與工具自行製作(圖中線長為 30 CM)
- DT-06 開發板 + USB-TO-TTL 燒錄器 + 杜邦線4P
DT-06 簡要規格
晶片:ESP8285(相容 ESP8266), 晶片內建 1MB Flash
尺寸:34mm×17mm×4mm
供電電壓:4.5V~6.0V,TTL 電壓:3.3V(可相容 5.0V)
引出腳位:STATE,Txd、Rxd、EN
平均電流:80mA;WiFi 資料發送時 170mA;深度睡眠模式下 20μA
WiFi支援AP、STA、AP+STA三種模式
- ESPHome 韌體
air-conditioner.yaml
substitutions:
device_name: air-conditioner
friendly_name: "冷氣"
model_name: "SAE-V41HJ"
min_outdoor_temperature: "-20"
max_outdoor_temperature: "80"
packages:
base: !include base.yaml
board: !include board/doit_dt_06.yaml
esphome:
comment: SANLUX $model_name
climate:
- platform: midea
id: midea_climate
name: Climate
period: 1s
timeout: 2s
num_attempts: 3
autoconf: true
beeper: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step: 1 °C
supported_modes:
- FAN_ONLY
- HEAT_COOL
- COOL
- HEAT
- DRY
custom_fan_modes:
- SILENT
- TURBO
supported_presets:
- ECO
- BOOST
- SLEEP
supported_swing_modes:
- VERTICAL
- HORIZONTAL
- BOTH
outdoor_temperature:
name: "Outdoor Temperature"
filters:
- lambda: |-
if (!isnan(x) && x >= $min_outdoor_temperature && x <= $max_outdoor_temperature) {
return x;
}
return NAN;
sensor:
- platform: template
name: "Target Temperature"
device_class: "temperature"
state_class: "measurement"
unit_of_measurement: °C
icon: mdi:thermometer
lambda: |-
if (id(midea_climate).mode != CLIMATE_MODE_OFF) {
return id(midea_climate).target_temperature;
}
return NAN;
- platform: template
name: "Indoor Temperature"
device_class: "temperature"
state_class: "measurement"
unit_of_measurement: °C
icon: mdi:thermometer
lambda: return id(midea_climate).current_temperature;
switch:
- platform: template
name: Beeper
icon: mdi:volume-source
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
turn_on_action:
midea_ac.beeper_on:
turn_off_action:
midea_ac.beeper_off:
button:
- platform: template
name: Swing Step
icon: mdi:tailwind
on_press:
if:
condition:
lambda: return id(midea_climate).mode != CLIMATE_MODE_OFF;
then:
midea_ac.swing_step:
- platform: template
name: Dump Config
entity_category: diagnostic
on_press:
lambda: |-
id(midea_climate).dump_config();
doit_dt_06.yaml
# Chip is ESP8285N08
# Features: WiFi, Embedded Flash
# Crystal is 26MHz
# Detected flash size: 1MB
esp8266:
board: esp8285
light:
- platform: status_led
name: "Status LED"
id: board_blue_led
output: light_output
output:
- platform: gpio
id: light_output
pin:
number: GPIO4
inverted: True
# The following are specific settings for air conditioner
logger:
level: DEBUG
baud_rate: 0 # Disable output to avoid conflict with RX, TX
uart:
rx_pin: GPIO3
tx_pin: GPIO1
baud_rate: 9600
base.yaml
esphome:
name: $device_name
friendly_name: $friendly_name
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
fast_connect: true
ap:
ssid: "$friendly_name"
password: "12345678"
captive_portal:
ota:
- platform: esphome
api:
web_server:
version: 3
port: 80
time:
- platform: homeassistant
sensor:
- platform: wifi_signal
name: "WiFi Signal"
update_interval: 60s
- platform: uptime
name: Uptime
type: timestamp
text_sensor:
- platform: version
name: "ESPHome Version"
- platform: wifi_info
ip_address:
name: WiFi IP
ssid:
name: WiFi SSID
button:
- platform: restart
name: "Restart"
id: restart_btn
- platform: factory_reset
id: factory_reset_btn
name: "Factory Reset"
secrets.yaml
# Your Wi-Fi SSID and password
wifi_ssid: "WIFI_SSID"
wifi_password: "WIFI_PASSWORD"
三、控制器製作與加入 Home Assistant
- 連接 DT-06 開發板 + USB-TO-TTL 燒錄器 + 電腦
DT-06 <> 燒錄器
VCC <> 5V
GND <> GND
TXD <> RXD
RXD <> TXD
- 查詢 電腦 裝置管理員查詢燒錄器的通訊埠編號(COMx)
-
DT-06 開發板切換下載模式,按住 G 鍵(Boot) 不放,按一下 R 鍵(Reset) 放開,再將 G 鍵放開
-
使用 ESPHome CLI 進行韌體燒錄
esphome run air-conditioner.yaml --device COMx
-
DT-06 開發板切換一般模式,按一下 R 鍵(Reset) 放開
-
Home Assistant 加入冷氣控制器(預設名稱:冷氣)
-
DT-06 開發板移除連接線
四、冷氣安裝控制器
-
打開室內機機殼,轉開接收顯示基板外殼固定螺絲,將外殼住左移拆下
-
連接冷氣與控制器
(!!! +5V, GND 不可接錯,接錯設備會毀損 !!!)
冷氣 <> DT-06
GND <> GND
RX <> TX
TX <> RX
+5v <> VCC
-
在接收顯示基板外殼內找個地方將控制器用雙面膠固定
-
遠端測試冷氣控制
-
機板外殼、室內機機殼復歸
-
完成
備註
-
DT-06 的 flash 只有 1MB,有的 ESPHome 版本所編譯出的 OTA image 檔案,上傳會超出可用容量,若已加入 HA 可考慮將 web_server 與 captive_portal 移除
-
Midea 通訊協定的控制功能有限,部份冷氣控制功能(顯示螢幕開關、隨身感…)仍需透過紅外線指令擴充,可參考下一章節的紅外加強版
-
Midea Air Conditioner 還有些選項可啟用 power_usage, humidity_setpoint 但冷氣不一定配備相關元件
紅外加強版
Midea 通訊協定的控制功能有限,部份冷氣控制功能(顯示螢幕開關、隨身感…)仍需透過紅外線指令擴充,下面增加紅外線發射器與光敏電阻的加強版控制器(ESP32C3開發板 + 5v-3.3v 邏輯電平轉換模組)
這款冷氣螢幕夜間的燈光過亮,但由於沒有直接控制螢幕開啟或關閉的指令可用,因此加入光敏電阻來偵測螢幕亮度狀態,再依亮度狀態來用紅外指令控制螢幕燈光開關
硬體部份做法是在顯示器 WIFI 圖示上方鑽孔引光(直徑約 1.4 mm),光敏電阻(5mm)正對小孔測光,再包覆兩層黑色布膠帶,用在固定與排除其它光源干擾
PS. 螢幕叠上白紙也能降低亮度
air-conditioner-plus.yaml
substitutions:
device_name: air-conditioner-plus
friendly_name: "冷氣"
model_name: "SAE-V41HJ"
min_outdoor_temperature: "-20"
max_outdoor_temperature: "80"
follow_me_temperature_sensor: "sensor.temperature_humidity_sensor_67c2_temperature"
min_photoresistor_threshold: "0"
max_photoresistor_threshold: "1000000"
default_display_photoresistor_threshold: "14000"
packages:
base: !include base.yaml
board: !include board/xiao_esp32c3.yaml
esphome:
comment: SANLUX $model_name
remote_transmitter:
pin:
number: GPIO7
carrier_duty_percent: 50%
climate:
- platform: midea
id: midea_climate
name: Climate
period: 1s
timeout: 2s
num_attempts: 3
autoconf: true
beeper: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step: 1 °C
supported_modes:
- FAN_ONLY
- HEAT_COOL
- COOL
- HEAT
- DRY
custom_fan_modes:
- SILENT
- TURBO
supported_presets:
- ECO
- BOOST
- SLEEP
supported_swing_modes:
- VERTICAL
- HORIZONTAL
- BOTH
outdoor_temperature:
name: "Outdoor Temperature"
filters:
- lambda: |-
if (!isnan(x) && x >= $min_outdoor_temperature && x <= $max_outdoor_temperature) {
return x;
}
return NAN;
switch:
- platform: template
name: Beeper
icon: mdi:volume-source
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
turn_on_action:
midea_ac.beeper_on:
turn_off_action:
midea_ac.beeper_off:
- platform: template
name: "Display Switch"
id: display_switch
turn_on_action:
if:
condition:
and:
- lambda: return id(midea_climate).mode != CLIMATE_MODE_OFF;
- switch.is_off: display_switch
then:
midea_ac.display_toggle:
turn_off_action:
if:
condition:
and:
- lambda: return id(midea_climate).mode != CLIMATE_MODE_OFF;
- switch.is_on: display_switch
then:
midea_ac.display_toggle:
- platform: template
name: "Follow Me"
id: follow_me
optimistic: true
restore_mode: RESTORE_DEFAULT_OFF
# Supports cool, fan only, dry modes
- platform: template
name: "Prevent Direct Blowing"
id: prevent_direct_blowing
optimistic: true
assumed_state: true
turn_on_action:
if:
condition:
lambda: return id(midea_climate).mode != CLIMATE_MODE_OFF;
then:
- remote_transmitter.transmit_pronto:
data: "0000 0073 0000 0064 009e 009f 0012 003b 0012 0013 0012 003b 0012 003a 0013 003a 0013 0013 0012 0013 0012 003b 0012 0013 0013 003a 0012 0013 0013 0013 0012 0013 0012 003b 0012 003a 0013 0013 0012 003b 0012 003a 0013 003a 0012 003b 0012 0013 0013 003a 0012 0013 0013 003a 0012 0013 0013 0013 0012 0013 0013 0012 0013 003a 0013 0013 0012 003a 0013 0013 0012 0013 0013 003a 0012 0013 0013 003a 0012 003b 0012 0013 0012 003b 0012 003a 0013 003a 0013 0013 0012 003a 0013 0013 0012 0013 0013 003a 0012 0013 0013 0013 0012 00bb 009f 009f 0012 003a 0013 0013 0012 003a 0013 003a 0013 003a 0012 0013 0013 0013 0012 003a 0013 0013 0012 003a 0013 0013 0012 0013 0013 0013 0012 003a 0013 003a 0013 0012 0013 003a 0013 003a 0012 003b 0012 003a 0013 0013 0012 003a 0013 0013 0012 003b 0012 0013 0012 0013 0013 0013 0012 0013 0013 003a 0012 0013 0013 003a 0012 0013 0013 0013 0012 003a 0013 0013 0012 003b 0012 003a 0013 0013 0012 003a 0013 003a 0013 003a 0012 0013 0013 003a 0012 0013 0013 0013 0012 003a 0013 0013 0012 0013 0013 0e4a"
turn_off_action:
if:
condition:
lambda: return id(midea_climate).mode != CLIMATE_MODE_OFF;
then:
- remote_transmitter.transmit_pronto:
data: "0000 0073 0000 0064 00a1 009b 0015 0037 0014 0011 0015 0037 0015 0037 0014 0039 0014 0011 0014 0011 0015 0037 0015 0011 0014 0037 0015 0011 0014 0011 0014 0011 0015 0037 0014 0039 0014 0011 0015 0037 0014 0039 0014 0037 0015 0037 0014 0012 0013 0039 0014 0012 0014 0037 0014 0012 0013 0012 0014 0012 0014 0011 0014 0039 0013 0012 0014 0039 0013 0012 0014 0011 0014 0039 0015 0011 0014 0037 0015 0037 0014 0039 0013 0012 0014 0012 0014 0037 0015 0011 0013 0039 0015 0011 0013 0012 0015 0011 0014 0037 0015 0037 0013 00bb 00a0 009c 0014 0039 0014 0011 0014 0039 0014 0037 0015 0037 0014 0012 0014 0011 0014 0039 0014 0011 0014 0039 0014 0011 0014 0012 0013 0012 0013 003a 0013 0039 0014 0012 0013 003a 0013 0039 0014 0039 0013 003a 0014 0011 0014 0039 0013 0012 0014 0039 0013 0012 0014 0012 0013 0012 0014 0011 0014 0039 0014 0012 0013 0039 0014 0012 0013 0012 0013 003a 0013 0012 0014 0039 0013 003a 0013 0039 0014 0012 0013 0012 0014 0039 0013 0012 0014 0039 0013 0012 0014 0012 0013 0012 0014 0039 0013 003a 0013 0e4a"
sensor:
- platform: template
name: "Target Temperature"
device_class: "temperature"
state_class: "measurement"
unit_of_measurement: °C
icon: mdi:thermometer
lambda: |-
if (id(midea_climate).mode != CLIMATE_MODE_OFF) {
return id(midea_climate).target_temperature;
}
return NAN;
- platform: template
name: "Indoor Temperature"
device_class: "temperature"
state_class: "measurement"
unit_of_measurement: °C
icon: mdi:thermometer
lambda: return id(midea_climate).current_temperature;
- platform: resistance
sensor: source_sensor
configuration: UPSTREAM
resistor: 10kOhm
id: photoresistor_sensor
name: Display Photoresistor
disabled_by_default: true
entity_category: diagnostic
filters:
- clamp:
min_value: $min_photoresistor_threshold
max_value: $max_photoresistor_threshold
on_value:
- lambda: |-
if(id(midea_climate).mode == CLIMATE_MODE_OFF){
id(display_switch).publish_state(false);
}else if(id(display_photoresistor_threshold).has_state() && x < id(display_photoresistor_threshold).state){
id(display_switch).publish_state(true);
}else{
id(display_switch).publish_state(false);
}
- platform: adc
pin: GPIO2
id: source_sensor
attenuation: auto
update_interval: 1s
- platform: homeassistant
id: follow_me_temp
entity_id: $follow_me_temperature_sensor
filters:
- throttle: 10s
- heartbeat: 2min
- debounce: 1s
on_value:
if:
condition:
and:
- lambda: return id(midea_climate).mode != CLIMATE_MODE_OFF;
- switch.is_on: follow_me
then:
midea_ac.follow_me:
temperature: !lambda "return x;"
beeper: false
number:
- platform: template
name: "Display Photoresistor Threshold"
id: display_photoresistor_threshold
icon: "mdi:alarm-light-outline"
unit_of_measurement: "ohm"
optimistic: true
min_value: $min_photoresistor_threshold
max_value: $max_photoresistor_threshold
initial_value: $default_display_photoresistor_threshold
restore_value: true
step: 1
entity_category: config
button:
- platform: template
name: Swing Step
icon: mdi:tailwind
on_press:
if:
condition:
lambda: return id(midea_climate).mode != CLIMATE_MODE_OFF;
then:
midea_ac.swing_step:
- platform: template
name: Active Clean
on_press:
- remote_transmitter.transmit_pronto:
data: "0000 0073 0000 0064 00a0 009c 0015 0037 0014 0011 0014 0039 0014 0039 0014 0037 0014 0012 0014 0011 0014 0039 0014 0011 0014 0039 0014 0011 0014 0013 0013 0011 0014 0039 0014 0039 0014 0011 0014 0039 0014 0037 0014 0039 0014 0039 0014 0011 0014 0039 0014 0012 0013 0039 0014 0012 0014 0011 0014 0011 0014 0012 0014 0037 0014 0012 0014 0039 0013 0012 0014 0011 0014 0039 0014 0011 0014 0012 0014 0037 0014 0039 0014 0039 0014 0039 0014 0039 0013 0012 0014 0039 0014 0037 0014 0012 0014 0011 0014 0012 0013 0012 0014 00ba 00a0 009c 0015 0037 0013 0012 0014 0039 0014 0037 0014 0039 0014 0012 0013 0012 0014 0039 0014 0011 0014 0039 0014 0011 0014 0012 0013 0013 0013 0039 0014 0037 0014 0012 0014 0039 0013 0039 0014 0039 0014 0039 0014 0011 0014 0039 0014 0011 0014 0039 0014 0011 0014 0012 0014 0011 0014 0012 0013 0039 0014 0012 0014 0037 0014 0012 0014 0012 0013 0039 0014 0011 0014 0012 0013 0039 0014 0039 0014 0039 0014 0039 0013 0039 0014 0012 0014 0037 0014 0039 0014 0012 0013 0012 0014 0011 0014 0012 0014 0e4a"
- platform: template
name: Dump Config
entity_category: diagnostic
on_press:
lambda: |-
id(midea_climate).dump_config();
xiao_esp32c3.yaml
# Chip is ESP32-C3 (QFN32) (revision v0.4)
# Features: WiFi, BLE, Embedded Flash 4MB (XMC)
# Crystal is 40MHz
esp32:
board: seeed_xiao_esp32c3
sensor:
- platform: internal_temperature
name: "Internal Temperature"
# The following are specific settings for air conditioner
uart:
rx_pin: GPIO20
tx_pin: GPIO21
baud_rate: 9600