using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading; namespace com.clusterrr.TuyaNet { /// /// Scanner to discover devices over local network. /// public class TuyaScanner { private const ushort UDP_PORT31 = 6666; // Tuya 3.1 UDP Port private const ushort UDP_PORTS33 = 6667; // Tuya 3.3 encrypted UDP Port private const string UDP_KEY = "yGAdlopoPVldABfn"; private bool running = false; private UdpClient udpServer31 = null; private UdpClient udpServer33 = null; private Thread udpListener31 = null; private Thread udpListener33 = null; private List devices = new List(); /// /// Even that will be called on every broadcast message from devices. /// public event EventHandler OnDeviceInfoReceived; /// /// Even that will be called only once for every device. /// public event EventHandler OnNewDeviceInfoReceived; /// /// Creates a new instance of the TuyaScanner class. /// public TuyaScanner() { } /// /// Starts scanner. /// public void Start() { Stop(); running = true; devices.Clear(); udpServer31 = new UdpClient(UDP_PORT31); udpServer33 = new UdpClient(UDP_PORTS33); udpListener31 = new Thread(UdpListener31Thread); udpListener33 = new Thread(UdpListener33Thread); udpListener31.Start(udpServer31); udpListener33.Start(udpServer33); } /// /// Stops scanner. /// public void Stop() { running = false; if (udpServer31 != null) { udpServer31.Dispose(); udpServer31 = null; } if (udpServer33 != null) { udpServer33.Dispose(); udpServer33 = null; } udpListener31 = null; udpListener33 = null; } private void UdpListener31Thread(object o) { var udpServer = o as UdpClient; byte[] udp_key; using (var md5 = MD5.Create()) { udp_key = md5.ComputeHash(Encoding.ASCII.GetBytes(UDP_KEY)); } while (running) { try { IPEndPoint ep = null; var data = udpServer.Receive(ref ep); var response = TuyaParser.DecodeResponse(data, udp_key, TuyaProtocolVersion.V31); Parse(response.JSON); } catch { if (!running) return; throw; } } } private void UdpListener33Thread(object o) { var udpServer = o as UdpClient; byte[] udp_key; using (var md5 = MD5.Create()) { udp_key = md5.ComputeHash(Encoding.ASCII.GetBytes(UDP_KEY)); } while (running) { try { IPEndPoint ep = null; var data = udpServer.Receive(ref ep); var response = TuyaParser.DecodeResponse(data, udp_key, TuyaProtocolVersion.V33); Parse(response.JSON); } catch { if (!running) return; throw; } } } private void Parse(string json) { var deviceInfo = JsonConvert.DeserializeObject(json); OnDeviceInfoReceived?.Invoke(this, deviceInfo); if ((OnNewDeviceInfoReceived) != null && !devices.Contains(deviceInfo)) { devices.Add(deviceInfo); OnNewDeviceInfoReceived?.Invoke(this, deviceInfo); } } } }