Introducing CHAI - a CAME gate controller to Home Assistant Interface

I have a parking gate with a Came BXV controller and wanted to fully integrate it with a home automation system. Using a good old ESP8266 and ESPHome, I can now exactly control the movements from Home Assistant, get feedback of the actual gate position and state, and control it remotely or set-up alarms in case it stays open for too long for example.

So let me introduce CHAI - a CAME gate controller to Home Assistant Interface

Intro

A few years ago, I installed a sliding parking gate with a Came BXV controller. I always thought it would be great to integrate it with a home automation system, for the following reasons:

  • The provided RF remote control has a limited range and you can never be sure the command has been received when you press the button from far away (so you often end up clicking a second time, and if the first command was in fact received, the gate stops and you have to click again to close, again to stop, and one more time to get it to open again)
  • When you leave and the gate starts to close, a spurious condition could trip the IR security sensor and stop the closing motion, leaving the gate open for the day
  • When you're expecting a package, it can be useful to remotely open the gate for a short time and let the delivery guy drop your parcel at a safe place

After a quick survey, I selected Home Assistant, which looks like the sensitive choice nowadays, and tried to design a device acting as a Came controller with Home Assistant, referred to as CHAI hereafter :-)

So finally, with the great help of MacGyver, I gave it a shot and here are our thoughts and results.

Target features

  • Must control the gate movements with distinct commands: OPEN - STOP - CLOSE
  • Must know for sure if the gate is fully open or closed
  • Must know if the gate is in movement
  • Must leave functional control using the original RF remote control (and reflect the situation in Home Assistant)
  • Must leave functional control using the original RF remote control even in case of power supply failure on CHAI
  • Must not do any action on the gate in case of CHAI reboot

Demonstration

Before diving into the implementation details, here is a demonstration of the final installation working at my home.



Hardware design

Please note that most of the information about the CAME controller comes from the official documentation, namely the manual for my model.

Microcontroller

I chose to base the CHAI on an ESP8266 chip on a WeMos D1 mini clone board as it is cheap, reliable and easy to interface. Plus, it has extended support in HomeAssistant through the ESPHome Add-On.

Power supply

The power supply of the Came controller board is 24VAC coming from a transformer.

I first thought of plugging a voltage conversion module to that source to power the CHAI, but finally decided to limit connections to the original setup as much as possible, so I included a dedicated power supply from the mains.

I chose a Hi-Link 5V AC/DC module I had laying around and added a small fuse in line. The 5V is fed to the D1 Mini which in turn produces the 3.3V required by the ESP. Currently no other device on the CHAI actually uses that 5V Voltage, but I thought it was futureproof to have 5V available.

Simulating button press:

The controller has terminals to connect buttons to: By default, button 2 (STOP) is disabled and button 4 is configured as "step-by-step" mode (open-close). We need to change the controller configuration as follows:

  • “F1=ON” to activate button 2 as “stop”
  • “F7=3” to configure button 4 as “close”
  • “F8=2” to configure button 3 as “open”

A few measurements indicate that the controller has pull-ups of 4.7KOhm to 5V on each contact, so connecting a N-channel MOSFET (2N7000) to GND, driven by a 3.3V pin of the ESP8266, will fit the bill.

Important note: I checked that all signals we will use below are referenced to the same ground. So connecting the CHAI ground to terminal 2 of this connector will make sure the two boards share a common ground.

Buttons 2 and 3 are Normally Open, so a 10kOhm pull-down on the gate of the MOSFET will make sure that they are not "pressed" active when left floating (even in case of reboot or power loss). The schematic is as follows (note that the final selection of ESP pins will be made later, this is just to show the external circuit logic): The STOP button, however, is Normally Closed (it can be used as an Emergency Stop button). In other words we have to make sure that the connection remains closed (MOSFET gate high) by default.

To achieve that pull-up even in case of power loss, we'll derive power from the other buttons, 2 and 3 (through 2 signal diodes (e.g. 1N4148) and a 10kOhm resistor to avoid interfering with those signals).

We'll also put two more diodes in series to drop the voltage and avoid exposing the ESP8266 input pin to a voltage above 3.3V. Something like:

Sensing limit switches

The CAME motor and controller also contains 2 limit switches connected to the controller's F/FA/FC terminals:

The limit switch themselves consist of a single spring that gets pushed left or right when the gate is fully open or closed, and flips one switch or the other:

The original schematic is as follows:

  • F (orange wire) is GND
  • FC (red wire, on the left) is held to GND unless the gate is fully closed.
  • FA (white wire, on the right) is held to GND unless the gate is fully open.

The complementary outputs of the switches are located between the orange and red, and orange and white terminals, and are not used by the CAME controller.

When not held to GND, FA and FC are pulled up to 5V by the controller.

Instead of connecting in parallel to those red/white wires and having to deal with level conversion from 5V to 3.3V, I simply used the complementary outputs of the switches, connected to an ESP pin (via a 560Ohm protection resistor - cabling errors happen, ask me how I know ;-)).

The ESP pins are configured with an internal pull-up to 3.3V, so those wires are at 3.3V unless the gate is fully closed or fully open.

Sensing motor movement

The motor is powered by the controller via terminals M/N (1 on the schematic below), and an encoder gives positional feedback to the controller through the terminals labeled +/E/- (2):

The measured DC voltage across terminals M/N is:

  • 30V when opening at full speed
  • 15V when opening at half-speed (approaching fully open)
  • 0V when the gate is not moving
  • -15V when closing at half-speed (approaching fully closed)
  • -30V when closing at full speed

At first, I wanted to retrieve information from the encoder terminals. However, I could not make sense of the observed signals, which look like this: (strangely enough, the small peaks between the big ones only appear at half speed).

I might have measured wrong. If anybody has sucessfully decoded that signal, don't hesitate to reach back to me... I might make a version 2 :-).

Anyway, in the meantime, we'll use the time of travel in one direction or the other to get an estimate of the gate position (remember that the end positions will be known for sure thanks to the limit switches).

To achieve this, we will just need to know when the gate is moving, and in which direction. The easiest way is to check the motor terminals voltage, but to handle negative voltages, and to protect the ESP from "high" voltage and spikes that could happen at the motor terminals, we'll run them through optocouplers (one PC817 in each direction), as follows:

Reading IR sensor

Although not used in any way by ESPHome's "covers" (*), as we still have a free GPIO, I thought it might be interesting to know if the IR photocell is interrupted. For example, if the gate cannot be closed remotely, that information will tell whether there is an obstacle (car ?) preventing the closing, or if the cause is elsewhere.

According to the CAME manual, here is one way to connect an IR photocell:

Terminal 2 is GND and terminal 10 is VCC (around 17V). The controller’s CX pin has a pull-up to 5V and is expected to be held to GND by the sensor unless the IR barrier is interrupted.

To adapt the level and protect the ESP, I've used a N-channel MOSFET (also 2N7000) as a buffered input as follows:

ESP8266 Pin selection

The ESP8266 (and the Wemos D1) have assigned specific roles to certain pins. Although most can be reconfigured for other uses, the state of the pins at boot time is critical. Some require certain levels for a normal boot to happen, and some are pulled up or down by default. See this excellent RandomNerdTutorlal page for all details.

With the requirement in mind to not interfere with the gate upon boot, I settled on the following pin assignment:

  • D1 and D2: movement (motor rotation) sensing
  • D3: IR barrier sensing
  • D4: STOP button
  • D5 and D6: limit switches sensing
  • D7 and D8 : OPEN/CLOSE buttons

Final circuit:

Here is the schematic (including a model of the controller to the right of the terminals):

