Мой умный дом уже длительное время работает на промышленном контроллере - стабильно, без сбоев и без привязки к облакам. Но с годами технологии изменились: появились новые беспроводные протоколы, веб-интерфейсы, голосовые ассистенты и гибкие сценарии автоматизации.
Проблема заключалась не в том, что существующая система устарела, а в том, что она уже не позволяла реализовать многие современные сценарии без серьезной переделки. Передо мной стояла задача не заменить работающую систему, а расширить ее возможности, сохранив все то, что доказало свою надежность. Для этого я создал поверх контроллера современный интеграционный слой. А чтобы полностью отказаться от проприетарного ПО, написал собственный OPC-сервер.
В этой статье не только история модернизации моего умного дома, но и попытка показать, какие архитектурные решения, принятые еще в 2011 году, позволили спустя многие годы добавить новые технологии без полной перестройки системы. Надеюсь, этот опыт окажется полезен тем, кто только начинает строить свой умный дом и хочет, чтобы его можно было развивать, а не переделывать через несколько лет.

Сегодня умный дом чаще всего ассоциируется с относительно простой автоматизацией на уровне сценариев и интеграций между готовыми устройствами. В большинстве случаев такой подход строится вокруг готовых экосистем, облачных сервисов и правил формата «если произошло событие А – выполнить действие Б». Это удобно, быстро и зачастую не требует глубоких технических знаний. Однако в 2011 году, когда я проектировал и строил свой умный дом, ситуация выглядела совершенно иначе.

В то время я занимался промышленной автоматизацией: программировал контроллеры, проектировал АСУ ТП (автоматизированные системы управления технологическим процессом) и запускал производственные объекты. Поэтому и к планированию оснащения собственного дома я подошел как к полноценному объекту автоматизации по всем правилам АСУ ТП.
В основу моего умного дома легли:
промышленный контроллер DirectLOGIC DL205;
проводные датчики и исполнительные механизмы;
OPC-сервер для обмена данными;
SCADA-система для визуализации и управления;
централизованная логика управления.
С точки зрения современного подхода в ИТ, такую систему скорее можно сравнить не с набором IoT-устройств (Internet of Things, интернет вещей), а с классической трехуровневой архитектурой приложения, где есть уровни данных, логики и представления.
Спустя 15 лет самое интересное заключается в том, что контроллер, шкаф автоматики и проводная инфраструктура продолжают работать практически без изменений. Зато мир вокруг них изменился полностью.
Появились доступные одноплатные компьютеры (Raspberry/Orange), контейнерная виртуализация (Docker), легкие протоколы обмена сообщениями (MQTT и т.п.), беспроводные сети для устройств умного дома (Zigbee/Wi-Fi), веб-интерфейсы управления, мессенджеры и голосовые помощники. Все это позволяет строить более гибкие и расширяемые системы автоматизации, которые уже не привязаны к одному компьютеру или специализированному программному обеспечению.
В какой-то момент передо мной встала та же задача, которую регулярно решают в ИТ: как модернизировать работающее решение, не разрушив того, что уже хорошо функционирует.
Как строился мой умный дом в 2011 году
Большинство современных технологий в 2011 году либо еще не существовало, либо не было доступно массовому пользователю. Поэтому решение было очевидным - применить подходы, которые я хорошо знал по работе.
Значительная часть оборудования покупалась на интернет-аукционах и была бывшей в употреблении. Для домашнего проекта это был практически единственный способ получить промышленную надежность за разумные деньги.
Основой моей системы стал контроллер DirectLOGIC DL205, максимально доступный на тот момент.
К сожалению, фотографий полностью собранного шкафа автоматики, сделанных в 2011 году, у меня не сохранилось. Тогда умный дом был просто личным проектом, и мысли о том, что спустя 15 лет я буду рассказывать о нем в блоге ЛАНИТ на Хабре, конечно, не возникало.
Поэтому ниже фотография начала сборки шкафа в 2011 году и фотография, сделанная в 2021 году. Поскольку за это время архитектура системы осталась почти без изменений, снимки показывают умный дом в его исходном виде – до начала модернизации.


Архитектуру, какой она была на протяжении десятка лет с 2011 года, я выстроил как типичную для промышленной автоматизации:
контроллер;
OPC-сервер Kepware;
SCADA под Windows;
проводные датчики;
проводные исполнительные механизмы.

На начальном этапе создания умного дома мой бюджет был ограничен, а потому мне удалось реализовать порядка 55 сигналов ввода-вывода. При этом я прекрасно понимал, что этого недостаточно для всех идей, которые хотелось воплотить. Но это был максимум, который я мог себе позволить. Таким образом часть задумок была отложена на будущее, а вся реализация целиком заняла, как оказалось, почти полтора десятилетия.
За это время изменился не дом, а я, ведь в процессе моя профессиональная деятельность сместилась в сторону DevOps. Вместо промышленной автоматизации в моей ежедневной работе появились Linux, Docker, управление инфраструктурой, системы мониторинга и разработки. Постепенно этот опыт и навыки начали находить применение и в собственном проекте умного дома. Стало очевидно, что многие новые идеи для него можно претворить в жизнь, используя знания и современные инструменты из быстро развивающегося мира ИТ.
Что перестало устраивать
Сам контроллер продолжал отлично выполнять свою работу. Шкаф автоматики функционировал без сбоев. Проводная инфраструктура также не вызывала нареканий. Проблема была в другом – хотелось добавить новые функции, которые невозможно было предусмотреть в 2011 году:
дополнительные датчики;
интеграцию с мессенджерами;
веб-интерфейс;
доступ со смартфона;
голосовое управление;
новые сценарии автоматизации.
При этом полностью переделывать существующую систему я не планировал. Наоборот, было желание сохранить надежное промышленное ядро и расширить его возможности современными технологиями, построить новый интеграционный слой.
В процессе модернизации я определил для себя три основные задачи.
1. Перейти от классической SCADA с привязкой к конкретному компьютеру на современный веб-интерфейс управления. Хотелось получить перспективу для управления домом с любого устройства через браузер, а также использовать более гибкую платформу для дальнейшего совершенствования логики и интеграций.
2. Развить возможности умного дома новыми технологиями. Проводная инфраструктура, заложенная на этапе строительства, была надежной, но ее расширение спустя годы стало сложнее. Нужно было обеспечить добавление новых датчиков и устройств без изменения существующей проводки.
3. Перестать зависеть от закрытого программного обеспечения и перейти к кросс-платформенному решению. Существующая связка с OPC-сервером под Windows хорошо выполняла свою задачу, но ограничивала дальнейшее развитие системы. Хотелось получить возможность работать в современной Linux-среде и иметь полную свободу в управлении обменом данными с контроллером. Для решения этих задач я выбрал Raspberry Pi.
Raspberry Pi как интеграционная платформа
Raspberry Pi обладала достаточной производительностью, имела необходимый набор интерфейсов, работала под управлением Linux и, что самое важное, позволяла постепенно расширять возможности умного дома, разворачивая новые сервисы без каких-либо изменений в существующей системе.
При этом эта платформа не заменяла промышленный контроллер. Она стала дополнительным уровнем системы, отвечающим за интеграцию с современными технологиями и выполнение задач, которые в 2011 году было невозможно реализовывать средствами PLC (Programmable Logic Controller, программируемый логический контроллер).

