Beispiel #1
0
        public void TestTemperatureStateDecisions()
        {
            testMachine           = new TemperatureStateMachine();
            testMachine.HighLimit = 85;
            GreenhouseState result = testMachine.DetermineState(89.6);

            Assert.IsTrue(testMachine.CurrentState == GreenhouseState.PROCESSING_DATA);
            Assert.IsTrue(result == GreenhouseState.COOLING);

            testMachine.LowLimit = 30;
            result = testMachine.DetermineState(0);
            Assert.IsTrue(testMachine.CurrentState == GreenhouseState.PROCESSING_DATA);
            Assert.IsTrue(result == GreenhouseState.HEATING);

            result = testMachine.DetermineState(50);
            Assert.IsTrue(testMachine.CurrentState == GreenhouseState.WAITING_FOR_DATA);

            result = testMachine.DetermineState(0);
            using (ArduinoControlSenderSimulator sim = new ArduinoControlSenderSimulator())
            {
                sim.SendCommand(result, testMachine);
            }
            Assert.IsTrue(testMachine.CurrentState == GreenhouseState.HEATING);

            result = testMachine.DetermineState(100);
            using (ArduinoControlSenderSimulator sim = new ArduinoControlSenderSimulator())
            {
                sim.SendCommand(result, testMachine);
            }
            Assert.IsTrue(testMachine.CurrentState == GreenhouseState.COOLING);

            result = testMachine.DetermineState(150);
            Assert.IsTrue(result == GreenhouseState.EMERGENCY);
        }
        /// <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)
        {
            _currentTime = GetCurrentTime(tlhData);
            ArduinoControlSender.Instance.TryConnect();

            List <GreenhouseState> statesToSend = new List <GreenhouseState>();

            #region Automation Decision Making
            // Get the averages of greenhouse readings
            GetTemperatureAverage(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
            for (int i = 0; i < StateMachineContainer.Instance.LightStateMachines.Count; i++)
            {
                GreenhouseState goalLightState = StateMachineContainer.Instance.LightStateMachines[i].DetermineState(_currentTime);
                if (goalLightState == GreenhouseState.LIGHTING || goalLightState == GreenhouseState.SHADING || goalLightState == GreenhouseState.WAITING_FOR_DATA)
                {
                    _lightState = new KeyValuePair <ITimeBasedStateMachine, GreenhouseState>(StateMachineContainer.Instance.LightStateMachines[i], goalLightState);
                    ArduinoControlSender.Instance.SendCommand(_lightState);
                }
            }

            // Get states for watering state machines, send commands
            for (int i = 0; i < StateMachineContainer.Instance.WateringStateMachines.Count; i++)
            {
                GreenhouseState goalWaterState = StateMachineContainer.Instance.WateringStateMachines[i].DetermineState(_currentTime);
                if (goalWaterState == GreenhouseState.WATERING || goalWaterState == GreenhouseState.WAITING_FOR_DATA)
                {
                    _waterState = new KeyValuePair <ITimeBasedStateMachine, GreenhouseState>(StateMachineContainer.Instance.WateringStateMachines[i], goalWaterState);
                    ArduinoControlSender.Instance.SendCommand(_waterState);
                }
            }

            // Get state for shading state machine, send commands
            GreenhouseState goalShadeState = StateMachineContainer.Instance.Shading.DetermineState(_avgLight);
            if (goalShadeState == GreenhouseState.SHADING || goalShadeState == GreenhouseState.WAITING_FOR_DATA)
            {
                _shadeState = new KeyValuePair <IStateMachine, GreenhouseState>(StateMachineContainer.Instance.Shading, goalShadeState);
                ArduinoControlSender.Instance.SendCommand(_shadeState);
            }
            #endregion
        }
        /// <summary>
        /// Converts a greenhouse state into a set of commands
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public List <Commands> ConvertStateToCommands(GreenhouseState state)
        {
            List <Commands> commandsToSend = new List <Commands>();

            if (state == GreenhouseState.SHADING)
            {
                commandsToSend.Add(Commands.SHADE_EXTEND);
            }
            else
            {
                commandsToSend.Add(Commands.SHADE_RETRACT);
            }
            return(commandsToSend);
        }
Beispiel #4
0
        /// <summary>
        /// Convert a greenhouse state to a list of commands to send to the Arduino
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public List <Commands> ConvertStateToCommands(GreenhouseState state)
        {
            // TODO: check the state of the lights so we don't have to send the command if it's already off
            List <Commands> commandsToSend = new List <Commands>();

            if (state == GreenhouseState.LIGHTING)
            {
                switch (Zone)
                {
                case 1:
                    commandsToSend.Add(Commands.LIGHT1_ON);
                    break;

                case 2:
                    commandsToSend.Add(Commands.LIGHT2_ON);
                    break;

                case 3:
                    commandsToSend.Add(Commands.LIGHT3_ON);
                    break;

                default:
                    break;
                }
            }
            else if (state == GreenhouseState.WAITING_FOR_DATA)
            {
                switch (Zone)
                {
                case 1:
                    commandsToSend.Add(Commands.LIGHT1_OFF);
                    break;

                case 2:
                    commandsToSend.Add(Commands.LIGHT2_OFF);
                    break;

                case 3:
                    commandsToSend.Add(Commands.LIGHT3_OFF);
                    break;

                default:
                    break;
                }
            }
            return(commandsToSend);
        }
        /// <summary>
        /// Convert a greenhouse state to a list of commands to send to the Arduino
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public List <Commands> ConvertStateToCommands(GreenhouseState state)
        {
            List <Commands> commandsToSend = new List <Commands>();

            if (state == GreenhouseState.LIGHTING)
            {
                switch (Zone)
                {
                case 1:
                    commandsToSend.Add(Commands.LIGHT1_ON);
                    break;

                case 2:
                    commandsToSend.Add(Commands.LIGHT2_ON);
                    break;

                case 3:
                    commandsToSend.Add(Commands.LIGHT3_ON);
                    break;

                default:
                    break;
                }
            }
            else if (state == GreenhouseState.WAITING_FOR_DATA)
            {
                switch (Zone)
                {
                case 1:
                    commandsToSend.Add(Commands.LIGHT1_OFF);
                    break;

                case 2:
                    commandsToSend.Add(Commands.LIGHT2_OFF);
                    break;

                case 3:
                    commandsToSend.Add(Commands.LIGHT3_OFF);
                    break;

                default:
                    break;
                }
            }
            return(commandsToSend);
        }
 /// <summary>
 /// Takes a list of commands to be sent to the arduino and sends them over the pi's serial port
 /// </summary>
 /// <param name="_commandsToSend">List of GreenhouseCommands from the enum</param>
 public void SendCommand(GreenhouseState state, IStateMachine stateMachine)
 {
     try
     {
         stateMachine.CurrentState = GreenhouseState.SENDING_DATA;
         Console.WriteLine($"Attempting to send state {stateMachine.CurrentState}");
         Console.WriteLine($"State {stateMachine.CurrentState} sent successfully");
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex);
     }
     try
     {
         stateMachine.CurrentState = GreenhouseState.WAITING_FOR_RESPONSE;
         Console.WriteLine($"State {stateMachine.CurrentState} executed successfully\n");
         stateMachine.CurrentState = state;
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex + $"\n State {stateMachine.CurrentState} unsuccessful\n");
     }
 }
        /// <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>
        /// Return a list of commands appropriate for the action required by the state
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public List <Commands> ConvertStateToCommands(GreenhouseState state)
        {
            // check the state of the solenoids
            List <Commands> commandsToSend = new List <Commands>();

            if (state == GreenhouseState.WATERING)
            {
                switch (Zone)
                {
                case 1:
                    commandsToSend.Add(Commands.WATER1_ON);
                    break;

                case 2:
                    commandsToSend.Add(Commands.WATER2_ON);
                    break;

                case 3:
                    commandsToSend.Add(Commands.WATER3_ON);
                    break;

                case 4:
                    commandsToSend.Add(Commands.WATER4_ON);
                    break;

                case 5:
                    commandsToSend.Add(Commands.WATER5_ON);
                    break;

                case 6:
                    commandsToSend.Add(Commands.WATER6_ON);
                    break;

                default:
                    break;
                }
            }
            else if (state == GreenhouseState.WAITING_FOR_DATA)
            {
                switch (Zone)
                {
                case 1:
                    commandsToSend.Add(Commands.WATER1_OFF);
                    break;

                case 2:
                    commandsToSend.Add(Commands.WATER2_OFF);
                    break;

                case 3:
                    commandsToSend.Add(Commands.WATER3_OFF);
                    break;

                case 4:
                    commandsToSend.Add(Commands.WATER4_OFF);
                    break;

                case 5:
                    commandsToSend.Add(Commands.WATER5_OFF);
                    break;

                case 6:
                    commandsToSend.Add(Commands.WATER6_OFF);
                    break;

                default:
                    break;
                }
            }

            return(commandsToSend);
        }
        /// <summary>
        /// Takes a greenhouse state and converts it to a list of commands to be sent off
        /// in order to properly transition to that state
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public List <Commands> ConvertStateToCommands(GreenhouseState state)
        {
            // TODO: check the state of the fans, heat, etc. so we know what commands to send
            List <Commands> commandsToSend = new List <Commands>();

            if (state == GreenhouseState.COOLING)
            {
                if (_heatState == true)
                {
                    commandsToSend.Add(Commands.HEAT_OFF);
                    _heatState = false;
                }
                if (_fanState == false)
                {
                    commandsToSend.Add(Commands.FANS_ON);
                    _fanState = true;
                }
                if (_ventState == false)
                {
                    commandsToSend.Add(Commands.VENTS_OPEN);
                    _ventState = true;
                }
            }
            else if (state == GreenhouseState.HEATING)
            {
                if (_fanState == true)
                {
                    commandsToSend.Add(Commands.FANS_OFF);
                    _fanState = false;
                }
                if (_heatState == false)
                {
                    commandsToSend.Add(Commands.HEAT_ON);
                    _heatState = true;
                }
                if (_ventState == true)
                {
                    commandsToSend.Add(Commands.VENTS_CLOSED);
                    _ventState = false;
                }
            }
            else if (state == GreenhouseState.WAITING_FOR_DATA)
            {
                if (_heatState == true)
                {
                    commandsToSend.Add(Commands.HEAT_OFF);
                    _heatState = false;
                }
                if (_fanState == true)
                {
                    commandsToSend.Add(Commands.FANS_OFF);
                    _fanState = false;
                }
                if (_ventState == true)
                {
                    commandsToSend.Add(Commands.VENTS_CLOSED);
                    _ventState = false;
                }
            }

            return(commandsToSend);
        }
        /// <summary>
        /// Return a list of commands appropriate for the action required by the state
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public List <Commands> ConvertStateToCommands(GreenhouseState state)
        {
            // Check the zone of the state machine calling this
            // and return the appropriate command
            List <Commands> commandsToSend = new List <Commands>();

            if (state == GreenhouseState.WATERING)
            {
                switch (Zone)
                {
                case 1:
                    commandsToSend.Add(Commands.WATER1_ON);
                    break;

                case 2:
                    commandsToSend.Add(Commands.WATER2_ON);
                    break;

                case 3:
                    commandsToSend.Add(Commands.WATER3_ON);
                    break;

                case 4:
                    commandsToSend.Add(Commands.WATER4_ON);
                    break;

                case 5:
                    commandsToSend.Add(Commands.WATER5_ON);
                    break;

                case 6:
                    commandsToSend.Add(Commands.WATER6_ON);
                    break;

                default:
                    break;
                }
            }
            else if (state == GreenhouseState.WAITING_FOR_DATA)
            {
                switch (Zone)
                {
                case 1:
                    commandsToSend.Add(Commands.WATER1_OFF);
                    break;

                case 2:
                    commandsToSend.Add(Commands.WATER2_OFF);
                    break;

                case 3:
                    commandsToSend.Add(Commands.WATER3_OFF);
                    break;

                case 4:
                    commandsToSend.Add(Commands.WATER4_OFF);
                    break;

                case 5:
                    commandsToSend.Add(Commands.WATER5_OFF);
                    break;

                case 6:
                    commandsToSend.Add(Commands.WATER6_OFF);
                    break;

                default:
                    break;
                }
            }

            return(commandsToSend);
        }
        /// <summary>
        /// Takes a greenhouse state and converts it to a list of commands to be sent off
        /// in order to properly transition to that state
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public List <Commands> ConvertStateToCommands(GreenhouseState state)
        {
            List <Commands> commandsToSend = new List <Commands>();

            if (state == GreenhouseState.COOLING)
            {
                if (_heatState == true)
                {
                    commandsToSend.Add(Commands.HEAT_OFF);
                    _heatState = false;
                }
                if (_fanState == false)
                {
                    commandsToSend.Add(Commands.FANS_ON);
                    _fanState = true;
                }
                if (_ventState == false)
                {
                    commandsToSend.Add(Commands.VENTS_OPEN);
                    _ventState = true;
                }
            }
            else if (state == GreenhouseState.HEATING)
            {
                if (_fanState == true)
                {
                    commandsToSend.Add(Commands.FANS_OFF);
                    _fanState = false;
                }
                if (_heatState == false)
                {
                    commandsToSend.Add(Commands.HEAT_ON);
                    _heatState = true;
                }
                if (_ventState == true)
                {
                    commandsToSend.Add(Commands.VENTS_CLOSED);
                    _ventState = false;
                }
            }
            else if (state == GreenhouseState.WAITING_FOR_DATA)
            {
                if (_heatState == true)
                {
                    commandsToSend.Add(Commands.HEAT_OFF);
                    _heatState = false;
                }
                if (_fanState == true)
                {
                    commandsToSend.Add(Commands.FANS_OFF);
                    _fanState = false;
                }
                if (_ventState == true)
                {
                    commandsToSend.Add(Commands.VENTS_CLOSED);
                    _ventState = false;
                }
            }

            return(commandsToSend);
        }