
Въведение
В тази статия ще разгледаме подробно как да управляваме устройствата HHC N8I8OP чрез MQTT протокол, използвайки написаната от нас Python библиотеката HHC_N8I8OP_Controller за тяхното управление. Устройствата HHC N8I8OP са модули за цифров вход и изход, които се използват за управление на релета и мониторинг на цифрови сигнали. Те са широко използвани в системи за автоматизация, IoT проекти и индустриални приложения.
Кодът, който ще разгледаме, използва MQTT за комуникация с устройствата, което позволява лесно интегриране в съществуващи IoT системи. MQTT е лек протокол за обмен на съобщения, който е идеален за устройства с ограничени ресурси и мрежи с ниска пропускателна способност.
В статията ще предоставим пълно обяснение на кода, включително настройка на MQTT брокера, използваните библиотеки, функциите и променливите, както и инструкции за конфигуриране и използване на MQTT панела. Освен това ще предоставим команди за Linux, които могат да се използват за четене и писане в MQTT.
Използвани ресурси за проекта
Нека да продължим напред с конфигурацията на HHC_N8I8OP контролера. Софтуера, както и обяснението за това може да намерите в ревюто ни за него:
Преди да започнем с този проект, нека първо да разберем как се инсталира MQTT брокер на Raspberry Pi и Orange Pi, както и да свалим библиотеката за комуникация с HHC_N8I8OP контролера. Всичко това може да научите в статиите ни:
- Инсталиране на Mosquitto MQTT Broker на Raspberry Pi 4
- Инсталиране Mosquitto MQTT Broker на Orange Pi Plus 2 и Armbian Linux
- Управление на HHC-N8I8OP с Raspberry Pi и Python: Библиотека, код и обяснение
Код на HHC N8I8OP управление чрез MQTT
import paho.mqtt.client as mqtt
import time
import socket
import threading
from HHC_N8I8OP_Controller import HHC_N8I8OP_Controller
# Конфигурация на MQTT
MQTT_BROKER = "localhost" # Ако не е на машината на която е MQTT брокера, заменете с IP адреса на MQTT брокера.
MQTT_PORT = 1883
MQTT_USERNAME = "xxxxxxxx" # Заменете с вашия username на MQTT брокера
MQTT_PASSWORD = "xxxxxxxx" # Заменете с вашата парола на MQTT брокера
# Интервали за изчитане (в секунди)
DIGITAL_READ_RELAYS = 2 # 3 е време на изчитане в секунди
DIGITAL_READ_INPUTS = 1 # 5 е време на изчитане в секунди
# Списък с контролери (IP адреси)
CONTROLLERS = ["192.168.1.96", "192.168.1.95"]
controllers = {ip: HHC_N8I8OP_Controller(ip) for ip in CONTROLLERS}
# Заключване за синхронизация на изхода в конзолата
print_lock = threading.Lock()
def is_device_active(ip, port=5000):
""" Проверява дали устройството е достъпно. """
try:
with socket.create_connection((ip, port), timeout=2):
return True
except (socket.timeout, ConnectionRefusedError, OSError) as e:
with print_lock:
print(f"Грешка при свързване с {ip}: {e}")
return False
def on_connect(client, userdata, flags, rc):
with print_lock:
print("Свързан към MQTT брокера")
for ip in CONTROLLERS:
for i in range(1, 9): # Абониране за relay1 до relay8
client.subscribe(f"hhc_n8i8op/{ip}/relay/{i}/set")
def on_message(client, userdata, msg):
parts = msg.topic.split("/")
if len(parts) == 5:
ip, relay = parts[1], parts[3]
payload = msg.payload.decode().upper()
if ip in controllers and is_device_active(ip):
relay_number = int(relay.replace("relay", ""))
state = 1 if payload == "ON" else 0
response = controllers[ip].digitalWrite(relay_number, state)
with print_lock:
print(f"{ip} - {relay}: {payload} -> {response}")
else:
with print_lock:
print(f"Устройството {ip} не е достъпно")
else:
with print_lock:
print(f"Невалиден topic: {msg.topic}")
def publish_relay_states(client, interval):
while True:
for ip, controller in controllers.items():
if is_device_active(ip):
for i in range(1, 9):
try:
state = controller.readRelay(i) # Връща "1" или "0"
topic = f"hhc_n8i8op/{ip}/status/relay/{i}"
client.publish(topic, state, qos=1, retain=True)
with print_lock:
print(f"Публикувано: {topic} -> {state}")
except Exception as e:
with print_lock:
print(f"Грешка при четене на реле {i} от {ip}: {e}")
time.sleep(interval)
def publish_input_states(client, interval):
while True:
for ip, controller in controllers.items():
if is_device_active(ip):
for i in range(1, 9):
try:
state = controller.readInputChannel(i) # Връща "1" или "0"
topic = f"hhc_n8i8op/{ip}/status/input/{i}"
client.publish(topic, state, qos=1, retain=True)
with print_lock:
print(f"Публикувано: {topic} -> {state}")
except Exception as e:
with print_lock:
print(f"Грешка при четене на вход {i} от {ip}: {e}")
time.sleep(interval)
client = mqtt.Client()
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_BROKER, MQTT_PORT, 60)
client.loop_start()
relay_thread = threading.Thread(target=publish_relay_states, args=(client, DIGITAL_READ_RELAYS), daemon=True)
input_thread = threading.Thread(target=publish_input_states, args=(client, DIGITAL_READ_INPUTS), daemon=True)
relay_thread.start()
input_thread.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
with print_lock:
print("Изключване...")
client.loop_stop()
client.disconnect()
relay_thread.join(timeout=1)
input_thread.join(timeout=1)
Подробно обяснение на кода за управление на HHC N8I8OP чрез MQTT
Преди да продължим с обяснението на кода нека ви покажем кратко видео от проекта.
Импортиране на библиотеки
import paho.mqtt.client as mqtt
import time
import socket
import threading
from HHC_N8I8OP_Controller import HHC_N8I8OP_Controller
- paho.mqtt.client: Тази библиотека предоставя функционалност за работа с MQTT протокол. Тя позволява създаване на MQTT клиенти, които могат да се свързват с MQTT брокер и да изпращат/получават съобщения.
- time: Библиотеката
time
се използва за работа с времеви интервали, като например изчакване за определен период от време. - socket: Библиотеката
socket
се използва за мрежова комуникация. Тя позволява проверка на активността на устройствата чрез TCP връзки. - threading: Тази библиотека се използва за създаване и управление на нишки, което позволява паралелно изпълнение на различни задачи.
- HHC_N8I8OP_Controller: Това е потребителска библиотека, специално разработена от нас за управление на устройствата HHC N8I8OP. Тя предоставя методи за четене и запис на цифрови входове и изходи.
Конфигурация на MQTT
# Конфигурация на MQTT
MQTT_BROKER = "localhost" # Ако не е на машината на която е MQTT брокера, заменете с IP адреса на MQTT брокера.
MQTT_PORT = 1883
MQTT_USERNAME = "xxxxxxxx" # Заменете с вашия username на MQTT брокера
MQTT_PASSWORD = "xxxxxxxx" # Заменете с вашата парола на MQTT брокера
- MQTT_BROKER: Това е адресът на MQTT брокера. В този случай,
localhost
означава, че брокерът е на същата машина, от която се изпълнява кодът. Ако не е на машината на която е MQTT брокера, заменете с IP адреса на MQTT брокера. - MQTT_PORT: Портът, на който MQTT брокерът слуша. Стандартният порт за MQTT е 1883.
- MQTT_USERNAME и MQTT_PASSWORD: Това са потребителското име и паролата за достъп до MQTT брокера. Те се използват за автентикация.
Интервали за изчитане
# Интервали за изчитане (в секунди)
DIGITAL_READ_RELAYS = 2 # 3 е време на изчитане в секунди
DIGITAL_READ_INPUTS = 1 # 5 е време на изчитане в секунди
- DIGITAL_READ_RELAYS: Това е интервалът в секунди, на който се извършва проверка на състоянието на релетата. В този случай, проверката се извършва на всеки 2 секунди.
- DIGITAL_READ_INPUTS: Това е интервалът в секунди, на който се извършва проверка на състоянието на цифровите входове. В този случай, проверката се извършва на всеки 1 секунда.
Списък с контролери
# Списък с контролери (IP адреси)
CONTROLLERS = ["192.168.1.96", "192.168.1.95"]
controllers = {ip: HHC_N8I8OP_Controller(ip) for ip in CONTROLLERS}
- CONTROLLERS: Това е списък с IP адресите на устройствата HHC N8I8OP, които ще бъдат управлявани.
- controllers: Това е речник, който съдържа инстанции на
HHC_N8I8OP_Controller
за всяко устройство. Ключовете са IP адресите, а стойностите са обектите за управление на устройствата.
Заключване за синхронизация
# Заключване за синхронизация на изхода в конзолата
print_lock = threading.Lock()
- print_lock: Това е обект за заключване, който се използва за синхронизация на изхода в конзолата. Той гарантира, че само една нишка може да извежда информация в конзолата в даден момент, което предотвратява преплитане на изхода.
Функция за проверка на активността на устройството
def is_device_active(ip, port=5000):
""" Проверява дали устройството е достъпно. """
try:
with socket.create_connection((ip, port), timeout=2):
return True
except (socket.timeout, ConnectionRefusedError, OSError) as e:
with print_lock:
print(f"Грешка при свързване с {ip}: {e}")
return False
- is_device_active(ip, port=5000): Тази функция проверява дали устройството с дадения IP адрес е достъпно чрез опит за създаване на TCP връзка на порт 5000. Ако връзката е успешна, функцията връща
True
, в противен случай връщаFalse
и извежда съобщение за грешка.
Функция за свързване към MQTT брокера
def on_connect(client, userdata, flags, rc):
with print_lock:
print("Свързан към MQTT брокера")
for ip in CONTROLLERS:
for i in range(1, 9): # Абониране за relay1 до relay8
client.subscribe(f"hhc_n8i8op/{ip}/relay/{i}/set")
- on_connect(client, userdata, flags, rc): Тази функция се извиква, когато клиентът се свърже успешно с MQTT брокера. Тя абонира клиента за topics, които се използват за управление на релетата на всяко устройство.
Функция за обработка на MQTT съобщения
def on_message(client, userdata, msg):
parts = msg.topic.split("/")
if len(parts) == 5:
ip, relay = parts[1], parts[3]
payload = msg.payload.decode().upper()
if ip in controllers and is_device_active(ip):
relay_number = int(relay.replace("relay", ""))
state = 1 if payload == "ON" else 0
response = controllers[ip].digitalWrite(relay_number, state)
with print_lock:
print(f"{ip} - {relay}: {payload} -> {response}")
else:
with print_lock:
print(f"Устройството {ip} не е достъпно")
else:
with print_lock:
print(f"Невалиден topic: {msg.topic}")
- on_message(client, userdata, msg): Тази функция се извиква, когато клиентът получи съобщение от MQTT брокера. Тя обработва съобщенията, които са предназначени за управление на релетата. Ако съобщението е валидно, то се изпраща към съответното устройство, за да се промени състоянието на релето.
Функция за публикуване на състоянието на релетата
def publish_relay_states(client, interval):
while True:
for ip, controller in controllers.items():
if is_device_active(ip):
for i in range(1, 9):
try:
state = controller.readRelay(i) # Връща "1" или "0"
topic = f"hhc_n8i8op/{ip}/status/relay/{i}"
client.publish(topic, state, qos=1, retain=True)
with print_lock:
print(f"Публикувано: {topic} -> {state}")
except Exception as e:
with print_lock:
print(f"Грешка при четене на реле {i} от {ip}: {e}")
time.sleep(interval)
- publish_relay_states(client, interval): Тази функция публикува състоянието на релетата на определен интервал. Тя чете състоянието на всяко реле от всяко устройство и го публикува в съответния MQTT topic.
Функция за публикуване на състоянието на входовете
def publish_input_states(client, interval):
while True:
for ip, controller in controllers.items():
if is_device_active(ip):
for i in range(1, 9):
try:
state = controller.readInputChannel(i) # Връща "1" или "0"
topic = f"hhc_n8i8op/{ip}/status/input/{i}"
client.publish(topic, state, qos=1, retain=True)
with print_lock:
print(f"Публикувано: {topic} -> {state}")
except Exception as e:
with print_lock:
print(f"Грешка при четене на вход {i} от {ip}: {e}")
time.sleep(interval)
- publish_input_states(client, interval): Тази функция публикува състоянието на цифровите входове на определен интервал. Тя чете състоянието на всеки вход от всяко устройство и го публикува в съответния MQTT topic.
Основна част на кода за управление на HHC N8I8OP през MQTT
client = mqtt.Client()
client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD)
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_BROKER, MQTT_PORT, 60)
client.loop_start()
relay_thread = threading.Thread(target=publish_relay_states, args=(client, DIGITAL_READ_RELAYS), daemon=True)
input_thread = threading.Thread(target=publish_input_states, args=(client, DIGITAL_READ_INPUTS), daemon=True)
relay_thread.start()
input_thread.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
with print_lock:
print("Изключване...")
client.loop_stop()
client.disconnect()
relay_thread.join(timeout=1)
input_thread.join(timeout=1)
- client = mqtt.Client(): Създаване на MQTT клиент.
- client.username_pw_set(MQTT_USERNAME, MQTT_PASSWORD): Задаване на потребителско име и парола за MQTT брокера.
- client.on_connect = on_connect: Задаване на функцията, която се извиква при успешно свързване към MQTT брокера.
- client.on_message = on_message: Задаване на функцията, която се извиква при получаване на съобщение от MQTT брокера.
- client.connect(MQTT_BROKER, MQTT_PORT, 60): Свързване към MQTT брокера.
- client.loop_start(): Стартиране на MQTT клиента в отделна нишка.
- relay_thread и input_thread: Създаване и стартиране на нишки за публикуване на състоянието на релетата и входовете.
- try-except блок: Основен цикъл, който работи, докато не бъде прекъснат от потребителя. При прекъсване, клиентът се изключва и нишките се спират.
MQTT Topics и Payload за конфигуриране на MQTT панел
Topics
- hhc_n8i8op/{ip}/relay/{i}/set: Topic за задаване на състоянието на реле.
- hhc_n8i8op/{ip}/status/relay/{i}: Topic за публикуване на състоянието на реле.
- hhc_n8i8op/{ip}/status/input/{i}: Topic за публикуване на състоянието на вход.
Payload
- ON: Задава релето в състояние “включено”.
- OFF: Задава релето в състояние “изключено”.
- 1: Състояние “включено”.
- 0: Състояние “изключено”.
Примери за MQTT Topics и Payload
1. Topic за задаване на състоянието на реле:
- Topic:
hhc_n8i8op/192.168.1.96/relay/1/set
- Payload:
ON
- Обяснение: Този payload задава реле 1 на устройството с IP
192.168.1.96
в състояние “включено“.
- Обяснение: Този payload задава реле 1 на устройството с IP
- Payload:
OFF
- Обяснение: Този payload задава реле 1 на устройството с IP
192.168.1.96
в състояние “изключено“.
- Обяснение: Този payload задава реле 1 на устройството с IP
2. Topic за публикуване на състоянието на реле:
- Topic:
hhc_n8i8op/192.168.1.96/status/relay/1
- Payload:
1
- Обяснение: Този payload показва, че реле 1 на устройството с IP
192.168.1.96
е в състояние “включено“.
- Обяснение: Този payload показва, че реле 1 на устройството с IP
- Payload:
0
- Обяснение: Този payload показва, че реле 1 на устройството с IP
192.168.1.96
е в състояние “изключено“.
- Обяснение: Този payload показва, че реле 1 на устройството с IP
3. Topic за публикуване на състоянието на вход:
- Topic:
hhc_n8i8op/192.168.1.96/status/input/1
- Payload:
1
- Обяснение: Този payload показва, че вход 1 на устройството с IP
192.168.1.96
е в състояние “активен” (високо ниво).
- Обяснение: Този payload показва, че вход 1 на устройството с IP
- Payload:
0
- Обяснение: Този payload показва, че вход 1 на устройството с IP
192.168.1.96
е в състояние “неактивен” (ниско ниво).
- Обяснение: Този payload показва, че вход 1 на устройството с IP
Допълнителни примери:
Пример 1: Задаване на състоянието на реле 3 на устройство с IP 192.168.1.95
- Topic:
hhc_n8i8op/192.168.1.95/relay/3/set
- Payload:
ON
- Обяснение: Реле 3 на устройството с IP
192.168.1.95
ще бъде включено.
- Обяснение: Реле 3 на устройството с IP
Пример 2: Публикуване на състоянието на реле 5 на устройство с IP 192.168.1.96
- Topic:
hhc_n8i8op/192.168.1.96/status/relay/5
- Payload:
0
- Обяснение: Реле 5 на устройството с IP
192.168.1.96
е изключено.
- Обяснение: Реле 5 на устройството с IP
Пример 3: Публикуване на състоянието на вход 2 на устройство с IP 192.168.1.95
Обяснение: Вход 2 на устройството с IP 192.168.1.95
е активен (високо ниво).
Topic: hhc_n8i8op/192.168.1.95/status/input/2
- Payload:
1
- Обяснение: Вход 2 на устройството с IP
192.168.1.95
е активен (високо ниво).
- Обяснение: Вход 2 на устройството с IP
Команди за Linux на проекта
Четене от MQTT
mosquitto_sub -h localhost -t "hhc_n8i8op/+/status/#" -u xxxxxxxx -P xxxxxxxx
- mosquitto_sub: Команда за абониране за MQTT topics.
- -h localhost: Указва хоста на MQTT брокера.
- -t “hhc_n8i8op/+/status/#”: Указва topics, за които да се абонира. Символът
+
е заместващ за всякаква стойност, а#
е заместващ за всички под –topics. - -u xxxxxxxxx: Потребителско име за MQTT брокера.
- -P xxxxxxxxx: Парола за MQTT брокера.
Писане в MQTT
mosquitto_pub -h localhost -t "hhc_n8i8op/192.168.1.96/relay/1/set" -m "ON" -u xxxxxxxx -P xxxxxxxx
- mosquitto_pub: Команда за публикуване на MQTT съобщение.
- -h localhost: Указва хоста на MQTT брокера.
- -t “hhc_n8i8op/192.168.1.96/relay/1/set”: Указва topic, към който да се публикува съобщението.
- -m “ON”: Съобщението, което да се публикува.
- -u xxxxxxxx: Потребителско име за MQTT брокера.
- -P xxxxxxxx: Парола за MQTT брокера.
Примери за Linux команди за управление и мониторинг на устройствата HHC N8I8OP чрез MQTT
1. Команда за изчитане на състоянието на всички релета и входове:
mosquitto_sub -h localhost -t "hhc_n8i8op/+/status/#" -u xxxxxxxx -P xxxxxxxx
- Тази команда се абонира за всички topics, които съдържат информация за състоянието на релетата и входовете на всички устройства HHC N8I8OP.
- Примерен изход:
hhc_n8i8op/192.168.1.96/status/relay/1 1
hhc_n8i8op/192.168.1.96/status/relay/2 0
hhc_n8i8op/192.168.1.96/status/input/1 1
hhc_n8i8op/192.168.1.96/status/input/2 0
Този изход показва, че:
- Реле 1 на устройството с IP
192.168.1.96
е включено (1
). - Реле 2 на устройството с IP
192.168.1.96
е изключено (0
). - Вход 1 на устройството с IP
192.168.1.96
е активен (1
). - Вход 2 на устройството с IP
192.168.1.96
е неактивен (0
).
2. Команда за задаване на състоянието на реле:
mosquitto_pub -h localhost -t "hhc_n8i8op/192.168.1.96/relay/1/set" -m "ON" -u xxxxxxxx -P xxxxxxxx
- Тази команда задава реле 1 на устройството с IP
192.168.1.96
в състояние “включено“. - Payload:
ON
задава релето да се включи. - Ако искате да изключите релето, използвайте payload
OFF
:
mosquitto_pub -h localhost -t "hhc_n8i8op/192.168.1.96/relay/1/set" -m "OFF" -u xxxxxxxx -P xxxxxxxx
3. Команда за изчитане на състоянието на конкретно реле:
mosquitto_sub -h localhost -t "hhc_n8i8op/192.168.1.96/status/relay/1" -u xxxxxxxx -P xxxxxxxx
- Тази команда се абонира за topic, който съдържа информация за състоянието на реле 1 на устройството с IP
192.168.1.96
. - Примерен изход:
hhc_n8i8op/192.168.1.96/status/relay/1 1
- Този изход показва, че реле 1 е включено (
1
).
4. Команда за изчитане на състоянието на конкретен вход:
mosquitto_sub -h localhost -t "hhc_n8i8op/192.168.1.96/status/input/1" -u xxxxxxxx -P xxxxxxxx
- Тази команда се абонира за topic, който съдържа информация за състоянието на вход 1 на устройството с IP
192.168.1.96
. - Примерен изход:
hhc_n8i8op/192.168.1.96/status/input/1 0
- Този изход показва, че вход 1 е неактивен (
0
).
Тези команди предоставят лесен начин за управление и мониторинг на устройствата HHC N8I8OP чрез MQTT, използвайки Linux терминал.
Заключение
В тази статия разгледахме подробно как да управляваме устройствата HHC N8I8OP чрез MQTT протокол, използвайки Python. Кодът предоставя лесен начин за управление на релета и мониторинг на входове, като използва MQTT за комуникация. Това го прави идеален за интеграция в IoT системи и проекти за автоматизация.
Чрез подробното обяснение на кода и инструкциите за настройка на MQTT, се надяваме, че сте придобили необходимите знания за успешното използване на този код в своите проекти.