Connection of the industrial I/O module of the OWEN (ОВЕН) company MU210-403

Hello everyone!
I want to tell how I connected the industrial I/O module MU210-403 from OWEN to the Home Assistant. Using the modbus tcp protocol.
The 24 outputs of the module are controlled by a single bitmask, which looks like 0000 0000 0000 0000 0000 0000. Asynchronous recording of output states is not suitable.

Input Output Module Parameters

Name of the parameter Parameter Value Data type
address of the status record 470 Unsigned 32
state reading address 468 Unsigned 32

My config folder structure:
config/
├──command_line/
│ └── mu210_403_comand_line.yaml
├── python_scripts/
│ └── bit_mask_modbus.py
├── sensors/
│ └── mu210_403_status_output.yaml
├── switches/
│ └── mu210_403_switches.yaml
└── configuration.yaml

Actions:

  1. Install the python “pymodbus.client” module
  2. Connect folders in the file “configuration.yaml” and add commands
Summary
sensor: !include_dir_merge_list sensors/
switch: !include_dir_merge_list switches/
command_line: !include_dir_merge_list command_line/

shell_command:
  mu210_403_set_bit: "python3 /config/python_scripts/bit_mask_modbus.py u32 192.168.77.5 502 1 470 write {{ bit }} {{ value }}"

change the data “192.168.77.5 502” to your IP and port
3. Creating a “yaml” file in the “command_line” folder

Summary
- sensor:
    name: mu210_403_bit_mask
    command: "python3 /config/python_scripts/bit_mask_modbus.py u32 192.168.77.5 502 1 468 read | grep 'dec:' | sed -E 's/.*\\(dec: ([0-9]+)\\).*/\\1/'"
    scan_interval: 2
    value_template: "{{ value | int(0) }}"

change the data “192.168.77.5 502” to your IP and port

  1. Create a file in the “python_scripts” folder “bit_mask_modbus.py”. The script is universal and can read and write data like u8 u16 u32 u64. Tested on u16 and u32
Summary
import sys
import time
from pymodbus.client import ModbusTcpClient

def usage():
    print("Usage:")
    print("  python3 mu_bitmask.py <type> <ip> <port> <slave_id> <address> read")
    print("  python3 mu_bitmask.py <type> <ip> <port> <slave_id> <address> write <bit> <value>")
    print("    <type> - u8, u16, u32, u64")
    print("    <bit> - 1..8 (u8), 1..16 (u16), 1..32 (u32), 1..64 (u64)")
    print("    <value> - 0 or 1")
    sys.exit(1)

if len(sys.argv) < 7:
    usage()

mask_type = sys.argv[1]
ip = sys.argv[2]
port = int(sys.argv[3])
slave_id = int(sys.argv[4])
address = int(sys.argv[5])
action = sys.argv[6]

if mask_type not in ("u8", "u16", "u32", "u64"):
    usage()

if mask_type == "u8":
    reg_count = 1
    bit_max = 8
    mask_fmt = "{:08b}"
elif mask_type == "u16":
    reg_count = 1
    bit_max = 16
    mask_fmt = "{:016b}"
elif mask_type == "u32":
    reg_count = 2
    bit_max = 32
    mask_fmt = "{:032b}"
elif mask_type == "u64":
    reg_count = 4
    bit_max = 64
    mask_fmt = "{:064b}"

client = ModbusTcpClient(ip, port=port)
client.connect()
time.sleep(0.3)

try:
    rr = client.read_holding_registers(address=address, count=reg_count, slave=slave_id)
    if rr.isError():
        print("Read error")
        sys.exit(2)

    if mask_type == "u8":
        reg_val = rr.registers[0]
        mask = reg_val & 0xFF
    elif mask_type == "u16":
        mask = rr.registers[0]
    elif mask_type == "u32":
        mask = (rr.registers[1] << 16) | rr.registers[0]
    elif mask_type == "u64":
        mask = (
            (rr.registers[3] << 48)
            | (rr.registers[2] << 32)
            | (rr.registers[1] << 16)
            | rr.registers[0]
        )

    if action == "read":
        print(f"Current mask: {mask_fmt.format(mask)} (dec: {mask})")
        for i in range(bit_max):
            print(f"Bit {i+1}: {(mask >> i) & 1}")
    elif action == "write":
        if len(sys.argv) != 9:
            usage()
        bit = int(sys.argv[7])
        value = int(sys.argv[8])
        if not (1 <= bit <= bit_max) or value not in (0, 1):
            usage()
        if value:
            mask |= (1 << (bit - 1))
        else:
            mask &= ~(1 << (bit - 1))
        if mask_type == "u8":
            # Сохраняем старшие 8 бит регистра
            new_reg_val = (reg_val & 0xFF00) | (mask & 0xFF)
            values = [new_reg_val]
        elif mask_type == "u16":
            values = [mask]
        elif mask_type == "u32":
            low = mask & 0xFFFF
            high = (mask >> 16) & 0xFFFF
            values = [low, high]
        elif mask_type == "u64":
            regs = [
                mask & 0xFFFF,
                (mask >> 16) & 0xFFFF,
                (mask >> 32) & 0xFFFF,
                (mask >> 48) & 0xFFFF,
            ]
            values = regs
        rq = client.write_registers(address=address, values=values, slave=slave_id)
        if rq.isError():
            print("Write error")
            sys.exit(3)
        print(f"Bit {bit} set to {value}. New mask: {mask_fmt.format(mask)} (dec: {mask})")
    else:
        usage()