На Raspberry Pi были развернуты ioBroker, MQTT-брокер, Zigbee2MQTT, собственный OPC-сервер и другие сервисы, которые значительно расширили возможности умного дома. Не затрагивая существующую архитектуру они позволили реализовать функции, не предусмотренные на первоначальном этапе создания проекта.

Задача №1. От SCADA к веб-интерфейсу
Первоначально управление умным домом осуществлялось через классическую SCADA-систему. На тот момент этот подход был вполне естественным. Используя встроенные средства SCADA, я самостоятельно разработал мнемосхемы и экраны, которые обеспечивали визуализацию состояния датчиков и исполнительных механизмов, позволяли контролировать оборудование, а также отображали состояние всех подключенных сигналов.

Современные технологии предлагают новую модель работы с системой. Поэтому, как я уже отмечал, вместо привязки к конкретному компьютеру с установленным SCADA-клиентом хотелось получить доступ к умному дому с любого устройства через обычный веб-браузер. Также нужна была возможность легко добавлять новые функции и интеграции. В качестве новой платформы управления я выбрал ioBroker.

Одним из ключевых преимуществ ioBroker для моего проекта стала именно веб-архитектура. Как и требовалось, пользовательский интерфейс больше не зависел от конкретного рабочего места: управлять системой через браузер можно было с компьютера, планшета или смартфона.
Для разработки интерфейса был выбран адаптер VIS-2.0. Это инструмент визуализации ioBroker, который позволяет создавать собственные веб-панели управления. В отличие от классической SCADA-визуализации, где структура экранов обычно определяется архитектурой конкретного проекта, VIS-2.0 дает гибкую возможность выстраивания интерфейса под любые задачи.
Применяя готовые виджеты и дополнительные расширения, можно формировать различные элементы управления: панели состояния, кнопки, графики, индикаторы, отображение показаний датчиков и другие компоненты. Это позволило сделать пользовательскую среду не только функциональной, но и адаптировать ее под удобную эксплуатацию в повседневной жизни.
Кроме этого, ioBroker предоставляет подходящую основу для дальнейшего развития системы: возможность добавлять новые адаптеры, создавать собственные сценарии автоматизации и интегрировать дополнительные сервисы.
Реализовать такой подход мне помог опыт работы в DevOps. Он позволил применить полученные знания на практике: от развертывания ioBroker на Linux до настройки сервисов и создания собственного интерфейса управления в VIS-2.0. При его проектировании также пригодились навыки JavaScript и веб-разработки: я мог создавать более сложные сценарии и адаптировать визуализацию под конкретные задачи умного дома.
В итоге первая цель обновления была решена: умный дом получил современный веб-интерфейс вместо классического SCADA-клиента. При этом существующая архитектура, как и хотелось, не была нарушена: промышленный контроллер DL205 продолжил выполнять свою основную функцию, а ioBroker стал новым уровнем взаимодействия с системой.
Задача №2. Расширение возможностей: как модернизировать дом спустя 15 лет
Следующей задачей стало расширение возможностей умного дома, которые появились с развитием технологий.
На момент создания системы, как вы уже поняли, основой была проводная промышленная автоматизация. Все основные датчики и исполнительные механизмы были подключены к контроллеру, а архитектура была рассчитана на те задачи, которые были актуальны в 2011 году.
Главная сложность заключалась в том, что система умного дома уже была реализована и встроена в готовый жилой объект. На этапе приобретения новостройки, когда квартира еще была без чистовой отделки, я мог заранее заложить необходимую проводную инфраструктуру, проложить кабельные линии и подключить основные датчики и исполнительные механизмы. Спустя годы делать это было бы сложнее, так как пришлось бы нарушать отделку, проводить ремонтные работы или использовать открытую прокладку проводов.
Именно здесь проявилась ценность выбранного подхода, который заключался в том, чтобы не заменять существующую систему, а дополнять ее новыми возможностями.
Появление Zigbee-устройств позволило добавлять новые датчики и исполнительное оборудование без переформатирования существующей проводной инфраструктуры. Благодаря связке Zigbee2MQTT и шлюза Sonoff Zigbee все это органично встроилось в общую архитектуру умного дома.
Но расширение произошло не только на уровне дооснащения. ioBroker предоставил возможность наращивать функции через адаптеры и собственные сценарии автоматизации. Появились JavaScript-сценарии, Node-RED, интеграции с внешними сервисами, уведомления в мессенджеры, управление мультимедийными системами через MPD и другие возможности, которых не было в первоначальной архитектуре.



