예제 #1
0
        /// <summary>
        /// Kollar om strömmen ska slås på eller av och gör det i sådana fall.
        /// </summary>
        public void CheckAndAct()
        {
            if (_isActing)
            {
                Logger.Write(SystemTime.Now, LogType.Debug, LogLevel.Error, "Last CheckAndAct was not finished.");
                return;
            }

            _isActing = true;
            bool mowerLeftThisTurn = false;

            if (!HomeFromStart.HasValue)
            {
                HomeFromStart = HomeSensor.IsHome;
            }

            IterationTime = SystemTime.Now;

            if (IterationTime.Hour == 0 && IterationTime.Minute == 0)
            {
                Logger.Write(IterationTime, LogType.NewDay, LogLevel.Debug, "A new day has begun.");
            }

            LogAnalyzer = new LogAnalyzer(Logger, HomeFromStart.Value);

            if (Config.TimeIntervals == null)
            {
                throw new InvalidOperationException();
            }

            // Calculate forecast hours

            ForecastHours = NextOrCurrentInterval.EndHour - IterationTime.Hour + 2;

            if (Config.UsingContactHomeSensor)
            {
                ForecastHours = Config.MaxMowingHoursWithoutCharge + 1;
            }

            try
            {
                // Write the hourly report log item

                if (IterationTime.Minute == 0)
                {
                    var hourlyReportItem = Logger.LogItems.OrderByDescending(r => r.Time).FirstOrDefault(x => x.Type == LogType.HourlyReport);

                    if (hourlyReportItem == null || hourlyReportItem.Time.ToString("yyyy-MM-dd HH:mm") != IterationTime.ToString("yyyy-MM-dd HH:mm"))
                    {
                        int    wetness = RainSensor is SmhiRainSensor ? ((SmhiRainSensor)RainSensor).Wetness : 0;
                        string weatherAheadDescription;
                        WeatherForecast.CheckIfWeatherWillBeGood(12, out weatherAheadDescription);
                        Logger.Write(IterationTime, LogType.HourlyReport, LogLevel.InfoLessInteresting, "Hourly report: " + weatherAheadDescription + " Current wetness: " + wetness);
                    }
                }

                // If a report was not made for yesterday, and if mowing started yesterday or before, create a report.

                var startLogItem   = Logger.LogItems.FirstOrDefault(x => x.Type == LogType.MowControllerStarted);
                var todayStartTime = new DateTime(IterationTime.Year, IterationTime.Month, IterationTime.Day, 0, 0, 0);

                if (startLogItem.Time < todayStartTime)
                {
                    var yesterdayStartTime = new DateTime(IterationTime.Year, IterationTime.Month, IterationTime.Day, 0, 0, 0).AddDays(-1);

                    var reportLogItem = Logger.LogItems.FirstOrDefault(x => x.Type == LogType.DailyReport && x.Time >= todayStartTime && x.Time < todayStartTime.AddDays(1));

                    if (reportLogItem == null)
                    {
                        var mowingLogItems = Logger.LogItems.Where(x => (x.Type == LogType.MowingStarted || x.Type == LogType.MowingEnded) && x.Time >= yesterdayStartTime && x.Time < todayStartTime);

                        var sb = new StringBuilder();
                        sb.AppendLine("Mowing Summary " + yesterdayStartTime.ToString("yyyy-MM-dd"));
                        sb.AppendLine();
                        DateTime startTime  = DateTime.MinValue;
                        var      mowingTime = new TimeSpan();

                        foreach (LogItem mowingLogItem in mowingLogItems)
                        {
                            sb.Append(mowingLogItem.Time.ToString("HH:mm"));
                            sb.Append(" ");
                            sb.AppendLine(mowingLogItem.Message);

                            if (mowingLogItem.Type == LogType.MowingStarted)
                            {
                                startTime = mowingLogItem.Time;
                            }
                            else
                            {
                                mowingTime += (mowingLogItem.Time - startTime);
                            }
                        }

                        TimeSpan mowingTimeSpan = LogAnalyzer.GetMowingTimeForDay(yesterdayStartTime);

                        sb.AppendLine();
                        sb.Append("Total mowed: ");
                        sb.Append(mowingTimeSpan.Hours);
                        sb.Append(":");
                        sb.Append(mowingTimeSpan.Minutes.ToString("00"));
                        sb.AppendLine(" hours.");

                        // If contact sensor, also add detailed mowing summary

                        if (Config.UsingContactHomeSensor)
                        {
                            TimeSpan actualMowingTimeSpan = LogAnalyzer.GetActuallyMowingTimeForDay(yesterdayStartTime);

                            sb.Append("Actual out mowing time: ");
                            sb.Append(actualMowingTimeSpan.Hours);
                            sb.Append(":");
                            sb.Append(actualMowingTimeSpan.Minutes.ToString("00"));
                            sb.AppendLine(" hours.");

                            TimeSpan exactMowerAwayTimeSpan = LogAnalyzer.GetMowerAwayTimeForDay(yesterdayStartTime);

                            sb.Append("Exact mower away time: ");
                            sb.Append(exactMowerAwayTimeSpan.Hours);
                            sb.Append(":");
                            sb.Append(exactMowerAwayTimeSpan.Minutes.ToString("00"));
                            sb.AppendLine(" hours.");
                        }

                        Logger.Write(IterationTime, LogType.DailyReport, LogLevel.InfoMoreInteresting, sb.ToString());
                    }
                }

                // Check if mower has entered or exited its home since last time

                if (_mowerIsHome != HomeSensor.IsHome)
                {
                    _mowerIsHome = HomeSensor.IsHome;

                    if (_mowerIsHome)
                    {
                        Logger.Write(IterationTime, LogType.MowerCame, LogLevel.Info, "Mower came.");
                        SetMowingStarted();
                    }
                    else
                    {
                        Logger.Write(IterationTime, LogType.MowerLeft, LogLevel.Info, "Mower left.");
                        mowerLeftThisTurn = true;
                    }
                }

                // Check if mower is lost or stuck, but only if contact sensor is used.

                if (Config.UsingContactHomeSensor && !LogAnalyzer.IsLost)
                {
                    //int forecastHours = Config.MaxMowingHoursWithoutCharge + 1;

                    if (_mowerIsHome && PowerSwitch.Status == PowerStatus.On && !RainSensor.IsWet && WeatherForecast.CheckIfWeatherWillBeGood(ForecastHours) && LogAnalyzer.IsMowing && !LogAnalyzer.IsStuck)
                    {
                        var lastEssentialLogItem = Logger.LogItems
                                                   .OrderByDescending(x => x.Time)
                                                   .FirstOrDefault(x => x.Type == LogType.MowerCame || x.Type == LogType.PowerOn || x.Type == LogType.PowerOff || x.Type == LogType.MowingStarted || x.Type == LogType.MowingEnded);

                        bool mowerHasHadEnoughChargingTime = (lastEssentialLogItem != null && lastEssentialLogItem.Time.AddHours(Config.MaxChargingHours) <= IterationTime);

                        if (mowerHasHadEnoughChargingTime && !BetweenIntervals)
                        {
                            Logger.Write(IterationTime, LogType.MowerStuckInHome, LogLevel.InfoMoreInteresting, $"Mower seems to be stuck at home. It did not leave after {Config.MaxMowingHoursWithoutCharge} hours of charging time.");
                            SetMowingEnded();
                        }
                    }

                    if (!_mowerIsHome)
                    {
                        var lastMowerLeftLogItem = Logger.LogItems
                                                   .OrderByDescending(x => x.Time)
                                                   .FirstOrDefault(x => x.Type == LogType.MowerLeft);

                        var lastLogItem = Logger.LogItems
                                          .OrderByDescending(x => x.Time)
                                          .FirstOrDefault(x => x.Type == LogType.MowerLost || x.Type == LogType.MowerCame);

                        if (lastMowerLeftLogItem?.Time.AddHours(Config.MaxMowingHoursWithoutCharge) <= IterationTime && lastLogItem?.Type != LogType.MowerLost)
                        {
                            Logger.Write(IterationTime, LogType.MowerLost, LogLevel.InfoMoreInteresting, $"Mower seems to be lost. It did not return home after {Config.MaxMowingHoursWithoutCharge} hours as expected.");

                            if (!BetweenIntervals)
                            {
                                SetMowingEnded();
                            }
                        }
                    }
                }

                // Check if there has ocurred an interval start, and in case it has, write a log message

                bool atLastMinuteOfInterval = NextOrCurrentInterval.EndHour == IterationTime.Hour && NextOrCurrentInterval.EndMin == IterationTime.Minute;
                if (!BetweenIntervals && PowerSwitch.Status == PowerStatus.On && !LogAnalyzer.IsMowing && !LogAnalyzer.IsLost && (!LogAnalyzer.IsStuck || mowerLeftThisTurn) && !RainSensor.IsWet && WeatherForecast.CheckIfWeatherWillBeGood(ForecastHours) && !atLastMinuteOfInterval)
                {
                    SetMowingStarted();
                }

                // Turn on power

                if (PowerSwitch.Status != PowerStatus.On)
                {
                    if (!RainSensor.IsWet)
                    {
                        foreach (var interval in Config.TimeIntervals)
                        {
                            // Om ett intervall håller på
                            if (interval.ContainsTime(IterationTime))
                            {
                                DateTime minutesFromEnd = (new DateTime(IterationTime.Year, IterationTime.Month, IterationTime.Day, interval.EndHour, interval.EndMin, 0).AddMinutes(-10));

                                // If the interval is not close to end
                                if (IterationTime < minutesFromEnd)
                                {
                                    //int forecastHours = interval.EndHour - IterationTime.Hour + 2;

                                    //if (Config.UsingContactHomeSensor)
                                    //{
                                    //    forecastHours = Config.MaxMowingHoursWithoutCharge + 1;
                                    //}

                                    string weatherAheadDescription;

                                    bool weatherWillBeGood = WeatherForecast.CheckIfWeatherWillBeGood(ForecastHours, out weatherAheadDescription);
                                    bool mowingNecessary   = MowingNecessary();
                                    if (weatherWillBeGood && mowingNecessary)
                                    {
                                        PowerSwitch.TurnOn();
                                        Logger.Write(IterationTime, LogType.PowerOn, LogLevel.Info, "Power was turned on. " + weatherAheadDescription);
                                        SetMowingStarted();
                                    }
                                }
                            }
                        }
                    }

                    if (BetweenIntervals && !RightBeforeIntervalStarts && SafelyAfterIntervalEnd)
                    {
                        PowerSwitch.TurnOn();
                        Logger.Write(IterationTime, LogType.PowerOn, LogLevel.Info, "Power was turned on. In between intervals.");
                    }
                }

                // Turn off power

                if (PowerSwitch.Status != PowerStatus.Off)
                {
                    if (HomeSensor.IsHome) // TODO: Fel i TimeBasedHomeSensor när kraften är Unknown...
                    {
                        DateTime nextIntervalExactStartTime = new DateTime(IterationTime.Year, IterationTime.Month, IterationTime.Day, NextInterval.StartHour, NextInterval.StartMin, 0);
                        if (nextIntervalExactStartTime < IterationTime)
                        {
                            nextIntervalExactStartTime = nextIntervalExactStartTime.AddDays(1);
                        }
                        double minutesLeftToIntervalStart = (nextIntervalExactStartTime - IterationTime).TotalMinutes;

                        // If there will be rain, turn off power
                        //int forecastHours = NextInterval.ToTimeSpan().Hours + 2;

                        // If a contact home sensor is used, weather can be checked for much smaller time spans
                        if (Config.UsingContactHomeSensor)
                        {
                            ForecastHours = Config.MaxMowingHoursWithoutCharge + 1;
                        }

                        if (minutesLeftToIntervalStart <= 5 || !BetweenIntervals && HomeSensor.IsHome && (IterationTime - HomeSensor.MowerCameTime).TotalMinutes >= 30 || PowerSwitch.Status == PowerStatus.Unknown)
                        {
                            string logMessage;
                            bool   weatherWillBeGood = WeatherForecast.CheckIfWeatherWillBeGood(ForecastHours, out logMessage);

                            if (weatherWillBeGood && RainSensor.IsWet)
                            {
                                logMessage = "Grass is wet.";
                            }

                            if (RainSensor.IsWet || !weatherWillBeGood)
                            {
                                PowerSwitch.TurnOff();
                                Logger.Write(IterationTime, LogType.PowerOff, LogLevel.Info, "Power was turned off. " + logMessage);

                                if (!BetweenIntervals)
                                {
                                    SetMowingEnded();
                                }
                            }
                            else if (!MowingNecessary()) // If mowing not necessary, turn off power
                            {
                                PowerSwitch.TurnOff();
                                Logger.Write(IterationTime, LogType.PowerOff, LogLevel.Info, "Power was turned off. Mowing not necessary.");

                                if (!BetweenIntervals)
                                {
                                    SetMowingEnded();
                                }
                            }
                        }
                    }
                }

                // Check if we're at an interval end, and in case we are, write a log message

                if (!BetweenIntervals && PowerSwitch.Status == PowerStatus.On && NextOrCurrentInterval.EndHour == IterationTime.Hour && NextOrCurrentInterval.EndMin == IterationTime.Minute)
                {
                    SetMowingEnded();
                }
            }
            catch (Exception ex)
            {
                string lastMsg = "";

                if (Logger.LogItems.Count > 0)
                {
                    lastMsg = Logger.LogItems[Logger.LogItems.Count - 1].Message;
                }

                if (ex.Message != lastMsg)
                {
                    Logger.Write(IterationTime, LogType.Failure, LogLevel.Error, ex.Message);
                }
            }
            finally
            {
                _isActing = false;
            }
        }