using EyesAndEars.UWP.Models; using System; using System.Diagnostics; using System.Text.Json; using System.Threading.Tasks; using Windows.Storage; using Windows.UI; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Documents; using Windows.UI.Text; namespace EyesAndEars.UWP.Services { public static class DataServices { public static async Task UpdateDevice(string url, int deviceId, RichTextBlock logs) { try { var id = MapFactoryDeviceToGalleyDevice(deviceId); // Has note. var readingAPI = $"{url}/api/readings/latest/{id}"; var statusAPI = $"{url}/api/status/latest/{deviceId}"; var readingJSON = await WebServices.GetJSON(readingAPI); var statusJSON = await WebServices.GetJSON(statusAPI); var r = MapToLightReading(readingJSON); var s = MapToDeviceStatus(statusJSON); var c = UpdateStatusColour(deviceId, s.status, r.reading); var dev = new Device(deviceId, r, s, c); LogUpdate(logs, dev); return dev; } catch (Exception e) { Debug.WriteLine(e.Message); return CreateFallBackDevice(deviceId); } } private static void LogUpdate(RichTextBlock logs, Device dev) { // Devices 3 and 6 are not in use. string device; if (dev.Id == 1) device = "factory1"; else if (dev.Id == 2) device = "factory2"; else if (dev.Id == 4) device = "gallery1"; else device = "gallery2"; Paragraph paragraph = new Paragraph(); var run1 = new Run { FontWeight = FontWeights.Bold, Text = $"{DateTime.Now} | " }; var run2 = new Run { Foreground = dev.StatusColour, FontWeight = FontWeights.Bold, Text = device }; var run3 = new Run { Foreground = dev.StatusColour, Text = $" | {dev.LatestReading.id} | {dev.LatestReading.reading} | " + $"{dev.LatestStatus.status} | {dev.LatestReading.time}" }; paragraph.Inlines.Add(run1); paragraph.Inlines.Add(run2); paragraph.Inlines.Add(run3); logs.Blocks.Insert(0, paragraph); } private static SolidColorBrush UpdateStatusColour(int device, string status, int reading) { try { if (status.Equals("on", StringComparison.OrdinalIgnoreCase)) { /* Note: 'Negative Light' Levels. * ======================================================== * The light meters will record 'negative light' values * when the factory lights are off. This does not mean * the light meters are not functioning properly. With that * said, this dashboard make it look like they are. Because * of this, the blocks in the dashboard will change to * 'LightSkyBlue' to help indicate the change is something * the system knows about and everything is fine -- nothing * is broken. */ if (device == 1) { if (reading > 0 && reading <= 38) // No weld detected. return new SolidColorBrush(Colors.LightSeaGreen); if (reading > 38) // Weld detected. return new SolidColorBrush(Colors.DarkSeaGreen); } else if (device == 2) { if (reading > 0 && reading <= 48) // No weld detected. return new SolidColorBrush(Colors.LightSeaGreen); if (reading > 48) // Weld detected. return new SolidColorBrush(Colors.DarkSeaGreen); } else if (reading < 0) { // The device is on but factory lights are off. return new SolidColorBrush(Colors.LightSkyBlue); } } // The device is off. return new SolidColorBrush(Colors.DarkRed); } catch (Exception e) { // Extra protection to if-check at top of this try block. Debug.WriteLine(e.Message); return new SolidColorBrush(Colors.DarkOrange); } } /* Note: The Purpose of Mapping a Factory to a Gallery Device. * ================================================================ * Every device in the project is paired up with another. * Factory1 => Gallery1 | Device1 => Device4 * Factory2 => Gallery2 | Device2 => Device5 * Factory3 => Gallery3 | Device3 => Device6 (Note in use at this time) * At the moment, when a device completes a status update, each one * is ran throught the "UpdateDevice" function (above). This means * the latest light reading for a light meter (factory) must be * retrieved when a galley-based device's status is updated. * From a strict point-of-view, the gallery device does not need it * so I should/could seperate out this functionality into seperate * functions. For now though, a light reading is still needed to be * retrieved because of the way the functions are called. * This function just maps/pairs the (factory) light reading to the * appropriate gallery device. By doing this, the gallery device * has extra information on its paired up light meter. One way I * have used that information is to show a small piece of text in * the gallery status box to quickly check the accuracy of the * synchronisation between the factory and gallery devices. */ static int MapFactoryDeviceToGalleyDevice(int deviceId) { int id = 0; if (deviceId > 3) { switch (deviceId) { case 4: id = 1; break; case 5: id = 2; break; case 6: id = 3; break; default: break; } } else { id = deviceId; } return id; } static LightReading MapToLightReading(string json) { try { var reading = JsonSerializer.Deserialize(json); return reading; } catch (Exception e) { Debug.WriteLine(e.Message); return CreateDefaultLightReading(); } } static DeviceStatus MapToDeviceStatus(string json) { try { var status = JsonSerializer.Deserialize(json); return status; } catch (Exception e) { Debug.WriteLine(e.Message); return CreateDefaultDeviceStatus(); } } public static Device CreateFallBackDevice(int deviceId) { // "999" and "err" are acting as sentinals in this context. var r = new LightReading { id = 0, reading = 999, time = DateTime.Now }; var s = new DeviceStatus { id = 0, status = "err", time = DateTime.Now }; var c = new SolidColorBrush(Colors.DarkOrange); var d = new Device(deviceId, r, s, c); return d; } static LightReading CreateDefaultLightReading() => new LightReading { id = 0, reading = 999, time = DateTime.Now }; static DeviceStatus CreateDefaultDeviceStatus() => new DeviceStatus { id = 0, status = "err", time = DateTime.Now }; public static async Task SaveBaseURLAsync(string contents) { try { var storageFolder = ApplicationData.Current.LocalFolder; var baseURLFile = await storageFolder.CreateFileAsync("baseURL.txt", CreationCollisionOption.ReplaceExisting); await FileIO.WriteTextAsync(baseURLFile, contents); } catch (Exception e) { Debug.WriteLine(e.Message); } } public static async Task GetBaseURLAsync() { try { var storageFolder = ApplicationData.Current.LocalFolder; var baseURLFile = await storageFolder.GetFileAsync("baseURL.txt"); var text = await FileIO.ReadTextAsync(baseURLFile); return text; } catch (Exception e) { Debug.WriteLine(e.Message); return ""; } } } }