В итоге спустя почти 15 лет умный дом начал развиваться дальше без переделки существующего промышленного ядра.
Контроллер DL205 продолжил выполнять свою основную задачу – стабильное управление проводными датчиками и исполнительными механизмами, а новый уровень на базе Raspberry Pi и ioBroker позволил добавлять новые технологии, устройства и сценарии, превратив первоначальную систему автоматизации в открытую платформу, способную меняться вместе с появлением перспективных возможностей.
Кстати, такой подход хорошо перекликается с архитектурой, которая давно используется в ИT. В современных приложениях редко все функции реализуются в одном компоненте и есть отдельные уровни: backend, frontend, сервисы интеграции и внешние интерфейсы. Каждый слой выполняет свою задачу и может развиваться независимо. Аналогичный принцип появился и в моем умном доме: промышленный контроллер остался надежным backend для управления оборудованием, а новый слой на базе Raspberry Pi и ioBroker стал платформой для расширения пользовательских функций и интеграций.
Задача №3. Последний шаг к открытой архитектуре: свой OPC-сервер вместо Kepware
После появления ioBroker, MQTT, Docker и Zigbee в системе оставался один компонент, который ограничивал дальнейшее развитие архитектуры.
Это был OPC-сервер Kepware. Сам по себе он отлично выполнял свою функцию: обеспечивал обмен данными между промышленным контроллером DirectLOGIC 205 и системой управления. Однако он оставался единственным элементом, который привязывал всю инфраструктуру к конкретной ОС и коммерческому программному обеспечению.
Хотелось получить полностью открытую архитектуру, где все основные компоненты можно было бы запускать в Linux-окружении и управлять ими самостоятельно. Поэтому я решил разработать собственный OPC-сервер.
Готового решения для Linux найти не удалось. Кроме того, отсутствовала документация по используемому сетевому протоколу обмена данными с контроллером.
Поэтому пришлось использовать подход, который хорошо знаком разработчикам при анализе неизвестных систем: сначала важно понять принципы существующего обмена данными.
Связь между контроллером DirectLOGIC 205 и OPC-сервером Kepware осуществляется по сети Ethernet с использованием UDP-протокола через порт 28784.
Первым этапом стал разбор уже работающего обмена между Kepware и контроллером с помощью Wireshark.

