コード例 #1
0
        /// <summary>
        /// Logs into CRM using provided credentials and then uploads each meter in memory that
        /// has been commissioned
        /// </summary>
        /// <returns></returns>
        private async Task CreateCRM()
        {
            SubmitEnabled = false;
            HttpClient client = new HttpClient();
            string     sid = null;
            string     toUploadDir = String.Format("{0}\\ToUpload", Directory.GetCurrentDirectory());
            string     uploadedDir = String.Format("{0}\\Uploaded", Directory.GetCurrentDirectory());
            string     logDir = String.Format("{0}\\ErrorLogs", Directory.GetCurrentDirectory());
            Dictionary <string, string> failedMeters = new Dictionary <string, string>(), infoMeters = new Dictionary <string, string>();
            Dictionary <string, string> operationToSite = new Dictionary <string, string>(), siteToCases = new Dictionary <string, string>();
            List <string> successMeters = new List <string>();


            // Logs into CRM using provided credentials and saves login token
            if (_ticket == null && !await Authenticate(client))
            {
                FailedMessage = "Incorrect credentials provided, please try again!";
                return;
            }

            // var service = CreateService();
            Dictionary <string, Meter> metersToCommission = Globals.Meters;

            // bhfwfquxf - FS Reports Table
            // bghhvi54m - Operations Table
            // bghhviw72 - Devices Table
            // bgs8pzryj - Device Issues
            //
            // Iterate over each meter in memory and attempt to upload contents to CRM
            foreach (KeyValuePair <string, Meter> kvp in metersToCommission)
            {
                // Only upload meters that have gone through each step and are commissioned
                if (!kvp.Value.Commissioned)
                {
                    continue;
                }

                // Upload meters that have not been processed
                // if (!successMeters.Contains(kvp.Key) && !failedMeters.ContainsKey(kvp.Key))
                //     UploadToGoogleDrive(service, String.Format("{0}\\{1}.txt", toUploadDir, kvp.Key), "1ITbna7DnCpXUvj2BgE3UtPgiZFIPITBo");

                string query, response, rid, oldMeters;
                Dictionary <string, string> data;

                // Check if a record already exists with this meter ID if so the current user is editting a record
                // if not the current user is creating or adding a record, empty response indicates a new record
                // will be generated
                oldMeters = await DoQueryRecordString(client, "bhfwfquxf", String.Format("{{19.TV.'{0}'}}AND{{37.TV.{1}}}", kvp.Value.ID, kvp.Value.OperationID), "37");

                var originalCount = failedMeters.Count;
                GetSite(client, kvp.Value.OperationID, kvp.Key, ref operationToSite, ref siteToCases, ref failedMeters);
                sid = operationToSite[kvp.Value.OperationID];

                if (failedMeters.Count > originalCount)
                {
                    continue;
                }

                // Check if current serial num has a device issue with a customer problem commissioning request
                // associated with the current site and a status that is not completed
                var deviceIssue = await IsDeviceIssue(client, kvp.Key, sid);

                // Get the Device Record
                query    = string.Format("{{186.TV.'{0}'}}", kvp.Key);
                response = await DoQueryRecordString(client, "bghhviw72", query);

                if (String.IsNullOrEmpty(response))
                {
                    FailedMessage = "Failure encountered, check log file";
                    failedMeters.Add(kvp.Key, String.Format("Can't find serial number: {0} in Devices, continuing...", kvp.Key));
                    continue;
                }

                data = CreateFSData(response, kvp.Value, deviceIssue);
                if (data.ContainsKey("error"))
                {
                    FailedMessage = "Failure encountered, check log file";
                    failedMeters.Add(kvp.Key, String.Format(data["error"], kvp.Key));
                    continue;
                }

                if (!siteToCases[sid].Split(new char[1] {
                    ','
                }).Contains(data["_fid_17"]))
                {
                    failedMeters.Add(kvp.Key, $"Serial {kvp.Key} has case {data["_fid_17"]} which is not associated with site {sid}");
                    continue;
                }

                var results2 = await UploadFSReport(client, oldMeters, kvp.Value.OperationID, kvp.Key, logDir, data, failedMeters);

                rid = results2.Item1;
                var edit = results2.Item2;
                failedMeters = results2.Item3;

                // If the edit or create record was successful then upload the meter file to CRM
                if (!string.IsNullOrEmpty(rid))
                {
                    foreach (Channel c in kvp.Value.Channels)
                    {
                        await UploadMeterPoint(client, c, rid, edit, kvp.Key, logDir);
                    }

                    // If successfully created FS Report, move meter save file but keep it locally just in case it needs to be referenced in the future
                    // 1ITbna7DnCpXUvj2BgE3UtPgiZFIPITBo Meters Folder
                    // 1YkVwvSJuQrb4RGsy9BoNTIfAuhqb-YNS Logs Folder

                    File.Move(String.Format("{0}\\{1}.json", toUploadDir, kvp.Key), String.Format("{0}\\{1}.json", uploadedDir, kvp.Key));
                    successMeters.Add(kvp.Key);
                }

                await Task.Delay(2500);
            }

            string windowMessage = LoggingInfo(successMeters, failedMeters, infoMeters);

            // Enable submit button after process complete
            SubmitEnabled = true;

            InfoView      info = null;
            InfoViewModel ifvm = new InfoViewModel("Upload Process Complete", windowMessage);

            Application.Current.Dispatcher.Invoke(() =>
            {
                info = new InfoView
                {
                    Owner = Application.Current.MainWindow,
                    WindowStartupLocation = WindowStartupLocation.CenterOwner,
                    DataContext           = ifvm
                };

                info.Show();
            });
        }
