/// <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(); }); }
/// <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 = " "; } }
/// <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); }
/// <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); }