finally:
    client.close()
  1. Creating a “yaml” file in the “sensors” folder (these are my configurations, so outputs 19-24 are inverted).
Summary
- platform: template
  sensors:
    mu210_403_output_1_state:
      unique_id: "mu210_403_output_1_state"
      friendly_name: "Ванная свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(1) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_2_state:
      unique_id: "mu210_403_output_2_state"
      friendly_name: "Ванная подсветка состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(2) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_3_state:
      unique_id: "mu210_403_output_3_state"
      friendly_name: "Прихожая свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(4) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_4_state:
      unique_id: "mu210_403_output_4_state"
      friendly_name: "Гардероб свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(8) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_5_state:
      unique_id: "mu210_403_output_5_state"
      friendly_name: "Коридор подсветка состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(16) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_6_state:
      unique_id: "mu210_403_output_6_state"
      friendly_name: "Коридор свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(32) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_7_state:
      unique_id: "mu210_403_output_7_state"
      friendly_name: "Спальня первый свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(64) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_8_state:
      unique_id: "mu210_403_output_8_state"
      friendly_name: "Спальня второй свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(128) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_9_state:
      unique_id: "mu210_403_output_9_state"
      friendly_name: "Спальня левый светильник состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(256) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_10_state:
      unique_id: "mu210_403_output_10_state"
      friendly_name: "Спальня левый правый состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(512) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_11_state:
      unique_id: "mu210_403_output_11_state"
      friendly_name: "Тулет свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(1024) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_12_state:
      unique_id: "mu210_403_output_12_state"
      friendly_name: "Туалет подсветка состояние: "
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(2048) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_13_state:
      unique_id: "mu210_403_output_13_state"
      friendly_name: "Кухня свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(4096) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_14_state:
      unique_id: "mu210_403_output_14_state"
      friendly_name: "Кабинен первый свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(8192) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_15_state:
      unique_id: "mu210_403_output_15_state"
      friendly_name: "Кабинен второй свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(16384) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_16_state:
      unique_id: "mu210_403_output_16_state"
      friendly_name: "Гостиная первый свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(32768) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_17_state:
      unique_id: "mu210_403_output_17_state"
      friendly_name: "Гостиная второй свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(65536) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_18_state:
      unique_id: "mu210_403_output_18_state"
      friendly_name: "Гостиная подсветка свет состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0))|bitwise_and(131072) %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_19_state:
      unique_id: "mu210_403_output_19_state"
      friendly_name: "Вытяжка состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(262144)) == 0 %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_20_state:
      unique_id: "mu210_403_output_20_state"
      friendly_name: "Спальня вентилятор конвектора состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0)) | bitwise_and(524288) == 0 %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_21_state:
      unique_id: "mu210_403_output_21_state"
      friendly_name: "Спальня и гардероб розетки состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0)) | bitwise_and(1048576) == 0 %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_22_state:
      unique_id: "mu210_403_output_22_state"
      friendly_name: "Балкон розетки состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0)) | bitwise_and(2097152) == 0 %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_23_state:
      unique_id: "mu210_403_output_23_state"
      friendly_name: "Гостиная розетки состояние:"
      value_template: >
        {% if not (states('sensor.mu210_403_bit_mask')|int(0)) | bitwise_and(4194304) == 0 %}
          on
        {% else %}
          off
        {% endif %}

    mu210_403_output_24_state:
      unique_id: "mu210_403_output_24_state"
      friendly_name: "Ванная и прихожая розетки состояние:"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0)) | bitwise_and(8388608) == 0%}
          on
        {% else %}
          off
        {% endif %}
  1. Creating a “yaml” file in the “switches” folder (these are my configurations, so outputs 19-24 are inverted).
