HHC N8I8OP управление чрез MQTT с Python

HHC N8I8OP управление чрез MQTT с Python

Въведение

В тази статия ще разгледаме подробно как да управляваме устройствата 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 контролера. Всичко това може да научите в статиите ни:

Код на 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: OFF
    • Обяснение: Този payload задава реле 1 на устройството с IP 192.168.1.96 в състояние “изключено“.

2. Topic за публикуване на състоянието на реле:

  • Topic: hhc_n8i8op/192.168.1.96/status/relay/1
  • Payload: 1
    • Обяснение: Този payload показва, че реле 1 на устройството с IP 192.168.1.96 е в състояние “включено“.
  • Payload:0
    • Обяснение: Този payload показва, че реле 1 на устройството с IP 192.168.1.96 е в състояние “изключено“.

3. Topic за публикуване на състоянието на вход:

  • Topic: hhc_n8i8op/192.168.1.96/status/input/1
  • Payload: 1
    • Обяснение: Този payload показва, че вход 1 на устройството с IP 192.168.1.96 е в състояние “активен” (високо ниво).
  • Payload: 0
    • Обяснение: Този payload показва, че вход 1 на устройството с IP 192.168.1.96 е в състояние “неактивен” (ниско ниво).

Допълнителни примери:

Пример 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 ще бъде включено.

Пример 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 е изключено.

Пример 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 е активен (високо ниво).

Команди за 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 на устройството с I192.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, се надяваме, че сте придобили необходимите знания за успешното използване на този код в своите проекти.

Translate »