В процессе изучения сетевого обмена стало понятно, что OPC-сервер циклически выполняет определенный набор повторяющихся запросов к контроллеру.
Было выявлено девять основных типов запросов, которые использовались для работы с различными областями памяти DirectLOGIC 205. Каждый тип запроса соответствовал своему диапазону данных контроллера:
Тип запроса |
Область данных |
A |
X |
B |
Y |
C |
C |
D |
T |
E |
CT |
F |
SP |
G |
V |
H |
C расширенная |
I |
V расширенная |
Такой анализ позволил понять не только структуру сетевого обмена, но и логику работы OPC-сервера Kepware: какие области памяти контроллера он опрашивает, каким образом формируются запросы и как полученные данные преобразуются в значения тегов.
После определения типов запросов и структуры пакетов стало возможным реализовать собственный клиент обмена с контроллером на Python.
koyo_opc.py
import asyncio import csv import logging import socket import struct import time from asyncua import ua, Server # --- КОНФИГУРАЦИЯ --- PLC_IP = "АДРЕС_КОНТРОЛЛЕРА" CSV_PATH = "tags.csv" logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s') logging.getLogger("asyncua").setLevel(logging.WARNING) logger = logging.getLogger("KoyoGateway") def crc16_ccitt(data): crc = 0x0000 for byte in data: crc ^= (byte << 8) for _ in range(8): if crc & 0x8000: crc = (crc << 1) ^ 0x1021 else: crc <<= 1 crc &= 0xFFFF return crc class KoyoPLC: def __init__(self, ip): self.ip = ip self.port = 28784 self.sock = None self.lock = asyncio.Lock() self._seq = 0xC2 self.is_online = False self.loop = asyncio.get_event_loop() self._reconnect() def _reconnect(self): if self.sock: self.sock.close() self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.setblocking(False) logger.info(f"Сетевой сокет инициализирован для {self.ip}") async def _safe_recv(self, expected_seq, timeout=0.8): start = time.time() while time.time() - start < timeout: try: data, _ = await asyncio.wait_for(self.loop.sock_recvfrom(self.sock, 2048), timeout=timeout) if len(data) > 3 and data[3] == expected_seq: return data except: await asyncio.sleep(0.01) return None async def _exchange(self, setup, seq, trigger=None): async with self.lock: try: await self.loop.sock_sendto(self.sock, setup, (self.ip, self.port)) if not await self._safe_recv(seq): return None if trigger: await asyncio.sleep(0.01) await self.loop.sock_sendto(self.sock, trigger, (self.ip, self.port)) resp = await self._safe_recv(seq) if resp and resp[9] == 0x22: self.is_online = True return resp[13:] self.is_online = True return True except: self.is_online = False return None def map_address(self, addr_str): addr_str = addr_str.replace('"', '').strip() if addr_str.startswith('V'): parts = addr_str[1:].split('.') return int(parts[0], 8), (int(parts[1]) if len(parts) > 1 else None) prefixes = {'X': (40400, 1), 'Y': (40500, 1), 'C': (40600, 1), 'T': (41100, 1), 'SP': (41200, 2), 'S': (41000, 1)} for pref, (base, plen) in prefixes.items(): if addr_str.startswith(pref): try: idx = int(addr_str[plen:], 8) return int(str(base), 8) + (idx // 16), (idx % 16) except: continue return None, None # --- ОБРАБОТЧИК ЗАПИСИ --- class PLCWriteHandler: def __init__(self, manager): self.manager = manager async def datachange_notification(self, node, val, data): node_id = str(node) if node_id not in self.manager.node_to_meta: return m = self.manager.node_to_meta[node_id] if m['last_val'] == val: return if m['v_dec'] not in self.manager.word_cache: return logger.info(f"ЗАПИСЬ В PLC: {m['name']} -> {val} (Тип: {m['type']})") self.manager.polling_suspended = True try: if m['ua_type'] == ua.VariantType.Boolean: curr_w = self.manager.word_cache[m['v_dec']] state = bool(val) new_w = (curr_w | (1 << m['bit'])) if state else (curr_w & ~(1 << m['bit'])) if await self.manager.write_word_to_plc(m['v_dec'], new_w): self.manager.word_cache[m['v_dec']] = new_w elif m['ua_type'] == ua.VariantType.Float: l, h = struct.unpack('<HH', struct.pack('<f', float(val))) await self.manager.write_word_to_plc(m['v_dec'], l) await self.manager.write_word_to_plc(m['v_dec']+1, h) self.manager.word_cache[m['v_dec']] = l self.manager.word_cache[m['v_dec']+1] = h elif 'BCD' in m['type']: bcd_val = int(str(int(val)), 16) if await self.manager.write_word_to_plc(m['v_dec'], bcd_val): self.manager.word_cache[m['v_dec']] = bcd_val else: if await self.manager.write_word_to_plc(m['v_dec'], int(val)): self.manager.word_cache[m['v_dec']] = int(val) m['last_val'] = val await asyncio.sleep(0.1) finally: self.manager.polling_suspended = False # --- МЕНЕДЖЕР СЕРВЕРА --- class OpcServerManager: def __init__(self, ip_plc, csv_path): self.plc = KoyoPLC(ip_plc) self.csv_path = csv_path self.server = Server() self.node_to_meta = {} self.word_cache = {} self.polling_suspended = False self.idx = 0 async def write_word_to_plc(self, v_dec, value): addr_val = v_dec + 1 v_l, v_h = (int(value) & 0xFF), (int(value) >> 8) & 0xFF payload = bytearray([0x19, 0x00, 0x01, 0x20, 0x02, addr_val & 0xFF, (addr_val >> 8) & 0xFF, 0x31, v_l, v_h]) seq = (self.plc._seq + 1) & 0xFF self.plc._seq = seq packet = bytearray([0x48, 0x41, 0x50, seq, seq ^ 0x10, crc16_ccitt(payload) & 0xFF, (crc16_ccitt(payload) >> 8) & 0xFF, 0x0A, 0x00]) + payload return await self.plc._exchange(packet, seq) async def sync_plc(self): needed = sorted(list(set(w for m in self.node_to_meta.values() for w in m['needed_words']))) if not needed: return idx = 0 while idx < len(needed): curr_start = needed[idx] j = idx while j + 1 < len(needed) and (needed[j+1] - curr_start < 30): j += 1 b_len = needed[j] - curr_start + 1 payload = bytearray([0x19, 0x00, 0x01, 0x1e, b_len*2, (curr_start+1)&0xFF, ((curr_start+1)>>8)&0xFF, 0x31]) setup = bytearray([0x48, 0x41, 0x50, 0x48, 0x58, crc16_ccitt(payload)&0xFF, (crc16_ccitt(payload)>>8)&0xFF, 0x08, 0x00]) + payload trigger = bytearray.fromhex("48415048582e990600201900000000") raw = await self.plc._exchange(setup, 0x48, trigger) if raw: for k in range(len(raw)//2): self.word_cache[curr_start + k] = raw[k*2] | (raw[k*2+1] << 8) idx = j + 1 async def init(self): await self.server.init() self.server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/") self.idx = await self.server.register_namespace("http://koyo.gateway") # 1. Загрузка конфигурации logger.info("Загрузка тегов из CSV...") raw_tags = [] with open(self.csv_path, 'r') as f: reader = csv.reader(f) for row in reader: if not row or row[0].startswith('Tag'): continue v_dec, bit = self.plc.map_address(row[1]) if v_dec is not None: raw_tags.append({'name': row[0], 'addr': row[1], 'type': row[2], 'v_dec': v_dec, 'bit': bit}) # Временные метаданные для первичной синхронизации dummy_id = f"tmp_{row[0]}" self.node_to_meta[dummy_id] = {'v_dec': v_dec, 'needed_words': [v_dec, v_dec+1] if 'Float' in row[2] or 'LBCD' in row[2] else [v_dec]} # 2. Синхронизация с PLC await self.sync_plc() self.node_to_meta.clear() # 3. Создание дерева OPC UA for t in raw_tags: parent = self.server.nodes.objects parts = t['name'].split('.') for part in parts[:-1]: parent = await self.get_or_create_folder(parent, part) # Определение типов на основе t['type'] current_type = t['type'] is_bool = (t['bit'] is not None) or ('Boolean' in current_type) is_float = 'Float' in current_type is_lbcd = 'LBCD' in current_type is_bcd = 'BCD' in current_type and not is_lbcd w1 = self.word_cache.get(t['v_dec'], 0) if is_bool: ua_type = ua.VariantType.Boolean val = bool((w1 >> t['bit']) & 1) if t['bit'] is not None else bool(w1 & 1) elif is_float: ua_type = ua.VariantType.Float w2 = self.word_cache.get(t['v_dec'] + 1, 0) val = struct.unpack('<f', struct.pack('<HH', w1, w2))[0] elif is_lbcd: ua_type = ua.VariantType.Int32 w2 = self.word_cache.get(t['v_dec'] + 1, 0) val = int(f"{w2:04x}{w1:04x}") elif is_bcd: ua_type = ua.VariantType.Int32 val = int(f"{w1:04x}") else: ua_type = ua.VariantType.Int32 val = w1 if w1 <= 32767 else w1 - 65536 tag_node = await parent.add_variable(self.idx, parts[-1], val, varianttype=ua_type) await tag_node.set_writable() self.node_to_meta[str(tag_node)] = { 'node': tag_node, 'v_dec': t['v_dec'], 'bit': t['bit'], 'type': current_type, 'ua_type': ua_type, 'name': t['name'], 'last_val': val, 'needed_words': [t['v_dec'], t['v_dec']+1] if is_float or is_lbcd else [t['v_dec']] } # Включение обработчика записи handler = PLCWriteHandler(self) sub = await self.server.create_subscription(100, handler) await sub.subscribe_data_change([m['node'] for m in self.node_to_meta.values()]) logger.info(f"Сервер готов. Загружено {len(self.node_to_meta)} тегов.") async def get_or_create_folder(self, parent, name): for child in await parent.get_children(): if (await child.read_browse_name()).Name == name: return child return await parent.add_folder(self.idx, name) async def poll_loop(self): while True: if not self.polling_suspended: await self.sync_plc() for m in self.node_to_meta.values(): try: w1 = self.word_cache.get(m['v_dec']) if w1 is None: continue if m['ua_type'] == ua.VariantType.Boolean: val = bool((w1 >> m['bit']) & 1) if m['bit'] is not None else bool(w1 & 1) elif m['ua_type'] == ua.VariantType.Float: w2 = self.word_cache.get(m['v_dec'] + 1, 0) val = struct.unpack('<f', struct.pack('<HH', w1, w2))[0] elif 'LBCD' in m['type']: w2 = self.word_cache.get(m['v_dec'] + 1, 0) val = int(f"{w2:04x}{w1:04x}") elif 'BCD' in m['type']: val = int(f"{w1:04x}") else: val = w1 if w1 <= 32767 else w1 - 65536 m['last_val'] = val await m['node'].write_value(ua.DataValue(ua.Variant(val, m['ua_type']))) except: continue await asyncio.sleep(0.5) async def main(): manager = OpcServerManager(PLC_IP, CSV_PATH) await manager.init() async with manager.server: await manager.poll_loop() if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: pass
Этот скрипт выполняет необходимые для моего проекта операции: устанавливает обмен с контроллером, отправляет запросы, получает ответы, выполняет чтение значений и запись данных в нужные области памяти DirectLOGIC 205. Чтобы он мог работать постоянно в составе новой архитектуры умного дома, Python-скрипт был оформлен как systemd-служба Linux.
koyo-opc.service
[Unit] Description=OPC Server Koyo After=network-online.target Wants=network-online.target [Service] Type=simple User=pi Group=pi WorkingDirectory=/opt/koyo_opc ExecStart=/opt/koyo_opc/venv/bin/python /opt/koyo_opc/koyo_opc.py Restart=always RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target
В результате система окончательно перестала зависеть от Windows и коммерческого OPC-сервера. Контроллер DL205 продолжил работать как надежное промышленное ядро, а программная часть умного дома стала полностью открытой и кросс-платформенной.
Освобождая место для новых идей
После того, как все три задачи были решены, неожиданно проявился еще один приятный эффект – шкаф автоматики начал постепенно избавляться от оборудования, которое когда-то было необходимо, но постепенно устарело.
Одним из таких устройств стал FM-тюнер с усилителем, который многие годы обеспечивал музыкальное сопровождение, например, в ванной комнате. Для своего времени это было вполне рабочее решение, однако оно занимало место в шкафу и ограничивалось только эфирными радиостанциями.
Ему на смену пришла плата Suptronics X400, установленная на Raspberry Pi. В качестве программного обеспечения был выбран Mopidy, работающий в Docker-контейнере.
В результате вместо отдельного аппаратного устройства появился программный сервис. Теперь стали доступны интернет-радио, локальная музыкальная коллекция и возможность управлять воспроизведением через веб-интерфейс ioBroker.
Другим примером стал источник бесперебойного питания (UPS). Раньше для его подключения к системе использовался отдельный преобразователь RS-232 ↔ Ethernet. После модернизации он оказался больше не нужен: взаимодействие с бесперебойником было реализовано программно через SNMP (Simple Network Management Protocol, простой протокол сетевого управления) с использованием соответствующего адаптера ioBroker.
В итоге новая архитектура сделала возможным подобный апгрейд. Теперь там, где раньше потребовалось бы устанавливать отдельное устройство, во многих случаях достаточно развернуть программный сервис или использовать готовый адаптер. Это позволило постепенно уменьшать количество оборудования в шкафу автоматики, сохраняя его функциональность и упрощая дальнейшее развитие системы.
Что получилось в итоге
На первый взгляд может показаться, что за 15 лет умный дом был практически построен заново. Но на самом деле произошло обратное – все, что было хорошо спроектировано в 2011 году, осталось работать.
В результате модернизации удалось:
сохранить промышленный контроллер DirectLOGIC DL205 как основное ядро системы;
сохранить всю проводную инфраструктуру и существующую логику управления;
перейти от классической SCADA к современному веб-интерфейсу;
интегрировать Zigbee-устройства без прокладки новых кабелей;
добавить MQTT, Node-RED, JavaScript-сценарии и другие современные инструменты автоматизации;
реализовать уведомления в мессенджеры и новые пользовательские сценарии;
расширить систему новыми датчиками и исполнительными устройствами;
отказаться от зависимости от Windows и коммерческого программного обеспечения;
заменить OPC-сервер Kepware собственным кросс-платформенным решением на Python;
создать архитектуру, которую можно развивать дальше без переделки существующей системы.
Считаю самым интересным, что за все время модернизации мне не пришлось менять промышленный контроллер или переписывать его программу. Все изменения происходили вокруг него, постепенно расширяя возможности системы и сохраняя ее надежность.
Оглядываясь назад, я понимаю, что главным результатом этой модернизации стали не Zigbee, не веб-интерфейс и даже не собственный OPC-сервер. Самым ценным оказалось то, что умный дом, построенный давно, получил возможность эволюционировать. При этом надеюсь, что через следующие 15 лет мне не придется начинать все с нуля. Но технологии покажут.
Вместо послесловия
В рамках одной статьи невозможно подробно рассказать обо всех этапах создания и модернизации умного дома. За кадром остались схемы подключения, программирование контроллера, отдельные инженерные решения и многие другие технические детали.
Предвосхищая один из самых популярных вопросов: «А были ли проблемы за годы эксплуатации?», поделюсь небольшими наблюдениями.
За все время в проводной части умного дома серьезных бед практически не возникло. Большинство отказов были связаны не с контроллером, а с периферийным оборудованием:
примерно через пять лет вышел из строя блок питания 24 В и был заменен;
еще через несколько лет аналогичная история произошла с блоком питания 12 В;
спустя примерно 10 лет отказал один дискретный выход модуля ввода-вывода, но к счастью, свободные каналы были предусмотрены заранее, поэтому нагрузка была просто перенесена на другой выход;
несколько лет назад начал некорректно работать аналоговый модуль – его также пришлось заменить.
Как я уже не раз отмечал, сам промышленный контроллер все это время продолжает работать без каких-либо сложностей. Не потребовалось ни переписывать программу, ни менять архитектуру системы.
Что касается Raspberry Pi и ioBroker, то срок их эксплуатации пока значительно меньше – около двух-трех лет. За это время единственной неприятностью оказалась нестабильная работа встроенного Wi-Fi модуля. Проблема была решена довольно просто: Raspberry Pi была подключена к сети одновременно по Ethernet и Wi-Fi с объединением интерфейсов в мост, после чего связь стала значительно стабильнее.
Поэтому, если сегодня меня спросят, стал бы я снова строить проводной умный дом на базе промышленного контроллера, мой ответ будет однозначным – да. За 15 лет именно аппаратная часть доказала свою надежность, а современные информационные технологии позволили вдохнуть в нее новую жизнь, не меняя фундамент, который был заложен еще в 2011 году.
Комментарии (12)

NutsUnderline
21.07.2026 07:57занятно, как раз в комментариях к статьям по автоматизации регулярно появляются те кому правильно все автоматизировать на языках iec (без всяких там линуксов, ага, из зачем вообще этот MQTT), изредка - которые не хотят беспроводного, на проводах надежнее. Тут им очень наглядный ответ - все равно придем к малинке на синей изоленте (кстати есть корпуса din для малинок).
кстати современные scada вполне умеют веб-интерфейс, это и можно и совеременно, и графический движок не надо выдумывать

Coder007
21.07.2026 07:57Я сейчас немного отойду в другую сторону от домашней автоматизации, не поймите меня неправильно, но я думаю что это стоит сделать небольшое отступление в сторону пояснений:
Вы знаете, а ведь в языках IEC ничего плохого нет и это как основа автоматизации производства без программного кода. Научить можно кого угодно, это не с языком С и С++ разбираться, да и не каждому это дано. И если промышленность сделала унификацию и включила туда IEC то это не просто так. Представьте так картину, как это происходит сейчас в ИТ: десятки языков, сотни фреймворков, каждый привык писать в том, в чем умеет и хочет. А теперь перенесите это на производство и получим хаос. Нет четкости, везде куча "подпорок" и "костылей", нет чёткой логики и организации процесса управления. И самое печальное что нужна куча разных специалистов/программистов.
И с домашней автоматизацией сейчас происходит та-же картина, куча брендов, у каждого своя архитектура, свое облако (не у всех) и их начинают объединять по разным протоколам, на какой-нибудь Home Assistant. А есть такие, которые не работают напрямую датчиками с HA, поэтому для них ставится свой докер, свой софт, потом интегрируется с HA. Слишком много порой действий, логика вся переносится на программный уровень и работает по правилам Home Assistant. А когда SD карта на малине накрывается, то вся система падает. И ей синяя изолента не поможет, если только отметить что сдохла))) тогда лучше красную.
А что касается применения промышленных ПЛК, так вы посмотрите на Wirenboard (я его не особо уважаю, но как пример - прекрасно). Там все на проводах, классическая структура подключения входов и выходов, достаточно много модулей для различных нужд, но при этом есть и скриптовая логика и поддержка языков IEC и Scada система и многое другое. Это как пример хорошего симбиоза классических промышленных решений и современной инфраструктуры и программного обеспечения.
А что касается малинки, так это совсем не эталон качества и производительности.
И вы правы, есть люди, которые думают что только провода и старые технологии имеют место быть, но имейте ввиду что есть и те, которые считают что только беспроводные технологии, докеры, интеграторы и MQTT могут быть в нашей реальности. Это как вечный спор между стариком и молодым, а истина всегда где-то между. Все зависит от того, что хотим получить, с какой скоростью, с каких объёмах и с каким уровнем опасности/безопасности.
PS: я никогда не доверю перекрытие воды при протечек, системе Home Assistant и беспроводным технологиям, потому что этот процесс при протечке должен быть максимально контролируемым и управляемым на низком уровне. И здесь я доверюсь исключительно проводным решениям и промышленному PLC. Но это моё мнение и я его никому не навязываю, просто делюсь своим опытом.

