public PellaBridgeClient()
 {
     tcpClient  = new PellaBridgeTCPClient();
     bridgeInfo = new BridgeInfo();
     hubIP      = IPAddress.Parse(Environment.GetEnvironmentVariable("HUB_IP_ADDRESS"));
     System.Threading.Thread listenerThread = new System.Threading.Thread(Listener);
     listenerThread.Start();
     tcpClient.Init();
     tcpClient.Connect();
     GetBridgeInfo();
     EnumerateDevices();
 }
        public BridgeInfo GetBridgeInfo()
        {
            lastCommand = "BRIDGEINFO";
            tcpClient.SendCommand("?BRIDGEINFO");

            if (evtBridgeStatus.WaitOne(timeout))
            {
                bridgeInfo = lastBridgeInfo;
                return(bridgeInfo);
            }
            else
            {
                throw new TimeoutException("Request timed out");
            }
        }
        private void Listener()
        {
            Regex BridgeInfoRegex    = new Regex(@"Version: (\w*), MAC: ([\w:]*)");
            Regex HelloRegex         = new Regex(@"Insynctive Telnet Server");
            Regex StatusChangeRegex  = new Regex(@"POINTSTATUS-([0-9]{3}),\$([0-9A-F][0-9A-F])");
            Regex BatteryChangeRegex = new Regex(@"POINTBATTERYGET-([0-9]{3}),\$([0-9A-F][0-9A-F])");
            Regex PointCountRegex    = new Regex(@"[0-9]{3}");
            Regex NumericRegex       = new Regex(@"\$([0-9A-F][0-9A-F])");

            do
            {
                // Don't wait forever, in case the TCPClient has thrown a socket error elsewhere and been replaced with a
                // new connection.
                tcpClient.messageReceived.WaitOne(timeout / 2);
                // While unlikely, it's possible multiple messages could be waiting after a single event, so loop until all are processed.
                // Note that a storm of messages is likely to cause issues, as we only track the last command received
                // So responses may end up getting matching with the wrong request.  But that it unavoidable and
                // will likely never happen in reality.  Instead what is more likely is the device pushes an update
                // while we are sending a command or refresh, and that should work fine.
                while (tcpClient.messageQueue.TryDequeue(out string message))
                {
                    Match             m;
                    int               deviceID;
                    int               newDeviceStatusCode;
                    int               newBatteryStatus;
                    PellaBridgeDevice device;

                    switch (message)
                    {
                    case string msg when HelloRegex.IsMatch(msg):
                        lastHello = DateTime.Now;

                        break;

                    case string msg when BridgeInfoRegex.IsMatch(msg):
                        m = BridgeInfoRegex.Match(msg);

                        BridgeInfo bi = new BridgeInfo
                        {
                            Version     = m.Groups[1].Value,
                            MAC         = m.Groups[2].Value,
                            connectTime = lastHello,
                            IP          = tcpClient.BridgeIPAddress.ToString()
                        };
                        lastBridgeInfo = bi;
                        evtBridgeStatus.Set();
                        break;

                    case string msg when StatusChangeRegex.IsMatch(msg):
                        m = StatusChangeRegex.Match(msg);

                        deviceID            = Int32.Parse(m.Groups[1].Value);
                        newDeviceStatusCode = Convert.ToInt32(m.Groups[2].Value, 16);
                        device = devices.Find(x => x.Id == deviceID);
                        if (device is null)
                        {
                            break;
                        }
                        UpdateDeviceStatus(device, newDeviceStatusCode);
                        break;

                    case string msg when BatteryChangeRegex.IsMatch(msg):
                        m = StatusChangeRegex.Match(msg);

                        deviceID         = Int32.Parse(m.Groups[1].Value);
                        newBatteryStatus = Convert.ToInt32(m.Groups[2].Value, 16);
                        device           = devices.Find(x => x.Id == deviceID);
                        if (device is null)
                        {
                            break;
                        }
                        UpdateBattery(device, newBatteryStatus);
                        break;

                    case string msg when PointCountRegex.IsMatch(msg):
                        m = PointCountRegex.Match(msg);

                        lastPointCount = Int32.Parse(m.Groups[0].Value);
                        evtPointCount.Set();
                        break;

                    case string msg when NumericRegex.IsMatch(msg) && lastCommand == "POINTDEVICE":
                        m = NumericRegex.Match(msg);

                        lastDevice = new PellaBridgeDevice(lastID, Convert.ToInt32(m.Groups[1].Value, 16));
                        evtPointDevice.Set();
                        break;

                    case string msg when NumericRegex.IsMatch(msg) && lastCommand == "POINTBATTERYGET":
                        m = NumericRegex.Match(msg);

                        lastBatteryStatus = Convert.ToInt32(m.Groups[1].Value, 16);
                        evtBatteryStatus.Set();
                        break;

                    case string msg when NumericRegex.IsMatch(msg) && lastCommand == "POINTSTATUS":
                        m = NumericRegex.Match(msg);

                        lastDeviceStatus = Convert.ToInt32(m.Groups[1].Value, 16);
                        evtDeviceStatus.Set();
                        break;
                    }
                }
            } while (true);
        }