And here is my working prototype (actually, as it is working fine, let's call it the production version :-)):

And protected in the black box at the bottom right :

Software design

Environment

As indicated above, I'm using Home Assistant (Important: install it as supervisor to be able to install AddOns. I recommend using Home Assistant OS on a Raspberry Pi), and the ESPHome Add-On for Home Assistant.

ESPHome component

Parking gates are part of ESPHome's "covers" (*), and several variants are supported. As we have limit switches that provide feedback to the ESP, the variant used here is called "feedback cover", which is part of the "time-based cover" family. In other words it can translate the "time of travel" to a position (in percentage) and conversely.

Like most configurations in Home Assistant, the ESPHome device is configured using YAML. Apart from the boilerplate sections (network connectivity, over-the-air update, possibility to force a reboot and get uptime and Wi-Fi quality metrics), the code defines mainly 3 outputs for the open/stop/close buttons and 5 binary sensors for the limit switches, motor sensing and IR barrier. Then, based on those, the "ParkingGate" cover is created and configured with the full opening/closing time (measured at 20s in my case) and a duration to emulate the button clicks (I used 300ms).

For debugging or lower level access, I also defined 3 "button" controls (to be able to bypass the cover and direcly simulate keypresses), but they are not needed for a functional gate. Similarly, I added a "name" field to the 5 binary sensors so that they show up in HA, but a name is not needed for the cover to work, and only the cover itself has to be given a name to be displayed in HA.

Optional feature - "Postman" script

Finally, the "postman" feature allows one to flip a switch in HA to trigger the following sequence to let a delivery guy leave a parcel inside: open gate partially / wait for 1 minute / close gate.

That feature is mainly a script, associated with a "switch" UI component that turns on and starts the script when you click on it, and turns off when the script is finished (with a bit of fiddling so that the script stops if you flip the switch back to off when it's running). Obviously, the postman script is completely optional.

Final configuration

Here is the complete YAML file I'm using:


esphome: name: "esp-parking" friendly_name: ESP Parking esp8266: board: d1_mini # Enable logging logger: # Enable Home Assistant API api: encryption: key: "************" ota: password: "************" wifi: ssid: !secret wifi_ssid password: !secret wifi_password # Enable fallback hotspot (captive portal) in case wifi connection fails ap: ssid: "Esp-Parking Fallback Hotspot" password: "************" manual_ip: static_ip: ************ gateway: ************ subnet: ************ captive_portal: output: - platform: gpio pin: D7 id: gate_control_close - platform: gpio pin: D8 id: gate_control_open - platform: gpio pin: D4 id: gate_control_stop inverted: true binary_sensor: - platform: gpio id: is_gate_opening name: is_gate_opening pin: number: D1 mode: input: true pullup: true inverted: true - platform: gpio id: is_gate_closing name: is_gate_closing pin: number: D2 mode: input: true pullup: true inverted: true - platform: gpio name: "Gate obstacle detected" pin: number: D3 mode: input: true pullup: true inverted: true - platform: gpio id: is_gate_open name: is_gate_open pin: number: D5 mode: input: true pullup: true inverted: true - platform: gpio id: is_gate_closed name: is_gate_closed pin: number: D6 mode: input: true pullup: true inverted: true cover: - platform: feedback device_class: gate name: "ParkingGate" id: parking_gate has_built_in_endstop: True open_action: - output.turn_on: gate_control_open - delay: 300ms - output.turn_off: gate_control_open open_duration: 20s open_endstop: is_gate_open open_sensor: is_gate_opening close_action: - output.turn_on: gate_control_close - delay: 300ms - output.turn_off: gate_control_close close_duration: 20s close_endstop: is_gate_closed close_sensor: is_gate_closing stop_action: - output.turn_on: gate_control_stop - delay: 300ms - output.turn_off: gate_control_stop script: - id: postman_access then: - cover.control: id: parking_gate position: 25% - delay: 65s # must be = opening time + duration of the "open" phase - cover.close: parking_gate - delay: 8s # must be = closing time + a few secs (motor slows down when nearing full close) - switch.turn_off: postman switch: - platform: template name: "Postman" id: postman optimistic: True #otherwise it turns off automatically after a delay as it has no confirmation of a state turn_on_action: - script.execute: postman_access turn_off_action: - script.stop: postman_access - cover.stop: parking_gate button: - platform: restart # reboot button name: "Gate module reboot" - platform: output name: "Gate control open" output: gate_control_open duration: 300ms - platform: output name: "Gate control close" output: gate_control_close duration: 300ms - platform: output name: "Gate control stop" output: gate_control_stop duration: 300ms sensor: # wifi signal level in dBm - platform: wifi_signal name: "Gate WiFi signal" update_interval: 60s # ESP uptime (to track reboots, if any) - platform: uptime name: Uptime Sensor

In the UI, using the history explorer Add-On, one can check the cover state changes based on the individual binary sensors:


(*) The ESPHome term "covers" covers (no pun intended :-)) gates, blinds, curtains, garage doors, and basically all home elements that do open or close

They posted on the same topic

1. On 2024-03-09, 14:04 by CHAI Acts as a Good Espressif ESP8266 Gateway Between

CHAI Acts as a Good Espressif ESP8266 Gateway Between

(…) The venture is documented in full, together with wiring diagrams and the YAML configuration file, on Vince’s weblog. (…)

Trackback URL : http://blog.deconinck.info/trackback/37

This post's comments feed