コード例 #2
0
        /// <summary>
        /// Connects a serial port to a meter and creates a new meter object, progressing user to next page
        /// </summary>
        /// <returns></returns>
        private async Task OpenSerial()
        {
            try
            {
                var tokenSource         = new CancellationTokenSource();
                CancellationToken token = tokenSource.Token;
                var task = EstablishSerial(token);

                // Waits 5 seconds for Phase Diagnostic call to finish execution if not then display
                // modal to user and attempt to reconnect
                if (!task.Wait(500, token))
                {
                    // Create thread that launches modal window for user and continues to poll
                    // original process to determine if it has completed
                    Thread t = new Thread(new ThreadStart(async() =>
                    {
                        InfoView info      = null;
                        InfoViewModel ifvm = new InfoViewModel(task, tokenSource, "Meter Serial Connection", "Connecting to Meter");

                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            info = new InfoView
                            {
                                Owner = Application.Current.MainWindow,
                                WindowStartupLocation = WindowStartupLocation.CenterOwner,
                                DataContext           = ifvm
                            };

                            info.Show();
                        });

                        var monitor = ifvm.Poll();
                        if (monitor)
                        {
                            // Close the window if the program has successfully re-established communication
                            Application.Current.Dispatcher.Invoke(() =>
                            {
                                ifvm.UserClosedWindow = false;
                                info.Close();
                            });
                        }
                        else
                        {
                            // Wait for the task to complete
                            while (task.Status != TaskStatus.RanToCompletion)
                            {
                            }

                            // exit this function
                            return;
                        }
                    }));

                    t.SetApartmentState(ApartmentState.STA);
                    t.IsBackground = true;
                    t.Start();
                    t.Join();
                }
            }
            catch
            {
            }
            finally
            {
                IsBusy  = false;
                COMPORT = "          ";
            }
        }
