I domotise my portal with a MOES ZM-102-M Zigbee

This comprehensive tutorial explains the precise wiring, Zigbee2MQTT configuration, Home Assistant integration and Alexa. A single dashboard button + real status feedback + voice command ‘Alexa opens the portal’.

My three objectives domotisation portal

I have set three specific objectives to domotise my Came beating portal equipped with a ZL180 control card.

  • A single button on the Home Assistant dashboard activates the portal via a precise impulse sequence: dry contact ON for 500 ms, break 500 ms minimum, then OFF.
  • Actual status return showing whether the gate is open or closed at any time, using a position sensor.
  • Simple voice control with Alexa: "Alexa, open the portal" or "Alexa, close the portal".

This tutorial replaces the old one using the QS-Zigbee-S10-C03 module which caused frequent disconnections from the Zigbee network. Obsolete article: Domotisation QS-Zigbee-S10-C03.

My order card Came ZL180

My beating portal works with the Came ZL180 electronic card that handles all movements, safety and race ends.

Full official technical information sheet: Download PDF ZL180.

ZL180 Came control card installed in the housing

ZL180 card order terminals

All home automation connections connect to the terminal blocks at the bottom right of the ZL180 card. These 10 terminals allow the control of the portal and the reading of the states.

ZL180 Card Terminal Identification Scheme

Control opening/closing portal

The ZL180 card controls the opening/closing by a dry contact (without voltage) between terminals 2 (COM) and 7 (IMP). Dry contact simply means closing the electrical circuit without applying voltage.

  • Close the terminal contact 2-7 for exactly 500 milliseconds (0.5 seconds).
  • Maintain a break of at least 500 ms before re-ordering.
  • Open the contact (OFF) to complete the pulse.

This pulse sequence is mandatory and described on page 8 of package leaflet ZL180.

Extract record ZL180 sequence impulse command terminals 2-7

Open/closed portal status return

The ZL180 card does not provide direct dry contact for the status of the gate. It delivers a 24V signal between terminals 5 (COM) and 10 (OUV) when the portal is fully open.

Extract notice ZL180 signalling 24V terminals 5-10

To convert this 0/24V signal to home automation-compatible dry contact, I install a 24V IEC255 relay in the Came housing. The relay electrically insulates the circuits and creates a simple open/closed dry contact.

Diagram conversion 24V to dry contact relay IEC255

Here is my IEC255 relay mounted on DIN support in the Came housing:

IEC255 relay installed in Came housing
Support DIN relay in Came housing
IEC255 relay used for 24V/dry contact conversion

DIP configuration switches crucial

Frequent problem: some impulses are not taken into account. The cause is often the "Stop" function activated on the DIP switch 2 of the ZL180 card. This function stops the portal at each impulse received.

Solution: position the DIP2 on OFF to allow partial controls (normal opening/closing).

Configuration DIP2=OFF card Came ZL180

My choice module Zigbee MOES

I tested several modules but chose the MOES ZM-102-M for its Zigbee stability, affordable price and full gate functions.

The MOES ZM-102-M-MS includes 230V power supply, pulse output, dry contact input and magnetic sensor. Version ZM-102-M = single module without sensor.

Module MOES ZM-102-M connectors

Where to buy this equipment?

Here is the link to the page dedicated to ZM-102-M. I referenced the sellers and prices.

Precise pinning MOES ZM-102-M

  • L and N : 230V phase + neutral power supply.
  • S4-S5 : Dry contact input (connected to IEC255 relay for portal state).
  • S1-S2 : Pulse output to terminals 2-7 card ZL180.
Brochure diagram MOES ZM-102-M
MOES ZM-102-M Module Connectors

Complete portal wiring diagram

Complete cabling diagram Came portal + MOES ZM-102-M + 24V relay

I pair the Zigbee2MQTT module

Power on = automatic pairing mode (blue LED flashes 10 min). Pair button behind the module. Place temporarily near the Zigbee coordinator if significant distance.

LED Pairing Module MOES ZM-102-M

In Zigbee2MQTT in "Permit Join" mode, the module appears as _TZE200 _fabuwqzo _ts0601. I call it "Came Portal".

Interface Zigbee2MQTT pairing MOES ZM-102-M
Renowned module Portal Came Zigbee2MQTT

Features exposed MOES

The module sets out these essential properties:

  • trigger (binary): Sends pulse S1-S2. true=open, false=close. Intelligence: does not send if state already correct.
  • _door _contact Garage (binary): State S4-S5. true=closed, false=open.
  • countdown (0-43200s): Forced impulse after delay.
  • run_time (-1 to 120s): Timeout movement. Alarm if overwhelmed.
  • status : Normal / RunTimeAlarm / OpenTimeAlarm.
Zigbee2MQTT interface complete Came Portal

Automatic integration Home Assistant

Entities automatically appear in Home Assistant after restarting or refreshing Zigbee2MQTT.

Entities Home Assistant module Portal Came
  • binary_sensor.portal_came_garage_door_contact : Real state (off=closed, on=open).
  • switch.portal_came_trigger : Pulse button (ON 500ms then auto-OFF).
  • sensor.portal_came_status : Module status.

My configuration Cover Portal

I create a unified Cover entity combining the real state (binary _sensor) and the command (switch). A Cover Home Assistant represents any workable element: gate, door, roller shutter.

Add in configuration.yaml under template → cover:

- cover: - name: _id Single Portal: cover.portal device_class: gate icon: > {% if is_state('binary_sensor.portal_came_garage_door_contact', 'off') %mdi:gate {% else %mdi:gate-open {% endif %} state: > {% if is_state('binary_sensor.portal_came_garage_door_contact', 'off') %} closed {% else %} open {% endif %} open_cover: - service: script.actionne_le_portal_toggle close_cover: - service: script.actionne _le _porttail _toggle
Entity Cover Portal Home Assistant

My dashboard portal buttons

Dashboard Portal Control Button Home Assistant

Simple button-card version

Single button version portal button-card
Type: custom:button-card show_name: false tap_action: Action: toggle entity: cover.portal state: -value: closed color: gray - value: open color: red

Advanced version picture-elements

Integrated picture-elements portal button
Animation Button Portal Opening
- type: custom:button-card color_type: card entity: cover.portal show_name: false tap_action: Action: toggle state: -value: open color: "#4f010a" icon: mdi:gate-open styles: card: - animation: blink 2s ease infinite - operator: default color: "#49556c" icon: mdi:gate styles: card: - height: 110px - width: 110px style: top: 93% left: 5%

Alexa Voice Control Portal

Expose the cover.portal entity to Alexa for voice control.

  1. Settings → Voice Assistants → "x entity(ies) to expose".
  2. Select cover.portal.
  3. Orders: "Alexa, open the portal", "Alexa, close the portal".
Menu Voice Assistants Home Assistant
Alexa Home Assistant Entities Exhibition
Selection cover.portal Alexa

Visual pulse bonus

Animation Visual Pulse Confirmation Portal

Immediate visual confirmation of pulse sending by flashing icon. Create input_boolean.pulse_portal via Settings → Devices & Services → Helpers → Switch.

Creation input_boolean impulse portal
Type: custom:button-card entity: input_boolean. impulse_portail name: Impulsion Portal show_state: false show_name: false icon: mdi:access-point styles: icon: - color: | [[ if (entity.state === 'on') return '#39FF14'; 'transparent' return; ]]] - animation: | [[[ if (entity.state === 'on') return 'blink 0.4s linear infinite'; return 'none'; ]]] card: - width: 150px - height: 150px - border-radius: 12px - background-color: transparent - box-shadow: none

Script operates _le _portal _toggle (to be created in scripts.yaml):

sequence: - service: switch.turn_on target: entity_id: switch.portal_came_trigger - service: input_boolean.turn_on target: entity_id: input_boolean. impulse_portal - delay: second: 1 - Service: input_boolean.turn_off target: entity_id: input_boolean. impulse_portal alias: Operates the portal

Bonus Rustine Opening

I have found, for a reason which still eludes me, that approximately once in every twenty, the order to open the portal is triggered correctly: the pulse is sent to the module, no errors appear … but nothing happens.

Everything suggests that the module is in standby mode at the time of ordering and simply does not react.

On the other hand, if I return a second pulse within seconds, the portal opens immediately.

Usually I am rather allergic to “rustines”. I like to understand and correct the problem at the source. But in this case, the most pragmatic solution seemed to me to be to add a catch-up mechanism.

The idea is simple:
if, after an opening command, the portal is still detected as closed after a few seconds, then the script automatically returns a second pulse.

At worst, we lose two seconds.
At best, an unseen hazard is corrected for the user.

I therefore set up the following script:

sequence: - alias: Saves the state of the portal before pulse variables: etat_portal_avant: "{{states('binary_sensor.portal_came_garage_door_contact') }}" - alias: Sends the impulse to the action portal: switch.toggle target: entity_id: switch.portal _came _trigger data: {} - parallel: - alias: Blinks the pulse sending on Dashboard sequence: - action: input_boolean.turn_on target: entity_id: input_boolean. impulse_portal data: {} - delay: second: 1 - Action: input_boolean.turn_off target: entity_id: input_boolean. impulse_portal data: {} - alias: Rustine only if the portal was closed sequence: - if: - condition: template value _template: "{{ etat _porttail _avant == 'off' }}" then: - alias: Maximum wait 2s for the portal to open wait_template: >- {{ is_state('binary_sensor.portal_came_garage_door_contact', 'on') }} timeout: second: 2 continues _on _timeout: true - if: - condition: template value _template: "{{ not wait.completed }}" then: - alias: Restarts the impulse if the portal has not reacted action: switch.toggle target: entity_id: switch.portal _came _trigger data: {} alias: Operates the description portal: ""

This script sets up a simple verification mechanism after sending a pulse to the portal, with a catch-up logic in case of problems.

The first step is to remember the status of the portal before any action. It is recorded whether it is open or closed at the time the order is sent (binary_sensor.portal_came_garage_door_contact). This information is important because it then makes it possible to know whether or not to activate the backup logic.

Once this state is saved, the script sends the pulse to the portal via the module (switch.portal_came_trigger), exactly as in normal operation. In parallel, a small visual indicator is activated for one second (input_boolean.pulse_portal), simply to materialise the sending of the pulse to the dashboard.

It is then that “rustine” comes into play, but only in a very specific case: if the gate was closed at the time of ordering. This precaution avoids undesirable effects, especially if the portal is closing, because in this case it can take several seconds to react and it is important not to return an impulse.

If the portal is closed, the script waits up to two seconds to see if it goes into the open state (binary_sensor.portal_came_garage_door_contact). This expectation is active: If the change happens quickly, the script detects it immediately and stops there.

On the other hand, if nothing happens during those two seconds, it is considered that the initial impulse was not taken into account, probably because of a module still in standby mode. The script then automatically sends a second pulse via the module (switch.portal _came _trigger).

In the end, this mechanism acts as a safety net. In the majority of cases, it is useless and remains invisible. But in the rare situations where the portal does not react, it allows to correct the problem without manual intervention, with a simple delay of two seconds.

Full technical documentation

Forum Exchanges Feedback Experience

Questions, feedback, additional diagrams: HACF Forum Discussion.