Vamos lá. Primeiramente, disclamer:
1: Use este tutorial por responsabilidade própria. NÃO SOU PROFISSIONAL da área. Provavelmente haverão erros, e o que funcionou para mim, não necessariamente funcionará para você.
2: Esta modificação com certeza vai invalidar a sua garantia do Contatto PPA, e talvez do seu motor.
3: Não cometa o mesmo erro que eu. DELIGUE A ENERGIA do portão antes de mexer nele. Tomei um BAITA choque quando estava mechendo e fiquei preso por alguns segundos ao portão. Isso tem mais de um mês, e o ferimento ainda não cicatrizou completamente. CUIDADO!
Será necessário um conversor USB - UART. Eu usei esse:
4 jumper wires para fazer o flash inicial, ou qualquer outro tipo de conexão que julgar melhor. Eu preferi soldar os jumper wires, porquê é o que eu tinha em casa.
Na imagem:
Fio verde: RX
Fio amarelo: GPIO0
Fio branco: TX
Fio azul: 3.3V
Para o flash, fiz via web.esphome.io
Conexão:
UART GND - Fio preto do chicote da foto
UART 3.3V - Fio azul da foto
UART RX - Fio branco da foto (TX)
UART TX - Fio verde da foto (RX)
Antes de ligar tudo, até o início do flash, o fio amarelo deve ser conectado ao GND para colocar o controlador em modo Download.
Se não quiser soldar o fio azul, e tiver facilmente uma fonte 12V, podem ser utilizados os fios vermelho e preto do chicote original como VCC e GND. Como eu não tinha, fiz desse jeito.
Após o flash, EU precisei reiniciar o controlador, cortando a energia e ligando novamente, para configurar o Wifi da casa. Após isso, é possível inclusive já instalar o Contatto no portão (Mais obre isso depois), mas eu fiz o desenvolvimento em bancada com uma fonte 12V que acabei comprando. 
Possiveis problemas: Inversão dos cabos RX/TX.
Falta de drivers do USB/Uart.
Mal contato nas conexões.
Comigo passei pelos 3, sua situação pode ser diferente.
A partir daí, seu novo ESPhome já deve aparecer no seu dashboard. Adicione ele ao home assistant e use um dos códigos abaixo:
Template cover:
substitutions:
devicename: south_gate
globals:
- id: performing_last_movement
type: boolean
restore_value: no
initial_value: 'false'
sensor:
- platform: wifi_signal
name: “WiFi Signal $devicename”
update_interval: 60s
- platform: uptime
name: “Uptime $devicename”
- platform: adc
pin: A0
name: “Teste ADC”
update_interval: 600s
- platform: adc
pin: VCC
name: “VCC Voltage $devicename”
text_sensor:
- platform: wifi_info
ip_address:
name: “ESP IP Address $devicename”
ssid:
name: “ESP Connected SSID $devicename”
bssid:
name: “ESP Connected BSSID $devicename”
mac_address:
name: “ESP Mac Wifi Address $devicename”
switch:
- platform: restart
name: “$devicename Restart”
- platform: gpio
name: “$devicename Relay”
id: relay$devicename
pin: GPIO4
restore_mode: ALWAYS_OFF
- platform: gpio
internal: true
name: “$devicename LED”
id: led$devicename
pin: GPIO12
restore_mode: ALWAYS_OFF
- platform: gpio
name: “Action $devicename”
icon: "mdi:gate"
id: Action$devicename
pin: GPIO13
restore_mode: ALWAYS_OFF
on_turn_on:
- delay: 500ms
- switch.turn_off: Action$devicename
binary_sensor:
- platform: status
name: “$devicename Status”
- platform: gpio
#device_class: presence
name: “$devicename Open” # FIO AZUL
id: open_endstop_$devicename
pin:
number: GPIO5
inverted: True
mode: INPUT_PULLUP
filters:
delayed_on_off: 100ms
- platform: gpio
#device_class: presence
name: “$devicename Button”
id: button$devicename
pin:
#number: RX
number: GPIO2
inverted: True
mode: INPUT_PULLUP
filters:
delayed_on_off: 100ms
- platform: gpio
#device_class: presence
name: “$devicename Closed” # FIO Branco
id: closed_endstop_$devicename
pin:
#number: RX
number: GPIO14
inverted: True
mode: INPUT_PULLUP
filters:
delayed_on_off: 100ms
cover:
- platform: template
name: South Gate
id: southgate
device_class: garage
lambda: |-
if (id(closed_endstop_$devicename).state) //Door at closed endstop
{
if (id(southgate).current_operation == esphome::cover::COVER_OPERATION_OPENING) //We should be opening
{
if (!id(performing_last_movement)) //Make sure we don't trigger this logic twice otherwise it will do unwanted things
{
delay(1000); //Wait for door to stop in case reed is triggered too early
id(Action$devicename).turn_on(); //Press button again
id(performing_last_movement) = true; //Set flag to indicate we madeknow where the door is
}
}
else if (id(southgate).current_operation == esphome::cover::COVER_OPERATION_CLOSING)
{
//We should be closing, so all is good
id(performing_last_movement) = false;
id(southgate).current_operation = esphome::cover::COVER_OPERATION_IDLE;
id(southgate).position = COVER_CLOSED;
id(southgate).publish_state();
return COVER_CLOSED;
}
else
{
//No operation in progress, just send state
id(performing_last_movement) = false;
if (!(id(southgate).position == esphome::cover::COVER_CLOSED))
{
id(southgate).position = COVER_CLOSED;
id(southgate).publish_state();
return COVER_CLOSED;
}
}
}
else if (id(open_endstop_$devicename).state) //Door at open endstop
{
if (id(southgate).current_operation == esphome::cover::COVER_OPERATION_CLOSING) //We should be closing
{
if (!id(performing_last_movement)) //Make sure we don't trigger this logic twice otherwise it will do unwanted things
{
delay(1000); //Wait for door to stop in case reed is triggered too early
id(Action$devicename).turn_on(); //Press button again
id(performing_last_movement) = true; //Set flag to indicate we madeknow where the door is
}
}
else if (id(southgate).current_operation == esphome::cover::COVER_OPERATION_OPENING)
{
//We should be opening, so all is good
id(performing_last_movement) = false;
id(southgate).current_operation = esphome::cover::COVER_OPERATION_IDLE;
id(southgate).position = COVER_OPEN;
id(southgate).publish_state();
return COVER_OPEN;
}
else //Door not at any endstop
{
//No operation in progress, just send state
id(performing_last_movement) = false;
if (id(southgate).position != esphome::cover::COVER_OPEN)
{
id(southgate).position = COVER_OPEN;
id(southgate).publish_state();
return COVER_OPEN;
}
}
}
else
{
//The door is halfway open, so set it to OPEN
if (id(southgate).position != esphome::cover::COVER_OPEN)
{
id(southgate).position = COVER_OPEN;
id(southgate).publish_state();
return COVER_OPEN;
}
}
return {};
open_action:
- lambda: |-
id(southgate).current_operation = esphome::cover::COVER_OPERATION_OPENING;
if (!id(open_endstop_$devicename).state) {
id(Action$devicename).turn_on();
if (id(closed_endstop_$devicename).state) {
id(performing_last_movement) = true; //Set flag to indicate we know where the door is
}
}
close_action:
- lambda: |-
id(southgate).current_operation = esphome::cover::COVER_OPERATION_CLOSING;
if (!id(closed_endstop_$devicename).state) {
id(Action$devicename).turn_on();
if (id(open_endstop_$devicename).state) {
id(performing_last_movement) = true; //Set flag to indicate we know where the door is
}
}
stop_action:
- lambda: |-
if (id(southgate).current_operation == esphome::cover::COVER_OPERATION_OPENING )
{
id(southgate).current_operation = esphome::cover::COVER_OPERATION_IDLE;
//Stop the door if it is opening
id(performing_last_movement) = false;
id(Action$devicename).turn_on();
}
else if (id(southgate).current_operation == esphome::cover::COVER_OPERATION_CLOSING )
{
id(southgate).current_operation = esphome::cover::COVER_OPERATION_OPENING;
//return to open if gate is closing
id(performing_last_movement) = true;
id(Action$devicename).turn_on();
}
interval:
- interval: 1s
then:
- if:
condition:
wifi.connected:
then:
- if:
condition:
switch.is_off: led$devicename
then:
- switch.turn_on: led$devicename
else:
- switch.turn_off: led$devicename
Feedback Cover e Portão social:
substitutions:
devicename: north_gate
sensor:
- platform: wifi_signal
name: “WiFi Signal $devicename”
update_interval: 60s
- platform: uptime
name: “Uptime $devicename”
- platform: adc
pin: A0
name: “Teste ADC”
update_interval: 600s
- platform: adc
pin: VCC
name: “VCC Voltage $devicename”
text_sensor:
- platform: wifi_info
ip_address:
name: “ESP IP Address $devicename”
ssid:
name: “ESP Connected SSID $devicename”
bssid:
name: “ESP Connected BSSID $devicename”
mac_address:
name: “ESP Mac Wifi Address $devicename”
switch:
- platform: restart
name: “$devicename Restart”
- platform: gpio
name: “Social Gate Action"
id: actionsocialgate
pin: GPIO4
restore_mode: ALWAYS_OFF
on_turn_on:
- delay: 1s
- switch.turn_off: actionsocialgate
- platform: gpio
name: “Led $devicename”
id: led$devicename
internal: true
pin: GPIO12
restore_mode: ALWAYS_OFF
- platform: gpio
name: “Action $devicename”
icon: "mdi:gate"
id: Action$devicename
pin: GPIO13
restore_mode: ALWAYS_OFF
on_turn_on:
- delay: 500ms
- switch.turn_off: Action$devicename
binary_sensor:
- platform: status
name: “$devicename Status”
- platform: gpio
#device_class: presence
name: “$devicename Open” # FIO AZUL
id: open$devicename
pin:
number: GPIO5
inverted: True
mode: INPUT_PULLUP
filters:
delayed_on_off: 100ms
- platform: gpio
#device_class: presence
name: “Reset Button $devicename”
id: ResetButt$devicename
pin:
#number: RX
number: GPIO2
inverted: True
mode: INPUT_PULLUP
filters:
delayed_on_off: 100ms
- platform: gpio
#device_class: presence
name: “$devicename Closed” # FIO Branco
id: closed$devicename
pin:
#number: RX
number: GPIO14
inverted: True
mode: INPUT_PULLUP
filters:
delayed_on_off: 100ms
- platform: homeassistant
id: socialgatecontact
# internal: false
# state_class: presence
entity_id: binary_sensor.social_gate_contact
attribute: contact
cover:
- platform: feedback
name: "North Gate"
id: NorthGate
has_built_in_endstop: True
infer_endstop_from_movement: false
open_action:
- switch.turn_on: Action$devicename
open_duration: 9s
open_endstop: open$devicename
close_action:
- switch.turn_on: Action$devicename
close_duration: 9s
close_endstop: closed$devicename
stop_action:
- switch.turn_on: Action$devicename
#controlador do portão social, usando um sensor zigbee do home assistant
- platform: template
name: "Social Gate"
id: socialgate
device_class: door
# assumed_state: true
has_position: true
lambda: |-
if (id(socialgatecontact).state) {
// socialgatecontact reports door as closed
return cover::COVER_CLOSED;
}
else if (!id(socialgatecontact).state) {
// socialgatecontact reports door as open
return cover::COVER_OPEN;
}
else {
return {};
}
open_action:
- switch.turn_on: actionsocialgate
- delay: 1s
- cover.template.publish:
id: socialgate
interval:
- interval: 1s
then:
- if:
condition:
wifi.connected:
then:
- if:
condition:
switch.is_off: led$devicename
then:
- switch.turn_on: led$devicename
else:
- switch.turn_off: led$devicename
Não vou entrar em detalhes aqui sobre a diferença entre Template e feedback cover. Como tenho dois portões, usei os dois e venho testando. Verifique a documentação para detalhes.
Instalação:
Esta imagem foi retirada do manual do Contatto PPA Wifi.
No nosso caso, podemos utilizar além do Fim de curso Fechado, o Fim de Curso Aberto do portão, dessa forma podendo confirmar quando o portão está completamente aberto. Infelizmente não tenho capacidade de código ainda para fazer um uso efetivo deste sensor, conseguindo demonstrar no HA se o portão está aberto, fechado, ou parcial. Ao mesmo tempo, caso o funcionamento do portão seja interrompido no meio do movimento, por vezes o HA não registra a posição correta.
De qualquer forma, fim de curso aberto é o fio azul do chicote original.
Utilize o manual de instalação do dispositivo, disponível no site do fabricante para instalação do hardware. Lembre-se de posicionar o Jumper da placa no modo portão. Não testei nenhum dos outros modos.
Muito do código, principalmente o que é cada cabo, veio do @eduardofbrito acima. Eu apenas fiz a correspondência do ESP12F para o ESP01 usando o diagrama de pinos dos dois. Fiz a correspondência apenas dos pinos que usei. Para os outros, deixei de acordo com o código que usei.
Esse é meu primeiro tutorial, então aceito toda e qualquer crítica, mesmo que só pra falar que fiz tudo errado.