コード例 #3
0
        /// <summary>
        /// Issues Phase Diagnostic call for meter
        /// </summary>
        /// <returns>Boolean indicating success of Phase Diagnostic call</returns>
        private string Process()
        {
            CancellationToken token = _cts.Token;
            var task = _serial.PhaseDiagnostic(token);

            // Waits X seconds for Phase Diagnostic call to finish execution if not then display
            // modal to user and attempt to reconnect
            int timeout = _serial.NewFirmware ? 7000 : 5000;

            if (!task.Wait(timeout, token))
            {
                // Create thread that launches modal window for user and continues to poll
                // original process to determine if it has completed
                Thread t = new Thread(new ThreadStart(() =>
                {
                    InfoView info      = null;
                    InfoViewModel ifvm = new InfoViewModel(task, _cts, "Serial Connection Lost", "Attempting to Reconnect");

                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        info = new InfoView
                        {
                            Owner = Application.Current.MainWindow,
                            WindowStartupLocation = WindowStartupLocation.CenterOwner,
                            DataContext           = ifvm
                        };

                        info.Show();
                    });

                    var monitor = ifvm.Poll();
                    if (monitor)
                    {
                        // Close the window if the program has successfully re-established communication
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            ifvm.UserClosedWindow = false;
                            info.Close();
                        });
                    }
                    else
                    {
                        // Wait for the task to complete
                        while (task.Status != TaskStatus.RanToCompletion)
                        {
                        }

                        // exit this function
                        return;
                    }
                }));

                t.SetApartmentState(ApartmentState.STA);
                t.IsBackground = true;
                t.Start();
                t.Join();
            }

            // Iterate over each line and extract the voltage, current and kW for each channel and phase of the meter
            string buffer      = task.Result;
            int    meter       = 0;
            bool   phase1      = true;
            int    lineNumber  = 0;
            bool   corrupted   = false;
            float  voltageASum = 0.0f;
            float  voltageBSum = 0.0f;
            float  voltageCSum = 0.0f;
            float  voltageANum = 0;
            float  voltageBNum = 0;
            float  voltageCNum = 0;

            foreach (string s in buffer.Split(new char[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries))
            {
                string[] cols = s.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);

                // if not data row continue to next line
                if (s.Contains("Amps") || (!_serial.NewFirmware && cols.Length != 10) || (_serial.NewFirmware && cols.Length != 9))
                {
                    continue;
                }

                if (!_serial.NewFirmware)
                {
                    if (Regex.IsMatch(cols[0], "^(3[2-9]|4[0-3])$") && Regex.IsMatch(cols[3], "^[12]$") && Convert.ToInt32(cols[0]) - 32 == lineNumber / 2)
                    {
                        meter  = Convert.ToInt32(cols[0]) - 32;
                        phase1 = cols[3] == "1" ? true : false;

                        if (phase1)
                        {
                            if (Regex.IsMatch(cols[6], @"^\d*\.\d*$"))
                            {
                                Phase1Text[meter, 0] = float.Parse(cols[6]).ToString("0.00");
                            }
                            else
                            {
                                Phase1Text[meter, 0] = "--";
                                corrupted            = true;
                            }

                            if (Regex.IsMatch(cols[8], @"^\d*\.\d*$"))
                            {
                                float watts = float.Parse(cols[8]);
                                Phase1Text[meter, 1] = (watts / 1000).ToString("0.00");

                                if (Regex.IsMatch(cols[9], @"^\d*\.\d*$"))
                                {
                                    double temp = Math.Atan2(float.Parse(cols[9]), watts);

                                    if (double.IsNaN(temp))
                                    {
                                        Phase1Text[meter, 2] = "--";
                                    }
                                    else
                                    {
                                        Phase1Text[meter, 2] = temp.ToString("0.00");
                                    }
                                }
                                else
                                {
                                    Phase1Text[meter, 2] = "--";
                                    corrupted            = true;
                                }
                            }
                            else
                            {
                                Phase1Text[meter, 1] = "--";
                                Phase1Text[meter, 2] = "--";
                                corrupted            = true;
                            }

                            // Set the voltages for the Meter Information box
                            if (Regex.IsMatch(cols[7], @"^\d*\.\d*$"))
                            {
                                if (Phase1Text[meter, 4] == "A")
                                {
                                    voltageASum += float.Parse(cols[7]);
                                    voltageANum++;
                                }
                                else if (Phase1Text[meter, 4] == "B")
                                {
                                    voltageBSum += float.Parse(cols[7]);
                                    voltageBNum++;
                                }
                                else if (Phase1Text[meter, 4] == "C")
                                {
                                    voltageCSum += float.Parse(cols[7]);
                                    voltageCNum++;
                                }
                            }
                            else
                            {
                                corrupted = true;
                            }
                        }
                        else
                        {
                            if (Regex.IsMatch(cols[6], @"^\d*\.\d*$"))
                            {
                                Phase2Text[meter, 0] = float.Parse(cols[6]).ToString("0.00");
                            }
                            else
                            {
                                Phase2Text[meter, 0] = "--";
                                corrupted            = true;
                            }

                            if (Regex.IsMatch(cols[8], @"^\d*\.\d*$"))
                            {
                                float watts = float.Parse(cols[8]);
                                Phase2Text[meter, 1] = (watts / 1000).ToString("0.00");

                                if (Regex.IsMatch(cols[9], @"^\d*\.\d*$"))
                                {
                                    double temp = Math.Atan2(float.Parse(cols[9]), watts);

                                    if (double.IsNaN(temp))
                                    {
                                        Phase2Text[meter, 2] = "--";
                                    }
                                    else
                                    {
                                        Phase2Text[meter, 2] = temp.ToString("0.00");
                                    }
                                }
                                else
                                {
                                    Phase2Text[meter, 2] = "--";
                                    corrupted            = true;
                                }
                            }
                            else
                            {
                                Phase2Text[meter, 1] = "--";
                                Phase2Text[meter, 2] = "--";
                                corrupted            = true;
                            }

                            // Set the voltages for the Meter Information box
                            if (Regex.IsMatch(cols[7], @"^\d*\.\d*$"))
                            {
                                if (Phase2Text[meter, 4] == "A")
                                {
                                    voltageASum += float.Parse(cols[7]);
                                    voltageANum++;
                                }
                                else if (Phase2Text[meter, 4] == "B")
                                {
                                    voltageBSum += float.Parse(cols[7]);
                                    voltageBNum++;
                                }
                                else if (Phase2Text[meter, 4] == "C")
                                {
                                    voltageCSum += float.Parse(cols[7]);
                                    voltageCNum++;
                                }
                            }
                            else
                            {
                                corrupted = true;
                            }
                        }
                    }
                    else
                    {
                        if (lineNumber % 2 == 0)
                        {
                            Phase1Text[lineNumber / 2, 0] = "--";   // Amps
                            Phase1Text[lineNumber / 2, 1] = "--";   // Watts
                            Phase1Text[lineNumber / 2, 2] = "--";   // PF
                        }
                        else
                        {
                            Phase2Text[lineNumber / 2, 0] = "--";   // Amps
                            Phase2Text[lineNumber / 2, 1] = "--";   // Watts
                            Phase2Text[lineNumber / 2, 2] = "--";   // PF
                        }

                        corrupted = true;
                    }
                }
                else
                {
                    if (Regex.IsMatch(cols[0], "^[12]$"))
                    {
                        phase1 = cols[0] == "1" ? true : false;

                        if (phase1)
                        {
                            if (Regex.IsMatch(cols[3], @"^\d*\.\d*$"))
                            {
                                Phase1Text[meter, 0] = float.Parse(cols[3]).ToString("0.00");
                            }
                            else
                            {
                                Phase1Text[meter, 0] = "--";
                                corrupted            = true;
                            }

                            if (Regex.IsMatch(cols[5], @"^\d*\.\d*$"))
                            {
                                float watts = float.Parse(cols[5]);
                                Phase1Text[meter, 1] = (watts / 1000).ToString("0.00");

                                if (Regex.IsMatch(cols[6], @"^\d*\.\d*$"))
                                {
                                    double temp = Math.Atan2(float.Parse(cols[6]), watts);
                                    if (double.IsNaN(temp))
                                    {
                                        Phase1Text[meter, 2] = "--";
                                    }
                                    else
                                    {
                                        Phase1Text[meter, 2] = temp.ToString("0.00");
                                    }
                                }
                                else
                                {
                                    Phase1Text[meter, 2] = "--";
                                    corrupted            = true;
                                }
                            }
                            else
                            {
                                Phase1Text[meter, 1] = "--";
                                Phase1Text[meter, 2] = "--";
                                corrupted            = true;
                            }

                            // Set the voltages for the Meter Information box
                            if (Regex.IsMatch(cols[4], @"^\d*\.\d*$"))
                            {
                                if (Phase1Text[meter, 4] == "A")
                                {
                                    voltageASum += float.Parse(cols[4]);
                                    voltageANum++;
                                }
                                else if (Phase1Text[meter, 4] == "B")
                                {
                                    voltageBSum += float.Parse(cols[4]);
                                    voltageBNum++;
                                }
                                else if (Phase1Text[meter, 4] == "C")
                                {
                                    voltageCSum += float.Parse(cols[4]);
                                    voltageCNum++;
                                }
                            }
                            else
                            {
                                corrupted = true;
                            }
                        }
                        else
                        {
                            if (Regex.IsMatch(cols[3], @"^\d*\.\d*$"))
                            {
                                Phase2Text[meter, 0] = float.Parse(cols[3]).ToString("0.00");
                            }
                            else
                            {
                                Phase2Text[meter, 0] = "--";
                                corrupted            = true;
                            }

                            if (Regex.IsMatch(cols[5], @"^\d*\.\d*$"))
                            {
                                float watts = float.Parse(cols[5]);
                                Phase2Text[meter, 1] = (watts / 1000).ToString("0.00");

                                if (Regex.IsMatch(cols[6], @"^\d*\.\d*$"))
                                {
                                    double temp = Math.Atan2(float.Parse(cols[6]), watts);
                                    if (double.IsNaN(temp))
                                    {
                                        Phase2Text[meter, 2] = "--";
                                    }
                                    else
                                    {
                                        Phase2Text[meter, 2] = temp.ToString("0.00");
                                    }
                                }
                                else
                                {
                                    Phase2Text[meter, 2] = "--";
                                    corrupted            = true;
                                }
                            }
                            else
                            {
                                Phase2Text[meter, 1] = "--";
                                Phase2Text[meter, 2] = "--";
                                corrupted            = true;
                            }

                            // Set the voltages for the Meter Information box
                            if (Regex.IsMatch(cols[4], @"^\d*\.\d*$"))
                            {
                                if (Phase2Text[meter, 4] == "A")
                                {
                                    voltageASum += float.Parse(cols[4]);
                                    voltageANum++;
                                }
                                else if (Phase2Text[meter, 4] == "B")
                                {
                                    voltageBSum += float.Parse(cols[4]);
                                    voltageBNum++;
                                }
                                else if (Phase2Text[meter, 4] == "C")
                                {
                                    voltageCSum += float.Parse(cols[4]);
                                    voltageCNum++;
                                }
                            }
                            else
                            {
                                corrupted = true;
                            }

                            meter++;
                        }
                    }
                    else
                    {
                        if (lineNumber % 2 == 0)
                        {
                            Phase1Text[lineNumber / 2, 0] = "--";   // Amps
                            Phase1Text[lineNumber / 2, 1] = "--";   // Watts
                            Phase1Text[lineNumber / 2, 2] = "--";   // PF
                        }
                        else
                        {
                            Phase2Text[lineNumber / 2, 0] = "--";   // Amps
                            Phase2Text[lineNumber / 2, 1] = "--";   // Watts
                            Phase2Text[lineNumber / 2, 2] = "--";   // PF
                        }

                        corrupted = true;
                    }
                }

                lineNumber++;
            }

            // Display average of Voltages instead of last voltage received
            // aids in troubleshooting
            VoltageA = (voltageASum / voltageANum).ToString("0.00") + " V";
            VoltageB = (voltageBSum / voltageBNum).ToString("0.00") + " V";
            VoltageC = (voltageCSum / voltageCNum).ToString("0.00") + " V";

            OnPropertyChanged(nameof(Phase1Text));
            OnPropertyChanged(nameof(Phase2Text));

            // If present data is corrupted, increment corrupted counter
            if (corrupted)
            {
                _numCorrupted++;
            }
            // Reset corrupted counter if data isn't corrupt
            else
            {
                _numCorrupted = 0;
            }

            // If data is corrupt, 3 times in a row
            // display modal to user and stop reading
            if (_numCorrupted == 3)
            {
                InfoView      info = null;
                InfoViewModel ifvm = new InfoViewModel("Corrupted Data", "Corrupted Data has been received multiple times. Please check set up. Pausing serial port reads.");

                Application.Current.Dispatcher.Invoke(() =>
                {
                    info = new InfoView
                    {
                        Owner = Application.Current.MainWindow,
                        WindowStartupLocation = WindowStartupLocation.CenterOwner,
                        DataContext           = ifvm
                    };

                    info.Show();
                });

                // Stops async processes and closes serial port
                // but leaves current tab open
                _break = true;
                _serial.Close();
            }

            return(buffer);
        }
