/// <summary> /// Takes in a BlockingCollection and removes data. Sends data to be assessed elsewhere /// </summary> /// <param name="source">Blocking collection used to hold data for producer consumer pattern</param> public void ReceiveGreenhouseData(BlockingCollection <byte[]> source) { // Create a container for the TLH and moisture packets so we can deserialize them easily TLHPacketContainer tlhContainer = new TLHPacketContainer(); MoisturePacketContainer moistureContainer = new MoisturePacketContainer(); // Take the bytes out of the queue and turn them back into a string source.TryTake(out _data); string json = Encoding.ASCII.GetString(_data); // Take the string to a JObject and deserialize according to the appropriate Type value JObject received = JObject.Parse(json); Console.WriteLine(received.ToString()); switch (received["Type"].Value <int>()) { case 0: tlhContainer = JsonConvert.DeserializeObject <TLHPacketContainer>(json); _tlhInformation = tlhContainer.Packets; break; case 1: moistureContainer = JsonConvert.DeserializeObject <MoisturePacketContainer>(json); _moistureInformation = moistureContainer.Packets; break; case 2: _limits = JsonConvert.DeserializeObject <LimitPacket>(json); break; case 3: _manual = JsonConvert.DeserializeObject <ManualPacket>(json); break; } // If we have all the TLH information, moisture information, limit and manual information we need... if (_tlhInformation != null && _moistureInformation != null && _limits != null && _manual != null) { Console.WriteLine("Sending to analyzers"); // Put everything into temporary variables and clear their values afterwards TLHPacket[] tlhToSend = new TLHPacket[_tlhInformation.Count]; _tlhInformation.CopyTo(tlhToSend); _tlhInformation.Clear(); MoisturePacket[] moistureToSend = new MoisturePacket[_moistureInformation.Count]; _moistureInformation.CopyTo(moistureToSend); _moistureInformation.Clear(); ManualPacket tempManual = _manual; _manual = null; LimitPacket tempLimits = _limits; _limits = null; // Send the temporary variables off to be analyzed DataAnalyzer data = new DataAnalyzer(); data.ExecuteActions(tlhToSend, moistureToSend, tempManual, tempLimits); } }
/// <summary> /// Processes the data received from the packets /// </summary> /// <param name="data">Array of Packet objects parsed from JSON sent via data server</param> private void AnalyzeData(TLHPacket[] tlhData, MoisturePacket[] moistData) { // Get the approximate current time from the packets _currentTime = GetCurrentTime(tlhData); // Make sure the Arduino is there ArduinoControlSender.Instance.CheckArduinoStatus(); #region Automation Decision Making // Get the averages of greenhouse readings _avgTemp = GetTemperatureAverage(tlhData); _avgLight = GetLightAverage(tlhData); // Determine what state we need to go to and then create a KVP for it and send it GreenhouseState goalTempState = StateMachineContainer.Instance.Temperature.DetermineState(_avgTemp); if (goalTempState == GreenhouseState.HEATING || goalTempState == GreenhouseState.COOLING || goalTempState == GreenhouseState.WAITING_FOR_DATA) { _tempState = new KeyValuePair <IStateMachine, GreenhouseState>(StateMachineContainer.Instance.Temperature, goalTempState); // Send the KVP to the control sender ArduinoControlSender.Instance.SendCommand(_tempState); } // Get state for lighting state machines, send commands foreach (LightingStateMachine stateMachine in StateMachineContainer.Instance.LightStateMachines) { // Get the packet from the zone we're currently operating on TLHPacket packet = tlhData.Where(p => p.ID == stateMachine.Zone).Single(); double lightingValue = packet.Light; GreenhouseState goalLightState = stateMachine.DetermineState(_currentTime, lightingValue); if (goalLightState == GreenhouseState.LIGHTING || goalLightState == GreenhouseState.SHADING || goalLightState == GreenhouseState.WAITING_FOR_DATA) { _lightState = new KeyValuePair <ITimeBasedStateMachine, GreenhouseState>(stateMachine, goalLightState); ArduinoControlSender.Instance.SendCommand(_lightState); } } // Get states for watering state machines, send commands foreach (WateringStateMachine stateMachine in StateMachineContainer.Instance.WateringStateMachines) { // Get the packet from the zone we're currently operating on MoisturePacket packet = moistData.Where(p => p.ID == stateMachine.Zone).Single(); double moistureValue = (packet.Probe1 + packet.Probe2) / 2; // Get the state we need to transition into, then go send a command appropriate to that GreenhouseState goalWaterState = stateMachine.DetermineState(_currentTime, moistureValue); if (goalWaterState == GreenhouseState.WATERING || goalWaterState == GreenhouseState.WAITING_FOR_DATA) { _waterState = new KeyValuePair <ITimeBasedStateMachine, GreenhouseState>(stateMachine, goalWaterState); ArduinoControlSender.Instance.SendCommand(_waterState); } } // Get state for shading state machine, send commands GreenhouseState goalShadeState = StateMachineContainer.Instance.Shading.DetermineState(_avgTemp); if (goalShadeState == GreenhouseState.SHADING || goalShadeState == GreenhouseState.WAITING_FOR_DATA) { _shadeState = new KeyValuePair <IStateMachine, GreenhouseState>(StateMachineContainer.Instance.Shading, goalShadeState); ArduinoControlSender.Instance.SendCommand(_shadeState); } #endregion }
/// <summary> /// Takes in a BlockingCollection and removes data. Sends data to be assessed elsewhere /// </summary> /// <param name="source">Blocking collection used to hold data for producer consumer pattern</param> public void ReceiveGreenhouseData(BlockingCollection <byte[]> source) { // TODO: Fix this up so that it doesn't mess with things already happening within state machines, etc. if (source.Count != 0) { try { source.TryTake(out _data); var data = JObject.Parse(Encoding.ASCII.GetString(_data)); Console.WriteLine(data.ToString()); if (data["Type"].Value <int>() == 0) { _currentTime = data["TimeOfSend"].Value <DateTime>(); var deserializedData = JsonConvert.DeserializeObject <TLHPacket>(Encoding.ASCII.GetString(_data)); // Check for repeat zones, and if we have any, throw out the old zone data if (_tlhInformation.Where(p => p.ID == deserializedData.ID) != null) { _tlhInformation.RemoveAll(p => p.ID == deserializedData.ID); } _tlhInformation.Add(deserializedData); } // if it's a moisture packet else if (data["Type"].Value <int>() == 1) { var deserializedData = JsonConvert.DeserializeObject <MoisturePacket>(Encoding.ASCII.GetString(_data)); // Check for repeat zones, and if we have any, throw out the old zone data if (_moistureInformation.Where(p => p.ID == deserializedData.ID) != null) { _moistureInformation.RemoveAll(p => p.ID == deserializedData.ID); } _moistureInformation.Add(deserializedData); } else if (data["Type"].Value <int>() == 2) { var deserializedData = JsonConvert.DeserializeObject <LimitPacket>(Encoding.ASCII.GetString(_data)); _limits = deserializedData; } else if (data["Type"].Value <int>() == 3) { var deserializedData = JsonConvert.DeserializeObject <ManualPacket>(Encoding.ASCII.GetString(_data)); _manual = deserializedData; } } catch (Exception ex) { Console.WriteLine(ex); } if (_tlhInformation.Count == 5 && _moistureInformation.Count == 6 && _limits != null && _manual != null) { TLHPacket[] tlhToSend = new TLHPacket[_tlhInformation.Count]; _tlhInformation.CopyTo(tlhToSend); _tlhInformation.Clear(); MoisturePacket[] moistureToSend = new MoisturePacket[_moistureInformation.Count]; _moistureInformation.CopyTo(moistureToSend); _moistureInformation.Clear(); ManualPacket tempManual = _manual; _manual = null; LimitPacket tempLimits = _limits; _limits = null; DataAnalyzer data = new DataAnalyzer(); Task.Run(() => data.ExecuteActions(tlhToSend, moistureToSend, tempManual, tempLimits)); } } }