Alex_Crack
21.07.2026 07:57Согласен, для критичных вещей — только провода.
А почему к WirenBoard предвзято относитесь?
Вот я как раз для себя выбрал WirenBoard. Пока в доме делаю грязные работы (стяжка, штробление и т.п.), все будет на проводах. Купил контроллер и пачку модулей, сижу, экспериментирую и проектирую. На борту опенсорсный Debian. Весь софт тоже открыт и лежит на гитхабе. Связь, опять же, по открытому Modbus.
Всю низкоуровневую логику (управление котлом, насосами, водой, светом, защитой от протечки и т.п.) делаю на самом контроллере в NodeRed, а высокоуровневую логику (сценарии) и интеграции буду делать в HomeAssistant на отдельном сервере.
Coder007
21.07.2026 07:57Я не то что бы предвзято, это как красная тряпка, много читаю статей про умный дом, и там почти везде WirenBoard, я его детально разобрал и был в шоке, если честно. Они его называют промышленным решением, а модули по i2c подключены, и масса ограничений, свойственных этой шине. Ну не тянет он на промышленный, как не крути. Потом - используют rs-485, отлично, хорошее решение, только эти модули ставят в том-же шкафу! И к ним тянут километры проводов! И вот это от проекта к проекту, один в один. От каждого выключателя до модуля дискретного ввода, от каждой лампочки, к модулю дискретного вывода, ну и так далее. Никакой распределенности, всегда тупо один контроллер и обвес внутри шкафа.
Хотя, у них есть классные компактные модули на rs485, которые можно поставить под выключатель (даже если модуль сдохнет, можно заменить на выключатель обычный, с фиксацией).
Но этого не делают. Я задавал много вопросов, и мне отвечают - это классическое решение. Километры проводов, под потолком (или на полу), в однушке, в щит на пол стены. Особенно улыбнули проекты, на 500 - 600 м2, в которых из гаража и из бассейна тащили освещение и управление в центральный щит! Блин, извините, но в 2025-2026 это можно сделать немного лучше. Мы так даже на производстве не делали 20 лет назад. Распределеные системы предполагают наличие нескольких шкафов с ПЛК, узлов, где можно грамотно распределить и нагрузки и управление и в конце концов обезопасить участки. Если один ПЛК тупо дохнет, остальные работают.
А так получается, я могу такую-же как wirenboard систему собрать и на esp32, подрубить по i2c или на spi модули расширения Mcp23017 (их кстати и используют модули DI/DO от Wirenboard) /mcp23s17 и сделать похожее решение. У меня 128 портов ввода вывода будет.
А самое интересное, что логика то будет максимально примитивной и обработается как if - else, ну или case. И ещё, самое главное, мне это все нейронка напишет быстрее, чем я через Web запрограммирую.
Это было во первых, а во вторых, они программируют его просто событиями, сценариями через Web интерфейс. И ни разу я не увидел адекватный код программы (хотя бы FBD на IEC) и понимаю, почему они не ставят несколько ПЛК, почему не связывают между собой, потому что в сценариях, они просто не свяжутся, и придётся городить MQTT брокера и гонять между ним данные.
Он ещё сыроватый и больше напоминает симбиоз между esp32 и Малинкой, в который постарались затолкать все то, что ему пока не нужно. И самое неприятное, что он зависит от Debian, на нем все крутится. Это сильно и отличает Wirenboard от промышленных контроллеров и даже микроконтроллеров. В них есть понятие тактирования, цикла а здесь нет, здесь программа крутится во внешней операционке. Это как Rp2040, когда они дали возможность писать на micro Python и все это подхватили, только код выполнялся медленнее чем на Arduino Nano, дольше и пробематичнее.
Я не говорю что он плохой, нет. Он просто мне не подходит. За много лет (более 30) я видел столько и очень разных и ПЛК и микроконтроллеров и ПЛИС и разных распределены и локальных систем, что wirenboard для меня - это нечто примитивное, медленное, простое, не надёжное и сырое.
А вам какие контроллеры и микроконтроллеры по душе?

