Implementação de Referência da Especificação OPC UA Part 14
Foco: Interoperabilidade JSON/MQTT para Gateways e Desktops.
Esta biblioteca fornece uma implementação em Python (CPython) das estruturas de dados e mecanismos de transporte definidos na especificação OPC UA Part 14 (PubSub). O projeto inclui ferramentas de validação cruzada utilizando a stack oficial em C (open62541) para garantir a conformidade normativa.
opc_ua_pubsub_py/
├── README.md # Este arquivo
├── requirements.txt # Dependências Python
├── Makefile # Automação (validadores C)
│
├── src/
│ └── opcua_pubsub.py # BIBLIOTECA: Core + Publisher + Subscriber
│
├── examples/
│ ├── publisher.py # Exemplo: Publisher de sensores
│ └── subscriber.py # Exemplo: Subscriber genérico
│
└── tests/
├── test_pubsub.py # Teste automatizado Publisher/Subscriber
└── validator_c/
└── subscriber.c # Validador C (open62541)
| Profile / Feature | Ref. Part 14 | Status | Detalhes |
|---|---|---|---|
| PubSub Base Information Model | §6.2 | ✅ | DataValue, DataSetMessage, NetworkMessage |
| JSON Encoding | §7.2.3 | ✅ | Serialização completa JSON |
| JSON DataSetMessage | §7.2.4 | ✅ | Key/Value mapping |
| Variant Data Types | §6.2.2 | ✅ | Int, Float, String, Bool, DateTime |
| MQTT Transport | Anexo B | ✅ | paho-mqtt |
| Standard DataSet Writer | §6.2.5 | ✅ | OPCUAPublisher |
| Standard DataSet Reader | §6.2.7 | ✅ | OPCUASubscriber |
| StatusCode | Part 4 | ✅ | Good, Bad, Uncertain + códigos específicos |
| UADP Encoding | §7.3 | ❌ | Não implementado |
| UDP Transport | Anexo A | ❌ | Não implementado |
| Security Sign/Encrypt | §6.2.2-3 | ❌ | Não implementado |
- Python 3.10+
- Broker MQTT (Ex: Mosquitto)
# Clone o repositório
git clone https://github.com/seu-usuario/opc_ua_pubsub_py.git
cd opc_ua_pubsub_py
# Crie ambiente virtual
python3 -m venv venv
source venv/bin/activate # Linux/Mac
# ou: venv\Scripts\activate # Windows
# Instale dependências
pip install -r requirements.txt# Linux (instalar Mosquitto)
sudo apt install mosquitto mosquitto-clients
# Verificar se está rodando
systemctl status mosquitto
# Ou iniciar manualmente
mosquitto -vfrom opcua_pubsub import OPCUAPublisher, DataValue, StatusCode
# Cria publisher
publisher = OPCUAPublisher(
publisher_id="MeuSensor-001",
broker_address="localhost",
base_topic="opcua/json/data"
)
# Conecta
publisher.connect()
# Publica dados
publisher.publish(
dataset_writer_id=1,
data={
"Temperature": DataValue(25.5),
"Humidity": DataValue(60.0, status_code=StatusCode.Good),
"Status": DataValue("Online")
}
)
# Desconecta
publisher.disconnect()from opcua_pubsub import OPCUASubscriber, NetworkMessage
def on_message(msg: NetworkMessage, topic: str):
print(f"Publisher: {msg.publisher_id}")
for dsm in msg.messages:
for field in dsm.get_fields():
value = dsm.get_value(field)
print(f" {field} = {value.value}")
# Cria subscriber
subscriber = OPCUASubscriber(
subscriber_id="MeuGateway",
broker_address="localhost"
)
# Configura callback
subscriber.on_message(on_message)
# Conecta e inscreve
subscriber.connect()
subscriber.subscribe("opcua/#")
# Loop principal
subscriber.loop_forever()cd examples
python subscriber.py localhostcd examples
python publisher.py localhostcd tests
python test_pubsub.py localhostResultado esperado:
✅ TESTE PASSOU - Comunicação OPC UA PubSub funcionando!
classDiagram
class NetworkMessage {
+String MessageId
+String MessageType
+String PublisherId
+List~DataSetMessage~ messages
+to_json()
+from_json()
}
class DataSetMessage {
+Int DataSetWriterId
+Int SequenceNumber
+Dict Payload
+add_value()
+get_value()
}
class DataValue {
+Any value
+StatusCode status_code
+DateTime source_timestamp
+to_dict()
+from_dict()
}
class OPCUAPublisher {
+connect()
+publish()
+disconnect()
}
class OPCUASubscriber {
+connect()
+subscribe()
+on_message()
+loop_forever()
}
NetworkMessage *-- "1..*" DataSetMessage
DataSetMessage *-- "1..*" DataValue
OPCUAPublisher ..> NetworkMessage : cria
OPCUASubscriber ..> NetworkMessage : recebe
class StatusCode(IntEnum):
Good = 0x00000000
Uncertain = 0x40000000
Bad = 0x80000000
BadSensorFailure = 0x80B10000
BadCommunicationError = 0x80C00000
BadOutOfRange = 0x803C0000
BadTimeout = 0x800A0000@dataclass
class DataValue:
value: Any
status_code: StatusCode = StatusCode.Good
source_timestamp: Optional[datetime] = None| Método | Descrição |
|---|---|
connect() |
Conecta ao broker MQTT |
disconnect() |
Desconecta do broker |
publish(dataset_writer_id, data, topic_suffix) |
Publica dados |
publish_raw(network_message, topic_suffix) |
Publica NetworkMessage diretamente |
| Método | Descrição |
|---|---|
connect() |
Conecta ao broker MQTT |
disconnect() |
Desconecta do broker |
subscribe(topic) |
Inscreve em tópico (suporta wildcards) |
set_filter(publisher_id, writer_id) |
Filtra mensagens |
on_message(callback) |
Define callback para NetworkMessage |
on_data(callback) |
Define callback para cada campo |
on_error(callback) |
Define callback para erros |
get_stats() |
Retorna estatísticas |
loop_forever() |
Mantém subscriber rodando |
| Ferramenta | Modo | Status |
|---|---|---|
| Prosys OPC UA Browser | JSON/MQTT | ✅ Validado |
| UADemoSubscriber | JSON/MQTT | ✅ Validado |
| UADemoPublisher | JSON/MQTT | ✅ Validado |
| Mosquitto Broker | MQTT 3.1.1 | ✅ Validado |
| open62541 | JSON/MQTT | 🔄 Em validação |
MIT License - Veja LICENSE para detalhes.
Fábio
Dissertação de Mestrado - Universidade do Estado do Amazonas (UEA)
Implementação OPC UA PubSub em Python para IoT Industrial