コード例 #4
0
        /// <summary>
        /// Code used to create/open meter object and create a tab for this item
        /// </summary>
        public async Task <string> CreateNewMeter()
        {
            Dictionary <string, Meter> meters = Globals.Meters;

            // Logs into meter and retrieves it's ID
            _id = await _serial.SetupSerial(_comPort);

            if (_id == "")
            {
                InfoView      info = null;
                InfoViewModel ifvm = new InfoViewModel("Unable to Connect", "COM Port already open, close port or choose another COM...");

                Application.Current.Dispatcher.Invoke(() =>
                {
                    info = new InfoView
                    {
                        Owner = Application.Current.MainWindow,
                        WindowStartupLocation = WindowStartupLocation.CenterOwner,
                        DataContext           = ifvm
                    };

                    info.Show();
                });

                return(null);
            }

            var query = ComPorts.Select((value, index) => new { value, index })
                        .Where(x => x.value.Name == _comPort)
                        .Select(x => x.index)
                        .Take(1);

            ComPorts[query.ElementAt(0)].Used = true;

            // Creates new meter if imported meters do not match current meter
            if (!meters.ContainsKey(_id))
            {
                Globals.Logger.LogInformation($"Creating new meter for {_id}");
                meters.Add(_id, new Meter());
                var meter = meters[_id];
                meter.ID = _id;

                // Sets the size of the meter based on the type/version of meter connected
                string version = await _serial.GetVersion();

                string[] lines   = version.Split(new char[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries);
                string   inspect = "";
                bool     stop    = false;
                foreach (string line in lines)
                {
                    if (line.ToLower().Contains("software"))
                    {
                        stop = true;
                    }
                    else if (stop)
                    {
                        inspect = line;
                        break;
                    }
                }

                var      cols    = inspect.Split(new char[0], System.StringSplitOptions.RemoveEmptyEntries);
                string[] serials = (await _serial.GetChildSerial()).Split(',');
                if (cols[1] == "59330354")
                {
                    meter.Firmware      = cols[1];
                    _serial.NewFirmware = true;
                    // Retrieves child serial numbers and assigns them to respective channel
                    for (int i = 0; i < 12; i++)
                    {
                        meter.Channels.Add(new Channel(i + 1));
                        meter.Channels[i].Serial = serials[i];
                    }

                    Globals.Logger.LogInformation($"Meter {_id} has firmware version {meter.Firmware}.");
                }
                else if (cols[1] == "59330353")
                {
                    meter.Firmware = cols[1];
                    // Retrieves child serial numbers and assigns them to respective channel
                    for (int i = 0; i < 12; i++)
                    {
                        meter.Channels.Add(new Channel(i + 1));
                        meter.Channels[i].Serial = serials[i];
                    }
                    Globals.Logger.LogInformation($"Meter {_id} has firmware version {meter.Firmware}.");
                }
                else
                {
                    InfoView      info = null;
                    InfoViewModel ifvm = new InfoViewModel("Bad Firmware Version", $"Invalid Firmware Version {cols[1]}");

                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        info = new InfoView
                        {
                            Owner = Application.Current.MainWindow,
                            WindowStartupLocation = WindowStartupLocation.CenterOwner,
                            DataContext           = ifvm
                        };

                        info.Show();
                    });

                    return(null);
                }
            }
            else
            {
                // Firmware was not populated from the file so read directly from the meter
                if (meters[_id].Firmware == null)
                {
                    string version = await _serial.GetVersion();

                    string[] lines   = version.Split(new char[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries);
                    string   inspect = "";
                    bool     stop    = false;
                    foreach (string line in lines)
                    {
                        if (line.ToLower().Contains("software"))
                        {
                            stop = true;
                        }
                        else if (stop)
                        {
                            inspect = line;
                            break;
                        }
                    }

                    var cols = inspect.Split(new char[0], System.StringSplitOptions.RemoveEmptyEntries);
                    meters[_id].Firmware = cols[1];
                    Globals.Logger.LogInformation($"Meter {_id} has firmware version {meters[_id].Firmware}.");
                }

                // This is an unknown firmware version, print message to user and exit
                if (meters[_id].Firmware != "59330353" && meters[_id].Firmware != "59330354")
                {
                    InfoView      info = null;
                    InfoViewModel ifvm = new InfoViewModel("Bad Firmware Version", $"Invalid Firmware Version {meters[_id].Firmware}");

                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        info = new InfoView
                        {
                            Owner = Application.Current.MainWindow,
                            WindowStartupLocation = WindowStartupLocation.CenterOwner,
                            DataContext           = ifvm
                        };

                        info.Show();
                    });

                    return(null);
                }
                else
                {
                    _serial.NewFirmware = (meters[_id].Firmware == "59330354");
                }
            }

            return(_id);
        }