Feer41rus
21.07.2026 07:57Доброе время суток!
С удовольствием прочитал данную статью. Спасибо вам за это.
Я сам в молодости читал статьи по автоматизации домов знаменитостей, пытался познакомится с продуктом SCADA, даже подавал заявку на партнёрство. Потом наступило время, когда мог позволить оборудование и делал ремонт, так я познакомился с уже более доступными и простыми устройствами и столкнулся с интересной вещью: что автоматизировать? Как раз на этот вопрос я и ожидал увидеть ответ в предыстории (предусловии) вашей статьи.
После 5 лет жизни в квартире, где автоматизировано не много - пришел к мысли, что многие автоматизируют квартиры и дома, ради общего удовольствия построения системы.
Обдумываю, что же ещё сделать у себя, останавливаюсь каждый раз на списке:
В квартире: очистители, кондиционеры, телевизоры, свет, различные реле для вытяжки (или приточки), теплый топ, контроль протечки и не более..
На даче (или частном доме): системы отопления, системы вытяжки (приточки), управление электропитанием, освещением, контроль подачи и протечки водоснабжения, кондиционеры, автоматизация открытия ворот через голосовой ассистент в навигаторе.
Хотелось бы ссылочку (если есть) или дополнение данной статьи - чтобы понимать, что у вас автоматизировано и как вы используете это в подседней жизни. Как уже написал чуть выше наш коллега (ну или товарищ) - цель дашбордов исключительно контроль систем и выполнение небольших сценарий (перекрыть краны, настройка теплого пола, что тоже можно сделать через голосового ассистента).

Vutshi Автор
21.07.2026 07:57Подробно описать, что именно и как сейчас автоматизировано, в комментарии не получится — это материал как минимум для отдельной статьи. Если коротко, то история моего умного дома началась еще на съемной квартире, когда я впервые столкнулся с признаками работы «домушника». Тогда главной задачей стала охрана: имитация присутствия, тревожная кнопка, контроль проникновения и тп. Следующим этапом стала безопасность - защита от затопления, дыма и пожара. Уже потом появился комфорт: управление освещением, шторами. При проектировании я сразу закладывал возможность климт-контроля, насколько это было реально на тот момент, также мультирум-аудио, управление камерами. Со временем их стало проще улучшить благодаря новым технологиям. Со временем появились и менее очевидные, но очень полезные вещи. Например, контроль энергопотребления помог выявить устройства, работавшие неэффективно, что в итоге позволило сократить расходы на электроэнергию. Мониторинг расхода воды дал меньший экономический эффект, но зато позволяет хорошо понимать, как меняется потребление в течение месяца и быстро замечать аномалии. Прогресс не стоит на месте. То, что сегодня кажется сложным или вовсе невозможным, через несколько лет может стать стандартной функцией. Поэтому при проектировании я старался строить не набор отдельных функций, а платформу, которую можно постепенно развивать и адаптировать под новые технологии

Feer41rus
21.07.2026 07:57Интересно будет почитать статью с вашим устройствами, сценариями. Спасибо за развернутый ответ.

Coder007
21.07.2026 07:57Прекрасная статья, я как будто вернулся в 2000-е, сам с 90-х занимаюсь промышленной автоматизацией и было приятно видеть, что автор сделал на промышленное ПЛК систему автоматизации дома (я не называю такие системы "умный дом", потому как там простые сценарии, банальная логика и дистанционное управление и для меня это не умная система).
Да, решение на момент 2011 года было несомненно отличным (хотя и сейчас я тоже сделаю так-же на проводах, единственное, сделаю систему распределенной, не люблю километры проводов, поэтому буду использовать надёжный промышленный RS-485 для управления и контроля). И сейчас промышленное решение типа PLC - кажется максимально надёжным и удобным (опять же, это мышление нашего поколения, потому как мы видели становление беспроводных технологий, видели их костыли и палки, поэтому доверяем им меньше).
Хотя, если посмотреть на современные решения для "умных домов", то там мало отличий от решений прошлых десятилетий и они очень похожи на промышленные решения (отчасти). Аналогичные модули ввода-вывода, использование Modbus на rs-485, но используется Linux и программное обеспечение.
Согласен с одним из выводов в комментариях, о том, что если старая система выйдет из строя, то все нужно будет переписывать и это создаёт проблемы. Да, несомненно, отказ системы - это проблема, но там и логика как правило описана простая. Там нет PID регуляторов, нет управления динамически процессом и автор сделал все, для того, что бы отказ системы прошел максимально безболезненно. Хотя я считаю что эти PLC, ещё 30 лет отработают без напряга. Единственное, что для расширения количества каналов управления и модулей DI необходимо иметь в наличии дополнительные модули. Ну или при их отсутствии городить новые методы управления и контроля, добавляя новую подсистему.
Ничего не имею против современных решений, протоколов и модулей, сам их использую и они несомненно имеют место быть и будут всегда развиваться, но ничто не сделает систему максимально надёжной, чем датчики и исполнительные устройства на проводах.
Сейчас как раз разрабатываю такую систему которая сочетает в себе возможности шинной, распределенной и в основном проводной топологии (беспроводные решения, IoT, zeegbee и пр. тоже будут, а так-же модули, которые смогут охватить максимум необходимых задач, как для промышленных решений, так и для дома. И естественно, в основе - классика автоматизации - DI, DO, AI, AO, RS-485 (MODBUS). Посмотрим, что из этого получится, но пока все отлично!
Автору спасибо за классную статью, хотелось бы ещё увидеть логику, схемы и прочие решения вашей системы управления домом.

Vutshi Автор
21.07.2026 07:57Спасибо!
Я тоже не считаю свой «умный» дом по-настоящему умным. На мой взгляд, таким он станет тогда, когда значительную часть решений начнет принимать ИИ, исходя из привычек пользователя, контекста и накопленного опыта. Следующий этап развития моей системы вижу именно в этом направлении.
Что касается архитектуры, мне кажется, домашняя автоматизация со временем будет все больше перенимать подходы промышленной автоматизации и в итоге придет к чему-то похожему на связку Raspberry Pi (или аналогичного промышленного компьютера) с CODESYS либо другой PLC-средой исполнения. Надежность и детерминированность останутся, а сама платформа станет более открытой и гибкой.
А про схемы, архитектуру и логику системы... уже несколько человек попросили написать об этом отдельно. Возможно, действительно соберусь с духом и сделаю продолжение статьи. :)

