Welcome to mirror list, hosted at ThFree Co, Russian Federation.

TuyaScanner.cs - github.com/ClusterM/tuyanet.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 440fe9494f63a9a5967727d8e4cb97efa7b69d44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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
{
    /// <summary>
    /// Scanner to discover devices over local network.
    /// </summary>
    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<TuyaDeviceScanInfo> devices = new List<TuyaDeviceScanInfo>();

        /// <summary>
        /// Even that will be called on every broadcast message from devices.
        /// </summary>
        public event EventHandler<TuyaDeviceScanInfo> OnDeviceInfoReceived;
        /// <summary>
        /// Even that will be called only once for every device.
        /// </summary>
        public event EventHandler<TuyaDeviceScanInfo> OnNewDeviceInfoReceived;

        /// <summary>
        /// Creates a new instance of the TuyaScanner class.
        /// </summary>
        public TuyaScanner() { }

        /// <summary>
        /// Starts scanner.
        /// </summary>
        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);
        }

        /// <summary>
        /// Stops scanner.
        /// </summary>
        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<TuyaDeviceScanInfo>(json);
            OnDeviceInfoReceived?.Invoke(this, deviceInfo);
            if ((OnNewDeviceInfoReceived) != null && !devices.Contains(deviceInfo))
            {
                devices.Add(deviceInfo);
                OnNewDeviceInfoReceived?.Invoke(this, deviceInfo);
            }
        }
    }
}