static void Main()
        {
            while (true)
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);

                //MCIv2Persistance.RestoreFromFile();

                ConfigurationManager.ReadConfigurationFromFile();

                //PeerSyncListener.Start();
                //PeerSyncAdvertiser.Start();
                //PeerSyncDiscovery.Start();

                //Application.ThreadExit += (e, b) => { ApplicationClosing(); };

                try
                {
                    var config = MCv2Persistance.Instance.Config;

                    (new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "backups\\")).Directory.Create();

                    //needs to test credentials
                    if (config.AutoLogin)
                    {
                        if (!(config.DatabaseConfiguration.DatabaseConnectionProperties.Hostname.Trim() != "" &&
                              config.DatabaseConfiguration.DatabaseConnectionProperties.Password.Trim() != "" &&
                              config.DatabaseConfiguration.DatabaseConnectionProperties.Schema.Trim() != "" &&
                              config.DatabaseConfiguration.DatabaseConnectionProperties.UID.Trim() != ""))
                        {
                            DatabaseConnectionEditor dbconneditor = new DatabaseConnectionEditor(config.DatabaseConfiguration.DatabaseConnectionProperties, false);
                            var res = dbconneditor.ShowDialog();
                            if (res == DialogResult.OK)
                            {
                                config.DatabaseConfiguration.DatabaseConnectionProperties = dbconneditor.DBConnProp;

                                MCv2Persistance.Instance.Config = config;

                                //MCv2Persistance.Instance.SaveToFile();
                            }
                            else
                            if (res == DialogResult.Abort)
                            {
                                Environment.Exit(0);
                            }
                        }
                    }

                    ProgressDialog pgd = new ProgressDialog("");
                    ARDBConnectionManager.default_progress_interface = pgd;
                    pgd.Show();
                    ARDBConnectionManager.default_manager.Start();

                    DeviceServerTracker.Stop();
                    DeviceServerTracker.Start();

                    Application.Run(new MCIv2Form());

                    DeviceServerTracker.Stop();

                    ARDBConnectionManager.default_manager.Stop();
                    pgd.Dispose();

                    break;
                }
                catch (System.Reflection.TargetInvocationException ex)
                {
                    MessageBox.Show("A database error has occured." + Environment.NewLine + ex.Message);

                    DatabaseConnectionEditor dbconneditor = new DatabaseConnectionEditor(MCv2Persistance.Instance.Config.DatabaseConfiguration.DatabaseConnectionProperties, false);
                    if (dbconneditor.ShowDialog() == DialogResult.OK)
                    {
                        MCv2Persistance.Instance.Config.DatabaseConfiguration.DatabaseConnectionProperties = dbconneditor.DBConnProp;
                    }
                    else
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
                    new ErrorBox(ex.Message + (ex.InnerException != null ? Environment.NewLine + ex.InnerException.Message : ""), ex.ToString()).ShowDialog();
                    break;
                }
            }

            //MCIv2Persistance.SaveToFile();

            //PeerSyncDiscovery.Stop();
            //PeerSyncAdvertiser.Stop();
            //PeerSyncListener.Stop();
        }
        static void Main(string[] args)
        {
            Task.Run(async() =>
            {
                DeviceServerTracker.Start();
                while (DeviceServerTracker.DeviceServerHostInfo == null)
                {
                    await Task.Delay(100);
                }

                //var client = new uPLibrary.Networking.M2Mqtt.MqttClient("127.0.0.1");
                //client.Connect(Guid.NewGuid().ToString(), "USER", "PASS");

                // Create a new MQTT client.
                var factory    = new MqttFactory();
                var mqttClient = factory.CreateMqttClient();

                var options = new MqttClientOptionsBuilder()
                              .WithTcpServer("192.168.0.31")
                              .WithTls()
                              .Build();

                //handle disconnection
                mqttClient.UseDisconnectedHandler(async e =>
                {
                    Console.WriteLine("### DISCONNECTED FROM SERVER ###");
                    await Task.Delay(TimeSpan.FromSeconds(5));

                    try
                    {
                        await mqttClient.ConnectAsync(options, CancellationToken.None); // Since 3.0.5 with CancellationToken
                    }
                    catch
                    {
                        Console.WriteLine("### RECONNECTING FAILED ###");
                    }
                });

                //connect to expander
                rem = new RemoteExpanderMonitor(8230500780121598431);

                write_timer.AutoReset = false;
                write_timer.Elapsed  += (a, b) =>
                {
                    write_timer.Stop();
                    Task.Run(() =>
                    {
                        lock (exp_mod_lock)
                        {
                            rem.WriteExpanders(exp_0_mask, exp_1_mask, exp_0_values, exp_1_values);

                            Parallel.For(0, 16, i =>
                            {
                                exp_0_mask[i]   = false;
                                exp_1_mask[i]   = false;
                                exp_0_values[i] = false;
                                exp_1_values[i] = false;
                            });
                        }
                    });
                };

                rem.freshstateevent += (a, b) =>
                {
                    Task.Run(async() =>
                    {
                        try
                        {
                            MqttApplicationMessage message;

                            //floor states
                            //Console.WriteLine("Publishing Message");
                            for (int car_val = 1; car_val < 3; car_val++)
                            {
                                for (int floor_val = 1; floor_val < 15; floor_val++)
                                {
                                    message = new MqttApplicationMessageBuilder()
                                              .WithTopic("access_control/elevator/car_" + car_val + "/floor_" + floor_val + "/get")
                                              .WithPayload(new byte[] { (car_val == 1 ? b.ExpanderState.Expander0State[floor_val - 1] : b.ExpanderState.Expander1State[floor_val - 1]) ? (byte)'1' : (byte)'0' })
                                              .WithExactlyOnceQoS()
                                              .WithRetainFlag()
                                              .Build();

                                    await mqttClient.PublishAsync(message);
                                }
                            }

                            Queue <mqtt_container> mqtt_tx = new Queue <mqtt_container>();

                            //expander 0 temp
                            mqtt_tx.Enqueue(new mqtt_container
                            {
                                c_topic   = "access_control/elevator/expander/operational_status/expander_0_temperature/get",
                                c_payload = Encoding.ASCII.GetBytes(b.ExpanderState.Board0Temperature + "")
                            });

                            //expander 1 temp
                            mqtt_tx.Enqueue(new mqtt_container
                            {
                                c_topic   = "access_control/elevator/expander/operational_status/expander_1_temperature/get",
                                c_payload = Encoding.ASCII.GetBytes(b.ExpanderState.Board1Temperature + "")
                            });

                            //fan temp
                            mqtt_tx.Enqueue(new mqtt_container
                            {
                                c_topic   = "access_control/elevator/expander/operational_status/fan_temperature/get",
                                c_payload = Encoding.ASCII.GetBytes(b.ExpanderState.FanTemperature + "")
                            });

                            //fan speed
                            mqtt_tx.Enqueue(new mqtt_container
                            {
                                c_topic   = "access_control/elevator/expander/operational_status/fan_speed/get",
                                c_payload = Encoding.ASCII.GetBytes(b.ExpanderState.FanSpeed + "")
                            });

                            //bus power
                            mqtt_tx.Enqueue(new mqtt_container
                            {
                                c_topic   = "access_control/elevator/expander/operational_status/bus_power/get",
                                c_payload = Encoding.ASCII.GetBytes(b.ExpanderState.BusPower + "")
                            });

                            //bus voltage
                            mqtt_tx.Enqueue(new mqtt_container
                            {
                                c_topic   = "access_control/elevator/expander/operational_status/bus_voltage/get",
                                c_payload = Encoding.ASCII.GetBytes(b.ExpanderState.BusVoltage + "")
                            });

                            //uptime
                            mqtt_tx.Enqueue(new mqtt_container
                            {
                                c_topic   = "access_control/elevator/expander/operational_status/uptime/get",
                                c_payload = Encoding.ASCII.GetBytes(b.ExpanderState.Uptime + "")
                            });

                            //expander state timestamp
                            mqtt_tx.Enqueue(new mqtt_container
                            {
                                c_topic   = "access_control/elevator/expander/operational_status/last_state_timestamp/get",
                                c_payload = Encoding.ASCII.GetBytes(b.ExpanderState.Timestamp.ToString())
                            });

                            foreach (mqtt_container c in mqtt_tx)
                            {
                                message = new MqttApplicationMessageBuilder()
                                          .WithTopic(c.c_topic)
                                          .WithPayload(c.c_payload)
                                          .WithExactlyOnceQoS()
                                          .WithRetainFlag()
                                          .Build();

                                await mqttClient.PublishAsync(message);
                            }
                        }
                        catch (Exception ex)
                        {
                            logger.AppendLog("MessageServer - An error occured while publishing status message.");
                            logger.AppendLog(ex.Message);
                        }
                    });
                };

                List <string> topics = new List <string>();
                for (int car_val = 1; car_val < 3; car_val++)
                {
                    for (int floor_val = 1; floor_val < 15; floor_val++)
                    {
                        topics.Add("access_control/elevator/car_" + car_val + "/floor_" + floor_val + "/set");
                    }
                }

                //subscribe to topics
                mqttClient.UseConnectedHandler(async e =>
                {
                    foreach (var topic in topics)
                    {
                        await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic).Build());
                    }
                });

                //received message handler
                mqttClient.UseApplicationMessageReceivedHandler(e =>
                {
                    Task.Run(() =>
                    {
                        if (topics.Contains(e.ApplicationMessage.Topic))
                        {
                            var substrs = e.ApplicationMessage.Topic.Split('/');

                            int car_val   = Convert.ToInt32(substrs[2].Split('_')[1]) - 1;
                            int floor_val = Convert.ToInt32(substrs[3].Split('_')[1]) - 1;

                            RelaySet(e.ApplicationMessage.Payload[0] == '1', car_val, floor_val);
                        }
                    });

                    /*
                     * Console.WriteLine("### RECEIVED APPLICATION MESSAGE ###");
                     * Console.WriteLine($"+ Topic = {e.ApplicationMessage.Topic}");
                     * Console.WriteLine($"+ Payload = {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
                     * Console.WriteLine($"+ QoS = {e.ApplicationMessage.QualityOfServiceLevel}");
                     * Console.WriteLine($"+ Retain = {e.ApplicationMessage.Retain}");
                     * Console.WriteLine();
                     */
                });

                await mqttClient.ConnectAsync(options, CancellationToken.None);

                Console.WriteLine("Starting Remote Monitor");

                rem.Start();

                Console.WriteLine("Remote Monitor Started");
            });

            Thread.Sleep(-1);
        }