Coder007
21.07.2026 07:57А ещё, когда его дооснастить датчиками, считывающими местоположение хозяина в каждой комнате, с точностью до 10 сантиметров, то можно сделать очень классную логику. А когда дом будет знать, кто перед ним и у него будет файл этого человека (предпочтения, вкусы, цвет глаз, рост и так далее) то он сможет ещё и создавать и предугадывать его действия. Он будет работать по нейроалгоритмам, а не по сценарию.
Я делал такой прикол с обычной LLM Нейросетью, дал ей просто все датчики, лампочки, нагреватель (понятно что виртуально) и потом отправлял пачки состояний (сам генерил) и она мне формировала ряд действий в виде закодированной строки, которую парсим и она работает. Можно добавить датчики, дообучить, и так далее, прикольный опыт. И это уже было похоже на +/- умную систему.
VsBirdEye
Несколько мыслей «на подумать», исходя из собственного опыта запиливания аналогичной системы.
Про интерфейс. Интерфейсы SCADA-систем предназначены для оператора, которому нужно следить за технологическим процессом «сверху» и реагировать на отклонения — там логично наличие общей мнемосхемы с массой деталей. Но и там детали должны «говорить» визуально: всё по плану — или что-то требует внимания.
Домашняя автоматизация нацелена на другое:
а) типовые действия (включить/выключить свет и технику вручную или по сценарию, глянуть температуру);
б) уведомления и реакция на них — датчик протечки, звонок домофона и т.п.
Общую план-схему, где есть «всё», редко использует кто-либо кроме создателя системы. Более того, зрелая домашняя автоматика вообще уезжает в плоскость, где панель почти не нужна: свет работает по расписанию или датчикам движения, домофон открывается из чата или видеозвонка на телефоне, показания счётчиков скрипт сам «сдаёт» на сайт. Панель остаётся инструментом отладки и «пульта на крайний случай».
Замечу, что вы фактически прошли этот путь сами — ушли от SCADA-клиента к вебу, добавили уведомления в мессенджеры и сценарии. Но интерфейс в VIS-2.0, судя по скриншоту, воспроизводит ту же SCADA-парадигму «общей мнемосхемы», только в браузере. Подозреваю, что через пару лет эксплуатации им будете пользоваться в основном вы, и в основном для диагностики. Впрочем, тут промышленный и домашний подходы в итоге сходятся в одной точке: «управление по отклонениям» — система молчит, пока всё хорошо, и активно сигналит, когда что-то не так. К этому же идёт и high-performance HMI в промышленности.
Про оборудование. Общий дрейф идёт в сторону отказа от проприетарщины и закрытых платформ, в которых были зашиты и логика, и интерфейс связи с исполнительными устройствами, — в сторону открытых протоколов и деления системы на взаимозаменяемые элементы. Под каждую шину с устройствами нижнего уровня ставится «по вкусу» шлюз, у которого с другой стороны открытый и задокументированный интерфейс (MQTT и т.п.), а логика взаимодействия переезжает на сторону открытых программных решений.
Ваша история это, кстати, отлично иллюстрирует с обеих сторон. С одной — вам пришлось реверсить недокументированный протокол DL205 через Wireshark, чтобы избавиться от Kepware: закрытый протокол чуть не стал якорем всей системы, и повезло, что он оказался достаточно простым для разбора. С другой — Zigbee2MQTT и ioBroker встали в архитектуру без единой переделки именно потому, что стыкуются через открытые интерфейсы.
Единственное, где я бы с вами поспорил, — центральная логика в PLC. Понимаю аргумент надёжности (15 лет аптайма — веский довод), но цена этого — логика заперта в закрытой платформе с вымирающим инструментарием. Если через 15 лет контроллер всё-таки умрёт, программу придётся не мигрировать, а писать заново — уже на чём-то другом.
Vutshi Автор
Спасибо за такой развернутый комментарий.
Про интерфейс. Для себя я не отказываюсь от общей схемы полностью - просто ее назначение изменилось. Если раньше это был основной способ управления домом, то сейчас это скорее возможность быстро оценить «общую температуру по больнице»: посмотреть, как работает автоматизация в целом, понять, что можно улучшить, найти неисправность или проверить новую функцию. Кроме того, общий экран служит своеобразным чек-листом перед выходом из дома: обратить внимание на важные события, убедиться, что все системы работают штатно. Разумеется, есть и специализированные экраны со статистикой, управлением и настройкой сценариев. Но в целом тенденция действительно такая, как вы описали: все больше взаимодействия происходит без открытия панели, а через автоматические сценарии, уведомления, в перспективе, скорее всего, все будет управляться через голосового помощника.
Про оборудование. Если бы вся бизнес-логика, интеграции и пользовательские сценарии по-прежнему жили в PLC, то это действительно был бы тупиковый путь. Как раз целью модернизации было максимально разгрузить контроллер. Сегодня PLC занимается тем, что у него получается лучше всего - детерминированным управлением дискретными входами и выходами. Все, что связано с интеграциями, интерфейсами, уведомлениями, Zigbee, сценариями высокого уровня и внешними сервисами, уже живет вне него. Понимаю, что однажды PLC все-таки придется заменить. Но благодаря нынешней архитектуре переносить придется только слой низкоуровневой логики ввода-вывода, а не всю экосистему дома. Именно ради этого и затевалась модернизация, чтобы оборудование перестало быть якорем для дальнейшего развития системы.