393 lines
13 KiB
C#
393 lines
13 KiB
C#
using Best.HTTP.JSON.LitJson;
|
|
using Best.MQTT;
|
|
using Best.MQTT.Packets;
|
|
using Best.MQTT.Packets.Builders;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using Newtonsoft.Json;
|
|
using UnityEngine;
|
|
using WI;
|
|
using System.Text.RegularExpressions;
|
|
|
|
public class MQTT : Protocol, ISingle, IOptionable
|
|
{
|
|
MQTTClient client;
|
|
|
|
[OptionSection]
|
|
string mqttClientSetting;
|
|
[OptionKey]
|
|
string host ="106.247.236.204";
|
|
[OptionKey]
|
|
string port="8901";
|
|
[OptionKey]
|
|
string topics= "MES/PDV/BOARD1,MES/PDV/BOARD2,MES/PDV/BOARD3,DVI/HOT/+";
|
|
|
|
static readonly Regex ijRegex = new Regex(@"^IJ(\d{2})$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
|
|
|
private int portData;
|
|
private string[] subscriptionTopics;
|
|
public event Action<bool> onNotloadData;
|
|
public event Action<List<CompleteInfo>> onMachineData;
|
|
public event Action<List<WorkShopInfo>> onWorkshopData;
|
|
public event Action<List<AlarmInfo>> onAlarmData;
|
|
public event Action<List<ThermostatData>> onThermostatData;
|
|
public void Awake()
|
|
{
|
|
onNotloadData?.Invoke(true);
|
|
}
|
|
public void Start()
|
|
{
|
|
MQTTConnect();
|
|
}
|
|
public void MQTTConnect()
|
|
{
|
|
Disconnect();
|
|
|
|
int.TryParse(port, out portData);
|
|
subscriptionTopics = topics.Split(",");
|
|
|
|
SubscriptionTopic(subscriptionTopics[0], onWorkshopData);
|
|
SubscriptionTopic(subscriptionTopics[1], onMachineData);
|
|
SubscriptionTopic(subscriptionTopics[2], onAlarmData);
|
|
SubscriptionTopic(subscriptionTopics[3], onThermostatData);
|
|
//SubscriptionTopic(subscriptionTopics[0], (data) => { });
|
|
Connect(host, portData.ToString(), topics);
|
|
}
|
|
|
|
public event Action portParsingError;
|
|
public void Connect(string ip, string port, string topics)
|
|
{
|
|
//Debug.Log($"1MQTT CONNECTING... {ip}:{port} {topics}");
|
|
host = ip;
|
|
if (!int.TryParse(port, out int pd))
|
|
{
|
|
portParsingError?.Invoke();
|
|
return;
|
|
}
|
|
this.portData = pd;
|
|
subscriptionTopics = topics.Split(',');
|
|
//Debug.Log($"2MQTT CONNECTING... {host}:{this.port} {subscriptionTopics.Length}");
|
|
Connect();
|
|
}
|
|
|
|
public void Disconnect()
|
|
{
|
|
client?.CreateDisconnectPacketBuilder()
|
|
.WithReasonCode(DisconnectReasonCodes.NormalDisconnection)
|
|
.WithReasonString("Bye")
|
|
.BeginDisconnect();
|
|
}
|
|
public void Connect()
|
|
{
|
|
//Disconnect();
|
|
//#if !UNITY_EDITOR
|
|
// HTTPManager.RootFolderName = "EdukitDT";
|
|
//#endif
|
|
client = new MQTTClientBuilder()
|
|
//#if !UNITY_WEBGL || UNITY_EDITOR
|
|
.WithOptions(new ConnectionOptionsBuilder().WithTCP(host, portData))
|
|
//#else
|
|
//.WithOptions(new ConnectionOptionsBuilder().WithWebSocket(host, port).WithTLS())
|
|
//#endif
|
|
.WithEventHandler(OnConnected)
|
|
.WithEventHandler(OnStateChange)
|
|
.WithEventHandler(OnDisconnected)
|
|
.WithEventHandler(OnError)
|
|
.CreateClient();
|
|
client.BeginConnect(ConnectPacketBuilderCallback);
|
|
}
|
|
|
|
public void OnPublisherData(string workcd, string inputValue)
|
|
{
|
|
var data = new MqttData()
|
|
{
|
|
ifstatus = "N",
|
|
inputdt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
workcd = workcd,
|
|
temp_value = inputValue
|
|
};
|
|
|
|
string json = JsonConvert.SerializeObject(data);
|
|
|
|
client.AddTopicAlias("MES/PDV/MTCU1");
|
|
client.CreateApplicationMessageBuilder("MES/PDV/MTCU1")
|
|
.WithPayload(json)
|
|
.WithContentType("application/json")
|
|
.BeginPublish();
|
|
}
|
|
|
|
public event Action<MQTTClient> onConnectedEvent;
|
|
private void OnConnected(MQTTClient client)
|
|
{
|
|
//Debug.Log("OnConnected");
|
|
for (int i = 0; i < subscriptionTopics.Length; i++)
|
|
{
|
|
client.AddTopicAlias(subscriptionTopics[i]);
|
|
|
|
client.CreateSubscriptionBuilder(subscriptionTopics[i])
|
|
.WithMessageCallback(OnMessage)
|
|
.WithRetainAsPublished()
|
|
.WithAcknowledgementCallback(OnSubscriptionAcknowledged)
|
|
.WithMaximumQoS(QoSLevels.ExactlyOnceDelivery)
|
|
.BeginSubscribe();
|
|
}
|
|
|
|
onConnectedEvent?.Invoke(client);
|
|
isSuccess = true;
|
|
errorMessage = "Connected";
|
|
|
|
//client.createapplicationmessagebuilder("best_mqtt/test_topic")
|
|
// .withpayload("hello mqtt world!")
|
|
// .withqos(best.mqtt.packets.qoslevels.exactlyoncedelivery)
|
|
// .withcontenttype("text/plain; charset=utf-8")
|
|
// .beginpublish();
|
|
|
|
}
|
|
[Serializable]
|
|
public class MqttData
|
|
{
|
|
public string ifstatus;
|
|
public string inputdt;
|
|
public string workcd;
|
|
public string temp_value;
|
|
}
|
|
|
|
[Serializable]
|
|
public class WorkShopInfo
|
|
{
|
|
public string groupcd;
|
|
public string groupnm;
|
|
public string mchcnt;
|
|
public string planqty;
|
|
public string workqty;
|
|
public string goodqty;
|
|
public string badqty;
|
|
public string badrate;
|
|
public string progressrate;
|
|
}
|
|
[Serializable]
|
|
public class CompleteInfo
|
|
{
|
|
public string datagbn;
|
|
public string wordno;
|
|
public string workdt;
|
|
public string daynight;
|
|
public string sitecd;
|
|
public string wccd;
|
|
public string workcd;
|
|
public string worknm;
|
|
public string workseq;
|
|
public string status;
|
|
public string statusnm;
|
|
public string itemcd;
|
|
public string itemdesc;
|
|
public string pjtcd;
|
|
public string matcd;
|
|
public string cycletime;
|
|
public string cavity;
|
|
public string planqty;
|
|
public string goalqty;
|
|
public string workqty;
|
|
public string goodqty;
|
|
public string badqty;
|
|
public string badrate;
|
|
public string efficiency;
|
|
public string progressrate;
|
|
public string sttm;
|
|
public string totm;
|
|
public string goaltime;
|
|
public string ptotm;
|
|
public string psttm;
|
|
public string moldcd;
|
|
public string moldseq;
|
|
}
|
|
[Serializable]
|
|
public class AlarmInfo
|
|
{
|
|
public string 설비코드;
|
|
public string 설비명;
|
|
public string 호출구분;
|
|
public string 호출메시지;
|
|
public string 호출상태코드;
|
|
public string 호출상태명;
|
|
public string 호출일;
|
|
}
|
|
[Serializable]
|
|
public class ThermostatData
|
|
{
|
|
public string workcd;
|
|
public ThermostatInfo thermostatInfo;
|
|
}
|
|
[Serializable]
|
|
public class ThermostatInfo
|
|
{
|
|
public string C001;
|
|
public string C002;
|
|
public string C003;
|
|
public string C004;
|
|
public string C005;
|
|
public string C006;
|
|
public string C007;
|
|
public string C008;
|
|
public string C009;
|
|
public string C010;
|
|
public string C011;
|
|
public string C012;
|
|
public string C013;
|
|
public string C014;
|
|
public string C015;
|
|
public string C000;
|
|
}
|
|
public List<CompleteInfo> infos = new List<CompleteInfo>();
|
|
public List<WorkShopInfo> workShopInfo = new List<WorkShopInfo>();
|
|
public List<AlarmInfo> alarmInfo = new List<AlarmInfo>();
|
|
public Dictionary<string, ThermostatData> thermostatInfo = new();
|
|
|
|
public List<string> workerIds = new List<string>();
|
|
Dictionary<string, Action<List<CompleteInfo>>> topicSubscriptionTable = new();
|
|
Dictionary<string, Action<List<WorkShopInfo>>> workShopTopicTable = new();
|
|
Dictionary<string, Action<List<AlarmInfo>>> alarmTopicTable = new();
|
|
Dictionary<string, Action<List<ThermostatData>>> thermostatTopicTable = new();
|
|
private void OnMessage(MQTTClient client, SubscriptionTopic topic, string topicName, ApplicationMessage message)
|
|
{
|
|
// Convert the raw payload to a string
|
|
var payload = Encoding.UTF8.GetString(message.Payload.Data, message.Payload.Offset, message.Payload.Count);
|
|
//Debug.Log($"Content-Type: '{message.ContentType}' Payload: '{payload}'");
|
|
|
|
if (topicName == "MES/PDV/BOARD1")
|
|
{
|
|
List<WorkShopInfo> data = JsonConvert.DeserializeObject<List<WorkShopInfo>>(payload);
|
|
workShopInfo = data;
|
|
workShopTopicTable[topicName]?.Invoke(data);
|
|
}
|
|
else if(topicName== "MES/PDV/BOARD2")
|
|
{
|
|
List<CompleteInfo> data = JsonConvert.DeserializeObject<List<CompleteInfo>>(payload);
|
|
infos = data;
|
|
topicSubscriptionTable[topicName]?.Invoke(infos);
|
|
}
|
|
else if (topicName == "MES/PDV/BOARD3")
|
|
{
|
|
List<AlarmInfo> data = JsonConvert.DeserializeObject<List<AlarmInfo>>(payload);
|
|
alarmInfo = data;
|
|
alarmTopicTable[topicName]?.Invoke(alarmInfo);
|
|
}
|
|
else if (topicName != null && topicName.StartsWith("DVI/HOT/", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var parts = topicName.Split('/');
|
|
if (parts.Length >= 3)
|
|
{
|
|
string last = parts[2]; // 예: "IJ06"
|
|
var m = ijRegex.Match(last);
|
|
if (m.Success)
|
|
{
|
|
int num;
|
|
if (int.TryParse(m.Groups[1].Value, out num))
|
|
{
|
|
if (num >= 1 && num <= 25)
|
|
{
|
|
var json = JsonConvert.DeserializeObject<ThermostatInfo>(payload);
|
|
var data = new ThermostatData
|
|
{
|
|
workcd = last,
|
|
thermostatInfo = json
|
|
};
|
|
thermostatInfo[topicName] = data;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var sendData = new List<ThermostatData>(thermostatInfo.Values);
|
|
thermostatTopicTable[subscriptionTopics[3]]?.Invoke(sendData);
|
|
}
|
|
}
|
|
StringBuilder sb = new StringBuilder();
|
|
void Print(List<string> target)
|
|
{
|
|
foreach(var t in target)
|
|
{
|
|
sb.AppendLine(t);
|
|
}
|
|
Debug.Log(sb.ToString());
|
|
sb.Clear();
|
|
}
|
|
|
|
public void SubscriptionTopic(string topic, Action<List<CompleteInfo>> callback)
|
|
{
|
|
if (!topicSubscriptionTable.ContainsKey(topic))
|
|
topicSubscriptionTable.Add(topic, null);
|
|
topicSubscriptionTable[topic] += callback;
|
|
}
|
|
public void SubscriptionTopic(string topic, Action<List<WorkShopInfo>> callback)
|
|
{
|
|
if (!workShopTopicTable.ContainsKey(topic))
|
|
workShopTopicTable.Add(topic, null);
|
|
workShopTopicTable[topic] += callback;
|
|
}
|
|
public void SubscriptionTopic(string topic, Action<List<AlarmInfo>> callback)
|
|
{
|
|
if (!alarmTopicTable.ContainsKey(topic))
|
|
alarmTopicTable.Add(topic, null);
|
|
alarmTopicTable[topic] += callback;
|
|
}
|
|
public void SubscriptionTopic(string topic, Action<List<ThermostatData>> callback)
|
|
{
|
|
if (!thermostatTopicTable.ContainsKey(topic))
|
|
thermostatTopicTable.Add(topic, null);
|
|
thermostatTopicTable[topic] += callback;
|
|
}
|
|
|
|
private void OnSubscriptionAcknowledged(MQTTClient client, SubscriptionTopic topic, SubscribeAckReasonCodes reasonCode)
|
|
{
|
|
// if (reasonCode <= SubscribeAckReasonCodes.GrantedQoS2)
|
|
// Debug.Log($"Successfully subscribed with topic filter '{topic.Filter.OriginalFilter}'. QoS granted by the server: {reasonCode}");
|
|
// else
|
|
// Debug.Log($"Could not subscribe with topic filter '{topic.Filter.OriginalFilter}'! Error code: {reasonCode}");
|
|
}
|
|
|
|
|
|
void OnDestroy()
|
|
{
|
|
//Debug.Log("MQTT DESTROY");
|
|
client?.CreateDisconnectPacketBuilder()
|
|
.WithReasonCode(DisconnectReasonCodes.NormalDisconnection)
|
|
//.WithReasonString("Bye")
|
|
.BeginDisconnect();
|
|
|
|
infos.Clear();
|
|
topicSubscriptionTable.Clear();
|
|
}
|
|
private ConnectPacketBuilder ConnectPacketBuilderCallback(MQTTClient client, ConnectPacketBuilder builder)
|
|
{
|
|
return builder;
|
|
}
|
|
|
|
public event Action<MQTTClient, string> onErrorEvent;
|
|
private void OnError(MQTTClient client, string error)
|
|
{
|
|
isSuccess = false;
|
|
errorMessage = "UnConnected";
|
|
//Debug.Log($"OnError! :{error}");
|
|
onErrorEvent?.Invoke(client, error);
|
|
//throw new NotImplementedException();
|
|
}
|
|
|
|
public event Action<MQTTClient, DisconnectReasonCodes, string> onDisconnectedEvent;
|
|
private void OnDisconnected(MQTTClient client, DisconnectReasonCodes reasonCode, string reasonMessage)
|
|
{
|
|
if (client == null)
|
|
{
|
|
Debug.Log("Client Missing");
|
|
return;
|
|
}
|
|
onDisconnectedEvent?.Invoke(client, reasonCode, reasonMessage);
|
|
}
|
|
|
|
public event Action<MQTTClient, ClientStates, ClientStates> onStateChangeEvent;
|
|
private void OnStateChange(MQTTClient client, ClientStates oldState, ClientStates newState)
|
|
{
|
|
onStateChangeEvent?.Invoke(client, oldState, newState);
|
|
//throw new NotImplementedException();
|
|
}
|
|
} |