Created
February 6, 2025 11:55
-
-
Save smirnowegor/b48a4d4c6398f44bc95854ca1a503952 to your computer and use it in GitHub Desktop.
Modbus RTU - Esphome- Home Assistant test code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### Серверная часть на esp32 и тест через Modbus Poll и QModMaster | |
captive_portal: | |
external_components: | |
- source: github://epiclabs-io/esphome-modbus-server@master | |
refresh: 60s | |
components: | |
- modbus_server | |
uart: | |
- id: intmodbus | |
tx_pin: GPIO17 # TX пин на ESP32 | |
rx_pin: GPIO16 # RX пин на ESP32 | |
baud_rate: 9600 | |
stop_bits: 1 | |
data_bits: 8 | |
parity: NONE | |
debug: | |
direction: BOTH # Включаем отладку для TX и RX | |
modbus_server: | |
- id: modbuserver | |
uart_id: intmodbus | |
address: 1 # slave address Адрес устройства, фактически адрес нашего esp | |
holding_registers: | |
- start_address: 200 # Регистр для управления реле | |
number: 1 # Тут больше бы информации | |
on_write: | | |
if(value) | |
id(relay)->turn_on(); | |
else | |
id(relay)->turn_off(); | |
return value; | |
on_read: | | |
return id(relay)->state ? 1 : 0; | |
switch: | |
- platform: gpio | |
pin: GPIO4 | |
id: relay | |
name: "Relay" #Наше реле для управления | |
#### Можно добавить на другой пин еще реле и добавить к текущему. | |
esphome: | |
name: power-meter | |
friendly_name: Power meter | |
esp32: | |
board: esp32dev | |
framework: | |
type: arduino | |
# Enable logging | |
logger: | |
# Enable Home Assistant API | |
api: | |
encryption: | |
key: "nl7CGnDDjFnOHbaiKJAq/CQ7Xa+G+/R/DcWPD0k+Ut4=" | |
ota: | |
- platform: esphome | |
password: "febdc9041f65ed06006278584c81090e" | |
wifi: | |
networks: | |
- ssid: !secret wifi_ssid | |
password: !secret wifi_password | |
- ssid: Esp | |
password: "" | |
# Enable fallback hotspot (captive portal) in case wifi connection fails | |
ap: | |
ssid: "Power-Meter Fallback Hotspot" | |
password: "Y8OgcVDRqqsE" | |
external_components: | |
- source: github://epiclabs-io/esphome-modbus-server@master | |
refresh: 60s | |
components: | |
- modbus_server | |
captive_portal: | |
uart: | |
- id: intmodbus | |
tx_pin: GPIO17 # TX пин на ESP32 | |
rx_pin: GPIO16 # RX пин на ESP32 | |
baud_rate: 9600 | |
stop_bits: 1 | |
data_bits: 8 | |
parity: NONE | |
debug: | |
direction: BOTH # Включаем отладку для TX и RX | |
modbus_server: | |
- id: modbuserver | |
uart_id: intmodbus | |
address: 1 # slave address (адрес устройства) | |
holding_registers: | |
- start_address: 200 # Регистр для управления первым реле (GPIO4) | |
number: 1 | |
on_write: | | |
if(value) | |
id(relay_1)->turn_on(); | |
else | |
id(relay_1)->turn_off(); | |
return value; | |
on_read: | | |
return id(relay_1)->state ? 1 : 0; | |
- start_address: 201 # Регистр для управления вторым реле (GPIO14) | |
number: 1 | |
on_write: | | |
if(value) | |
id(relay_2)->turn_on(); | |
else | |
id(relay_2)->turn_off(); | |
return value; | |
on_read: | | |
return id(relay_2)->state ? 1 : 0; | |
switch: | |
- platform: gpio | |
pin: GPIO4 | |
id: relay_1 | |
name: "Relay 1" # Первое реле | |
- platform: gpio | |
pin: GPIO14 | |
id: relay_2 | |
name: "Relay 2" # Второе реле | |
### Подключаем в качестве теста передачу температуры от рандомного датчика. Сам датчик находится в разделе sensor, а в modbus_server: добавим - start_address: 202 # Register for reading temperature. Смотри в коде. На выходе можем принимать значение. | |
external_components: | |
- source: github://epiclabs-io/esphome-modbus-server@master | |
refresh: 60s | |
components: | |
- modbus_server | |
captive_portal: | |
uart: | |
- id: intmodbus | |
tx_pin: GPIO17 # TX pin on ESP32 | |
rx_pin: GPIO16 # RX pin on ESP32 | |
baud_rate: 9600 | |
stop_bits: 1 | |
data_bits: 8 | |
parity: NONE | |
debug: | |
direction: BOTH # Enable debug for TX and RX | |
modbus_server: | |
- id: modbuserver | |
uart_id: intmodbus | |
address: 1 # slave address | |
holding_registers: | |
- start_address: 200 # Register for controlling relay 1 (GPIO4) | |
number: 1 | |
on_write: | | |
if(value) | |
id(relay_1)->turn_on(); | |
else | |
id(relay_1)->turn_off(); | |
return value; | |
on_read: | | |
return id(relay_1)->state ? 0x0001 : 0x0000; | |
- start_address: 201 # Register for controlling relay 2 (GPIO14) | |
number: 1 | |
on_write: | | |
if(value) | |
id(relay_2)->turn_on(); | |
else | |
id(relay_2)->turn_off(); | |
return value; | |
on_read: | | |
return id(relay_2)->state ? 1 : 0; | |
- start_address: 202 # Register for reading temperature | |
number: 1 | |
on_read: | | |
return id(virtual_temp).state * 10; | |
switch: | |
- platform: gpio | |
pin: GPIO4 | |
id: relay_1 | |
name: "Relay 1" # Первое реле | |
- platform: gpio | |
pin: GPIO14 | |
id: relay_2 | |
name: "Relay 2" # Второе реле | |
sensor: | |
- platform: template | |
id: virtual_temp | |
name: "Virtual Temperature" | |
unit_of_measurement: "C" | |
accuracy_decimals: 1 | |
update_interval: 5s | |
lambda: |- | |
static float temp = 25.0; | |
temp += random(-5, 5) * 0.1; | |
return temp; | |
### Клиент (Мастер) на esp32 | |
captive_portal: | |
uart: | |
- id: modbus_uart | |
tx_pin: GPIO17 | |
rx_pin: GPIO16 | |
baud_rate: 9600 | |
stop_bits: 1 | |
data_bits: 8 | |
parity: NONE | |
debug: | |
direction: BOTH | |
dummy_receiver: false | |
modbus: | |
- id: modbus_client | |
uart_id: modbus_uart | |
# flow_control_pin: | |
# number: GPIO4 | |
# inverted: false #не нужен, так как поток автоматически меняется | |
modbus_controller: | |
- id: modbus_device | |
address: 0x1 | |
modbus_id: modbus_client | |
setup_priority: -10 | |
update_interval: 10s # Опрашивать устройство каждые 10 секунд | |
switch: | |
- platform: modbus_controller | |
modbus_controller_id: modbus_device | |
name: "Relay 1" | |
register_type: holding | |
address: 200 | |
bitmask: 1 | |
use_write_multiple: true | |
lambda: |- | |
if (x) { | |
return 1; | |
} else { | |
return 0; | |
} | |
- platform: modbus_controller | |
modbus_controller_id: modbus_device | |
name: "Relay 2" | |
register_type: holding | |
address: 201 | |
bitmask: 1 | |
use_write_multiple: true | |
lambda: |- | |
if (x) { | |
return 1; | |
} else { | |
return 0; | |
} | |
sensor: | |
- platform: modbus_controller | |
modbus_controller_id: modbus_device | |
name: "Temperature Sensor" | |
register_type: holding | |
address: 202 | |
value_type: U_WORD | |
unit_of_measurement: "°C" | |
accuracy_decimals: 1 | |
filters: | |
- multiply: 0.1 | |
### Клиент Home Assistnat / Сервер kincony_kc868_a16s ( Esp32) - прямая связь Modbus | |
#### В Home Assistant в конфигурации добавил файл с модбасом и сделал ссылку на файл | |
modbus: !include modbus.yaml | |
#### Вот код для Home Assistant | |
- name: kincony_kc868_a16s # Имя устройства в Home Assistant | |
type: serial # Тип подключения (последовательный порт) | |
method: rtu # Метод Modbus (RTU) | |
port: /dev/ttyUSB0 # Путь к устройству USB-RS485 | |
baudrate: 9600 # Скорость передачи данных | |
stopbits: 1 # Количество стоп-битов | |
bytesize: 8 # Размер байта | |
parity: N # Отсутствие контроля четности | |
timeout: 5 # Таймаут ожидания данных | |
delay: 1 # Задержка между запросами | |
switches: # Конфигурация реле | |
- name: "Relay 1" # Имя реле 1 | |
slave: 1 # Адрес устройства (slave) | |
address: 200 # Адрес регистра для управления реле 1 | |
- name: "Relay 2" # Имя реле 2 | |
slave: 1 # Адрес устройства (slave) | |
address: 201 # Адрес регистра для управления реле 2 | |
sensors: | |
- address: 202 # Адрес регистра для температуры | |
input_type: holding # Тип регистра (holding register) | |
name: "Virtual Temperature" # Имя датчика температуры | |
device_class: temperature # Класс устройства (температура) | |
data_type: uint16 # Тип данных (16-битное целое число) | |
scale: 0.1 # Масштабирование данных (например, значение 250 будет интерпретировано как 25.0°C) | |
offset: 0 # Смещение данных (дополнительная коррекция значения) | |
precision: 1 # Точность (количество знаков после запятой) | |
slave: 1 # Адрес устройства (slave) на шине Modbus | |
#### Вот “ответный код” от сервера контроллера. | |
# Внешние компоненты, которые подключаются из репозитория GitHub | |
external_components: | |
- source: github://epiclabs-io/esphome-modbus-server@master # Источник компонента | |
refresh: 60s # Частота обновления компонента | |
components: | |
- modbus_server # Используемый компонент (Modbus-сервер) | |
# Пример конфигурации для ESP32 с использованием I2C | |
i2c: | |
sda: 4 # Пин для данных (SDA) | |
scl: 5 # Пин для тактового сигнала (SCL) | |
scan: true # Автоматическое сканирование устройств на шине I2C | |
id: bus_a # Идентификатор шины I2C | |
# Включение Captive Portal (портала для настройки устройства через Wi-Fi) | |
captive_portal: | |
# Конфигурация для PCF8574 (расширитель портов) | |
pcf8574: | |
- id: 'pcf8574_hub_out_1' # Идентификатор для управления выходами 1-8 | |
address: 0x24 # Адрес устройства на шине I2C | |
# Конфигурация реле (переключателей) | |
switch: | |
- platform: gpio # Использование GPIO для управления реле | |
name: "a16s-output1" # Имя реле 1 | |
pin: | |
pcf8574: pcf8574_hub_out_1 # Использование PCF8574 для управления | |
number: 0 # Номер выхода на PCF8574 | |
mode: OUTPUT # Режим работы (выход) | |
inverted: true # Инверсия сигнала (активный низкий уровень) | |
id: relay_1 # Идентификатор реле 1 | |
- platform: gpio # Второе реле | |
name: "a16s-output2" # Имя реле 2 | |
pin: | |
pcf8574: pcf8574_hub_out_1 # Использование PCF8574 | |
number: 1 # Номер выхода на PCF8574 | |
mode: OUTPUT # Режим работы | |
inverted: true # Инверсия сигнала | |
id: relay_2 # Идентификатор реле 2 | |
# Конфигурация UART для Modbus | |
uart: | |
id: modbus_uart # Идентификатор UART | |
tx_pin: GPIO33 # Пин для передачи данных (TX) на RS485 | |
rx_pin: GPIO32 # Пин для приема данных (RX) на RS485 | |
baud_rate: 9600 # Скорость передачи данных | |
parity: NONE # Отсутствие контроля четности | |
stop_bits: 1 # Количество стоп-битов | |
debug: | |
direction: BOTH # Отладка в обоих направлениях (TX и RX) | |
dummy_receiver: false # Отключение фиктивного приемника | |
# Конфигурация Modbus-сервера | |
modbus_server: | |
id: modbuserver # Идентификатор Modbus-сервера | |
uart_id: modbus_uart # Использование настроенного UART | |
address: 1 # Адрес устройства (slave) на шине Modbus | |
holding_registers: # Регистры для хранения данных | |
- start_address: 200 # Регистр для управления реле 1 (a16s-output1) | |
number: 1 # Количество регистров | |
on_write: |- # Действие при записи в регистр | |
if (value) { | |
id(relay_1).turn_on(); # Включение реле 1 | |
} else { | |
id(relay_1).turn_off(); # Выключение реле 1 | |
} | |
return value; | |
on_read: |- # Действие при чтении регистра | |
return id(relay_1).state ? 0x0001 : 0x0000; # Возврат состояния реле 1 | |
- start_address: 201 # Регистр для управления реле 2 (a16s-output2) | |
number: 1 | |
on_write: |- | |
if (value) { | |
id(relay_2).turn_on(); # Включение реле 2 | |
} else { | |
id(relay_2).turn_off(); # Выключение реле 2 | |
} | |
return value; | |
on_read: |- | |
return id(relay_2).state ? 1 : 0; # Возврат состояния реле 2 | |
- start_address: 202 # Регистр для чтения виртуальной температуры | |
number: 1 | |
on_read: |- | |
return id(virtual_temp).state * 10; # Возврат значения температуры | |
# Конфигурация виртуального датчика температуры | |
sensor: | |
- platform: template # Использование шаблонного датчика | |
id: virtual_temp # Идентификатор датчика | |
name: "Virtual Temperature" # Имя датчика | |
unit_of_measurement: "C" # Единица измерения (градусы Цельсия) | |
accuracy_decimals: 1 # Количество знаков после запятой | |
update_interval: 5s # Интервал обновления данных | |
lambda: |- # Лямбда-функция для генерации данных | |
static float temp = 25.0; # Начальное значение температуры | |
temp += random(-5, 5 | |
#### Если нужно подключить кнопку, вот код для контроллера. | |
# Бинарные сенсоры (входы) | |
binary_sensor: | |
- platform: gpio | |
name: "a16s-input1" # Имя первого входа | |
pin: | |
pcf8574: pcf8574_hub_in_1 # Использование PCF8574 для входа | |
number: 0 # Номер входа на PCF8574 | |
mode: INPUT # Режим работы (вход) | |
inverted: true # Инверсия сигнала (активный низкий уровень) | |
id: input_1 # Идентификатор для использования в Modbus | |
- platform: gpio | |
name: "a16s-input2" # Имя второго входа | |
pin: | |
pcf8574: pcf8574_hub_in_1 # Использование PCF8574 для входа | |
number: 1 # Номер входа на PCF8574 | |
mode: INPUT # Режим работы (вход) | |
inverted: true # Инверсия сигнала | |
id: input_2 # Идентификатор для использования в Modbus | |
#### Модбас настройки для кнопок | |
modbus_server: | |
id: modbuserver | |
uart_id: modbus_uart | |
address: 1 # адрес slave | |
holding_registers: | |
# Регистры для бинарных сенсоров | |
- start_address: 300 # Регистр для состояния входа 1 (a16s-input1) | |
number: 1 | |
on_read: |- | |
return id(input_1).state ? 1 : 0; | |
- start_address: 301 # Регистр для состояния входа 2 (a16s-input2) | |
number: 1 | |
on_read: |- | |
return id(input_2).state ? 1 : 0; | |
#### Для Home Assistant. | |
binary_sensors: # Конфигурация бинарных сенсоров | |
- name: "Input 1" | |
slave: 5 # Адрес slave | |
address: 300 # Адрес регистра для состояния входа 1 | |
input_type: holding # Тип регистра (holding register) | |
device_class: door # Класс устройства (например, door, window, motion) | |
- name: "Input 2" | |
slave: 5 | |
address: 301 # Адрес регистра для состояния входа 2 | |
input_type: holding | |
device_class: window # Пример класса устройства | |
## Цепь Modbus RTU из 4х устройств. | |
#### Мой код для клиента Мастер Home Assistant | |
# Конфигурация для Home Assistant | |
- name: kincony_kc868_a16s # Имя устройства в Home Assistant | |
type: serial # Тип подключения (последовательный порт) | |
method: rtu # Метод Modbus (RTU) | |
port: /dev/ttyUSB0 # Путь к устройству USB-RS485 | |
baudrate: 9600 # Скорость передачи данных | |
stopbits: 1 # Количество стоп-битов | |
bytesize: 8 # Размер байта | |
parity: N # Отсутствие контроля четности | |
timeout: 5 # Таймаут ожидания данных | |
delay: 1 # Задержка между запросами | |
switches: # Конфигурация реле | |
- name: "Relay 1" # Имя реле 1 | |
slave: 5 # Адрес устройства (slave) | |
address: 200 # Адрес регистра для управления реле 1 | |
- name: "Relay 2" # Имя реле 2 | |
slave: 5 # Адрес устройства (slave) | |
address: 201 # Адрес регистра для управления реле 2 | |
- name: "Relay 3" # Имя реле 2 | |
slave: 2 # Адрес устройства (slave) | |
address: 0x0000 # Адрес регистра для управления реле Стандартное модбас-устройство (slave 1) | |
write_type: coil | |
- name: "Relay 4" # Имя реле 2 | |
slave: 3 # Адрес устройства (slave) | |
address: 210 # Адрес регистра для управления реле На ESP32 | |
sensors: # Конфигурация датчиков | |
- address: 202 | |
input_type: holding | |
name: "Kincony Virtual Temperature" | |
data_type: int16 # Исправлено с uint16 | |
scale: 0.1 | |
slave: 5 | |
- address: 220 # Новый регистр для ustroistvo-3 | |
input_type: holding | |
name: "Ustroistvo-3 Virtual Temperature" | |
data_type: int16 | |
scale: 0.1 | |
slave: 3 # Адрес Slave 3 | |
binary_sensors: # Конфигурация бинарных сенсоров | |
- name: "Input 1" | |
slave: 5 # Адрес slave | |
address: 300 # Адрес регистра для состояния входа 1 | |
input_type: holding # Тип регистра (holding register) | |
device_class: door # Класс устройства (например, door, window, motion) | |
- name: "Input 2" | |
slave: 5 | |
address: 301 # Адрес регистра для состояния входа 2 | |
input_type: holding | |
device_class: window # Пример класса устройства | |
#### мой код для Сервер 1 это ESP32 с реле и виртуальным датчиком | |
external_components: | |
- source: github://epiclabs-io/esphome-modbus-server@master | |
refresh: 60s | |
uart: | |
id: modbus_uart2 | |
tx_pin: GPIO17 | |
rx_pin: GPIO16 | |
baud_rate: 9600 | |
parity: NONE | |
stop_bits: 1 | |
debug: | |
direction: BOTH | |
dummy_receiver: false | |
modbus_server: | |
id: modbuserver2 | |
uart_id: modbus_uart2 | |
address: 3 # Новый адрес для данного устройства (slave 2) | |
holding_registers: | |
- start_address: 210 # Регистр управления реле (можно выбрать любой свободный адрес) | |
number: 1 | |
on_write: |- | |
if (value) { | |
id(relay_gpio4).turn_on(); | |
} else { | |
id(relay_gpio4).turn_off(); | |
} | |
return value; | |
on_read: |- | |
return id(relay_gpio4).state ? 1 : 0; | |
# В раздел modbus_server добавляем новый регистр: | |
- start_address: 220 # Новый регистр для температуры | |
number: 1 | |
on_read: |- | |
return id(virtual_temp_ustroistvo3).state * 10; | |
# Управление реле напрямую через GPIO | |
switch: | |
- platform: gpio | |
name: "ESP32 Relay on GPIO4" | |
pin: GPIO4 | |
id: relay_gpio4 | |
# В раздел sensor добавляем: | |
sensor: | |
- platform: template | |
id: virtual_temp_ustroistvo3 | |
name: "Virtual Temperature Ustroistvo-3" | |
unit_of_measurement: "°C" | |
accuracy_decimals: 1 | |
update_interval: 5s | |
lambda: |- | |
return 25.0 + random(-5, 5) * 0.1; | |
#### Мой код Сервер 3 это kincony kc868 a16s со встроенным rs485 на котором настроено 2 реле и виртуальный датчик. | |
captive_portal: | |
external_components: | |
- source: github://epiclabs-io/esphome-modbus-server@master | |
refresh: 60s | |
components: | |
- modbus_server | |
i2c: | |
sda: 4 | |
scl: 5 | |
scan: true | |
id: bus_a | |
pcf8574: | |
- id: 'pcf8574_hub_out_1' # for output channel 1-8 | |
address: 0x24 | |
- id: 'pcf8574_hub_out_2' # для выходов 9-16 | |
address: 0x25 | |
- id: 'pcf8574_hub_in_1' # для входов 1-8 | |
address: 0x22 | |
- id: 'pcf8574_hub_in_2' # для входов 9-16 | |
address: 0x23 | |
switch: | |
- platform: gpio | |
name: "a16s-output1" | |
pin: | |
pcf8574: pcf8574_hub_out_1 | |
number: 0 | |
mode: OUTPUT | |
inverted: true | |
id: relay_1 | |
- platform: gpio | |
name: "a16s-output2" | |
pin: | |
pcf8574: pcf8574_hub_out_1 | |
number: 1 | |
mode: OUTPUT | |
inverted: true | |
id: relay_2 | |
binary_sensor: | |
- platform: gpio | |
name: "a16s-input1" | |
id: input_1 | |
pin: | |
pcf8574: pcf8574_hub_in_1 | |
number: 0 | |
mode: INPUT | |
inverted: true | |
on_press: | |
- switch.toggle: relay_1 | |
on_state: | |
then: | |
- lambda: |- | |
id(modbuserver).add_holding_register(300, x ? 1 : 0); | |
- platform: gpio | |
name: "a16s-input2" | |
id: input_2 | |
pin: | |
pcf8574: pcf8574_hub_in_1 | |
number: 1 | |
mode: INPUT | |
inverted: true | |
on_press: | |
- switch.toggle: relay_2 | |
on_state: | |
then: | |
- lambda: |- | |
id(modbuserver).add_holding_register(301, x ? 1 : 0); | |
uart: | |
id: modbus_uart | |
tx_pin: GPIO33 # RS485-TX на KinCony KC868-A16S | |
rx_pin: GPIO32 # RS485-RX на KinCony KC868-A16S | |
baud_rate: 9600 | |
parity: NONE | |
stop_bits: 1 | |
debug: | |
direction: BOTH | |
dummy_receiver: false | |
modbus_server: | |
id: modbuserver | |
uart_id: modbus_uart | |
address: 5 # адрес slave | |
holding_registers: | |
- start_address: 200 # Регистр для управления реле 1 (a16s-output1) | |
number: 1 | |
on_write: |- | |
if (value) { | |
id(relay_1).turn_on(); | |
} else { | |
id(relay_1).turn_off(); | |
} | |
return value; | |
on_read: |- | |
return id(relay_1).state ? 0x0001 : 0x0000; | |
- start_address: 201 # Регистр для управления реле 2 (a16s-output2) | |
number: 1 | |
on_write: |- | |
if (value) { | |
id(relay_2).turn_on(); | |
} else { | |
id(relay_2).turn_off(); | |
} | |
return value; | |
on_read: |- | |
return id(relay_2).state ? 1 : 0; | |
- start_address: 202 # Регистр для чтения температуры | |
number: 1 | |
on_read: |- | |
return id(virtual_temp).state * 10; | |
- start_address: 300 # Регистр для состояния входа 1 (a16s-input1) | |
number: 1 | |
on_read: |- | |
return id(input_1).state ? 1 : 0; | |
- start_address: 301 # Регистр для состояния входа 2 (a16s-input2) | |
number: 1 | |
on_read: |- | |
return id(input_2).state ? 1 : 0; | |
sensor: | |
- platform: template | |
id: virtual_temp | |
name: "Virtual Temperature" | |
unit_of_measurement: "°C" | |
accuracy_decimals: 1 | |
update_interval: 5s | |
lambda: |- | |
return 25.0 + random(-5, 5) * 0.1; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment