Files
ChunilENG/Assets/Scripts/MQTT.cs
2025-11-21 13:07:13 +09:00

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();
}
}