Summary
- platform: template
  switches:
    mu210_403_output_1:
      friendly_name: "Ванная свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_1_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_1_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_1_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 1
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 1
          value: 0

    mu210_403_output_2:
      friendly_name: "Ванная подсветка"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_2_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_2_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_2_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 2
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 2
          value: 0

    mu210_403_output_3:
      friendly_name: "Прихожая свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_3_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_3_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_3_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 3
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 3
          value: 0

    mu210_403_output_4:
      friendly_name: "Гардероб свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_4_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_4_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_4_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 4
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 4
          value: 0

    mu210_403_output_5:
      friendly_name: "Коридор подсветка"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_5_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_5_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_5_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 5
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 5
          value: 0

    mu210_403_output_6:
      friendly_name: "Коридор свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_6_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_6_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_6_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 6
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 6
          value: 0

    mu210_403_output_7:
      friendly_name: "Спальня первый свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_7_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_7_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_7_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 7
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 7
          value: 0

    mu210_403_output_8:
      friendly_name: "Спальня второй свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_8_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_8_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_8_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 8
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 8
          value: 0

    mu210_403_output_9:
      friendly_name: "Спальня левый светильник"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_9_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_9_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_9_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 9
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 9
          value: 0

    mu210_403_output_10:
      friendly_name: "Спальня правый светильник"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_10_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_10_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_10_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 10
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 10
          value: 0

    mu210_403_output_11:
      friendly_name: "Тулет свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_11_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_11_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_11_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 11
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 11
          value: 0

    mu210_403_output_12:
      friendly_name: "Туалет подсветка"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_12_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_12_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_12_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 12
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 12
          value: 0

    mu210_403_output_13:
      friendly_name: "Кухня свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_13_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_13_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_13_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 13
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 13
          value: 0

    mu210_403_output_14:
      friendly_name: "Кабинен первый свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_14_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_14_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_14_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 14
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 14
          value: 0

    mu210_403_output_15:
      friendly_name: "Кабинет второй свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_15_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_15_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_15_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 15
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 15
          value: 0

    mu210_403_output_16:
      friendly_name: "Гостиная первый свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_16_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_16_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_16_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 16
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 16
          value: 0

    mu210_403_output_17:
      friendly_name: "Гостиная второй свет"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_17_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_17_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_17_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 17
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 17
          value: 0

    mu210_403_output_18:
      friendly_name: "Гостиная подсветка"
      icon_template: >-
        {% if is_state('sensor.mu210_403_output_18_state', 'on') %}
          mdi:lightbulb
        {% else %}
          mdi:lightbulb-outline
        {% endif %}
      unique_id: "mu210_403_output_18_switch"
      value_template: "{{ is_state('sensor.mu210_403_output_18_state', 'on') }}"
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 18
          value: 1
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 18
          value: 0

    mu210_403_output_19:
      friendly_name: "Вытяжка"
      icon_template: >-
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(262144)) == 0 %}
          mdi:hvac
        {% else %}
          mdi:hvac-off
        {% endif %}
      unique_id: "mu210_403_output_19_switch"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(262144)) == 0 %}
          on
        {% else %}
          off
        {% endif %}
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 19
          value: 0
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 19
          value: 1

    mu210_403_output_20:
      friendly_name: "Спальня вентилятор конвектора"
      icon_template: >-
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(524288)) == 0 %}
          mdi:fan
        {% else %}
          mdi:fan-off
        {% endif %}
      unique_id: "mu210_403_output_20_switch"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(524288)) == 0 %}
          on
        {% else %}
          off
        {% endif %}
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 20
          value: 0
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 20
          value: 1

    mu210_403_output_21:
      friendly_name: "Спальня и гардероб розетки"
      icon_template: >-
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(1048576)) == 0 %}
          mdi:power-socket-eu
        {% else %}
          mdi:power-plug-off
        {% endif %}
      unique_id: "mu210_403_output_21_switch"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(1048576)) == 0 %}
          on
        {% else %}
          off
        {% endif %}
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 21
          value: 0
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 21
          value: 1

    mu210_403_output_22:
      friendly_name: "Балкон розетки"
      icon_template: >-
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(2097152)) == 0 %}
          mdi:power-socket-eu
        {% else %}
          mdi:power-plug-off
        {% endif %}
      unique_id: "mu210_403_output_22_switch"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(2097152)) == 0 %}
          on
        {% else %}
          off
        {% endif %}
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 22
          value: 0
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 22
          value: 1

    mu210_403_output_23:
      friendly_name: "Гостиная розетки"
      icon_template: >-
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(4194304)) == 0 %}
          mdi:power-socket-eu
        {% else %}
          mdi:power-plug-off
        {% endif %}
      unique_id: "mu210_403_output_23_switch"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(4194304)) == 0 %}
          on
        {% else %}
          off
        {% endif %}
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 23
          value: 0
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 23
          value: 1

    mu210_403_output_24:
      friendly_name: "Ванная и прихожая розетки"
      icon_template: >-
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(8388608)) == 0 %}
          mdi:power-socket-eu
        {% else %}
          mdi:power-plug-off
        {% endif %}
      unique_id: "mu210_403_output_24_switch"
      value_template: >
        {% if (states('sensor.mu210_403_bit_mask')|int(0) | bitwise_and(8388608)) == 0 %}
          on
        {% else %}
          off
        {% endif %}
      turn_on:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 24
          value: 0
      turn_off:
        service: shell_command.mu210_403_set_bit
        data:
          bit: 24
          value: 1
  1. Reload Home Assistant

I also connected another MU210-402 module. It has 16 outputs and you need to be careful reading data type Unsigned 32, writing data type Unsigned 16.

shell_command:
  mu210_402_set_bit: "python3 /config/python_scripts/bit_mask_modbus.py u16 192.168.77.7 502 1 470 write {{ bit }} {{ value }}"
- sensor:
    name: mu210_402_bit_mask
    command: "python3 /config/python_scripts/bit_mask_modbus.py u32 192.168.77.7 502 1 468 read | grep 'dec:' | sed -E 's/.*\\(dec: ([0-9]+)\\).*/\\1/'"
    scan_interval: 2
    value_template: "{{ value | int(0) }}"