public void Monitor(EngineRoomServiceDB erdb, List <Message> messages, bool returnEventsOnly)
        {
            if (!Enabled)
            {
                return;
            }

            EngineRoomServiceDB.LogEventType let = EngineRoomServiceDB.LogEventType.INFO;
            String  desc = null;
            Message msg  = null;

            PumpState pumpState = StateOfPump;

            if (IsOn && DateTime.Now.Subtract(LastOn).TotalSeconds > MaxOnDuration)
            {
                StateOfPump = PumpState.ON_TOO_LONG;
            }
            else
            {
                StateOfPump = IsOn ? PumpState.ON : PumpState.OFF;
            }

            switch (StateOfPump)
            {
            case PumpState.ON_TOO_LONG:
                let  = EngineRoomServiceDB.LogEventType.WARNING;
                desc = String.Format("Pump is: {0}", StateOfPump);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(ID, BBAlarmsService.AlarmState.CRITICAL, desc);
                break;

            case PumpState.ON:
            case PumpState.OFF:
                let  = StateOfPump == PumpState.ON ? EngineRoomServiceDB.LogEventType.ON: EngineRoomServiceDB.LogEventType.OFF;
                desc = String.Format("Pump is: {0}", StateOfPump);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(ID, BBAlarmsService.AlarmState.OFF, desc);
                break;
            }
            if (msg != null && (pumpState != StateOfPump || !returnEventsOnly))
            {
                messages.Add(msg);
                if (returnEventsOnly)
                {
                    erdb.LogEvent(let, ID, desc);
                }
            }
        }
        public void Monitor(EngineRoomServiceDB erdb, List <Message> messages, bool returnEventsOnly)
        {
            if (!Enabled)
            {
                return;
            }

            EngineRoomServiceDB.LogEventType let = EngineRoomServiceDB.LogEventType.INFO;
            String  desc = null;
            Message msg  = null;

            //see if engine is Running (and log)
            bool running = Running; // record to test change of state

            Running = RPM.AverageRPM > IS_RUNNING_RPM_THRESHOLD;
            bool isEvent = running != Running;

            //Running or not
            if (isEvent) //log
            {
                if (Running)
                {
                    erdb.LogEvent(EngineRoomServiceDB.LogEventType.ON, ID, String.Format("Current RPM = {0}", RPM.RPM));
                    LastOn = erdb.GetLatestEvent(EngineRoomServiceDB.LogEventType.ON, ID).GetDateTime("created");
                }
                else
                {
                    desc = LastOn == default(DateTime) ? "N/A" : String.Format("Running for {0}", (DateTime.Now - LastOn).ToString("c"));
                    erdb.LogEvent(EngineRoomServiceDB.LogEventType.OFF, ID, desc);
                    LastOff = erdb.GetLatestEvent(EngineRoomServiceDB.LogEventType.OFF, ID).GetDateTime("created");
                }
            }

            if (isEvent || !returnEventsOnly)
            {
                EngineRoomMessageSchema schema = new EngineRoomMessageSchema(new Message(MessageType.DATA));
                schema.AddEngine(this);
                messages.Add(schema.Message);
            }


            //some useful durations...
            long secsSinceLastOn  = LastOn == default(DateTime) ? -1 : (long)DateTime.Now.Subtract(LastOn).TotalSeconds;
            long secsSinceLastOff = LastOff == default(DateTime) ? -1 : (long)DateTime.Now.Subtract(LastOff).TotalSeconds;

            //Oil State
            OilState oilState = StateOfOil;

            if (Running && RPM.RPM > 100 && secsSinceLastOn > 30)
            {
                oilState = OilSensor.IsOn ? OilState.NO_PRESSURE : OilState.OK_ENGINE_ON;
            }
            else if (!Running && RPM.RPM == 0 && secsSinceLastOff > 30)
            {
                oilState = OilSensor.IsOff ? OilState.SENSOR_FAULT : OilState.OK_ENGINE_OFF;
            }

            msg        = null;
            isEvent    = oilState != StateOfOil;
            StateOfOil = oilState;
            String rpmDesc = String.Format("RPM (instant/average) = {0}/{1}", RPM.RPM, RPM.AverageRPM);

            switch (StateOfOil)
            {
            case OilState.NO_PRESSURE:
                let  = EngineRoomServiceDB.LogEventType.WARNING;
                desc = String.Format("Engine {0} Oil sensor {1} gives {2} ... {3}", Running ? "running for " + secsSinceLastOn : "off for " + secsSinceLastOff, OilSensor.State, StateOfOil, rpmDesc);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(OilSensor.ID, BBAlarmsService.AlarmState.SEVERE, desc);
                break;

            case OilState.SENSOR_FAULT:
                let  = EngineRoomServiceDB.LogEventType.WARNING;
                desc = String.Format("Engine {0} Oil sensor {1} gives {2} ... {3}", Running ? "running for " + secsSinceLastOn : "off for " + secsSinceLastOff, OilSensor.State, StateOfOil, rpmDesc);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(OilSensor.ID, BBAlarmsService.AlarmState.MODERATE, desc);
                break;

            case OilState.OK_ENGINE_OFF:
            case OilState.OK_ENGINE_ON:
                let  = EngineRoomServiceDB.LogEventType.INFO;
                desc = String.Format("Engine {0} Oil sensor {1} gives {2}... {3}", Running ? "running for " + secsSinceLastOn : "off for " + secsSinceLastOff, OilSensor.State, StateOfOil, rpmDesc);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(OilSensor.ID, BBAlarmsService.AlarmState.OFF, desc);
                break;
            }

            if (msg != null && (isEvent || !returnEventsOnly))
            {
                messages.Add(msg);
                if (isEvent)
                {
                    erdb.LogEvent(let, OilSensor.ID, desc);
                }
            }


            //Temp state
            TemperatureState tempState = StateOfTemperature; //keep a record

            if (!Running || (TempSensor.AverageTemperature <= TemperatureThresholds[TemperatureState.OK]))
            {
                StateOfTemperature = TemperatureState.OK;
            }
            else if (TempSensor.AverageTemperature <= TemperatureThresholds[TemperatureState.HOT])
            {
                StateOfTemperature = TemperatureState.HOT;
            }
            else
            {
                StateOfTemperature = TemperatureState.TOO_HOT;
            }

            msg     = null;
            isEvent = tempState != StateOfTemperature;
            switch (StateOfTemperature)
            {
            case TemperatureState.TOO_HOT:
                let  = EngineRoomServiceDB.LogEventType.WARNING;
                desc = String.Format("Temp sensor: {0} {1}", TempSensor.AverageTemperature, StateOfTemperature);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(TempSensor.ID, BBAlarmsService.AlarmState.CRITICAL, desc);
                break;

            case TemperatureState.HOT:
                let  = EngineRoomServiceDB.LogEventType.WARNING;
                desc = String.Format("Temp sensor: {0} {1}", TempSensor.AverageTemperature, StateOfTemperature);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(TempSensor.ID, BBAlarmsService.AlarmState.SEVERE, desc);
                break;

            case TemperatureState.OK:
                let  = EngineRoomServiceDB.LogEventType.INFO;
                desc = String.Format("Temp sensor: {0} {1}", TempSensor.AverageTemperature, StateOfTemperature);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(TempSensor.ID, BBAlarmsService.AlarmState.OFF, desc);
                break;
            }
            if (msg != null && (isEvent || !returnEventsOnly))
            {
                messages.Add(msg);
                if (isEvent)
                {
                    erdb.LogEvent(let, TempSensor.ID, desc);
                }
            }

            //RPM state
            RPMState rpmState = StateOfRPM;

            if (!Running)
            {
                StateOfRPM = RPMState.OFF;
            }
            else if (secsSinceLastOn > 10)
            {
                if (RPM.AverageRPM < RPMThresholds[RPMState.SLOW])
                {
                    StateOfRPM = RPMState.SLOW;
                }
                else if (RPM.AverageRPM < RPMThresholds[RPMState.NORMAL])
                {
                    StateOfRPM = RPMState.NORMAL;
                }
                else if (RPM.AverageRPM < RPMThresholds[RPMState.FAST])
                {
                    StateOfRPM = RPMState.FAST;
                }
                else
                {
                    StateOfRPM = RPMState.TOO_FAST;
                }
            }

            msg     = null;
            isEvent = rpmState != StateOfRPM;
            switch (StateOfRPM)
            {
            case RPMState.OFF:
            case RPMState.SLOW:
            case RPMState.NORMAL:
                let  = EngineRoomServiceDB.LogEventType.INFO;
                desc = String.Format("RPM (Instant/Average): {0}/{1} gives state {2}", RPM.RPM, RPM.AverageRPM, StateOfRPM);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(RPM.ID, BBAlarmsService.AlarmState.OFF, desc);
                break;

            case RPMState.FAST:
                let  = EngineRoomServiceDB.LogEventType.WARNING;
                desc = String.Format("RPM (Instant/Average): {0}/{1} gives state {2}", RPM.RPM, RPM.AverageRPM, StateOfRPM);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(RPM.ID, BBAlarmsService.AlarmState.MODERATE, desc);
                break;

            case RPMState.TOO_FAST:
                let  = EngineRoomServiceDB.LogEventType.WARNING;
                desc = String.Format("RPM (Instant/Average): {0}/{1} gives state {2}", RPM.RPM, RPM.AverageRPM, StateOfRPM);
                msg  = BBAlarmsService.AlarmsMessageSchema.AlertAlarmStateChange(RPM.ID, BBAlarmsService.AlarmState.SEVERE, desc);
                break;
            }
            if (msg != null && (isEvent || !returnEventsOnly))
            {
                messages.Add(msg);
                if (isEvent)
                {
                    erdb.LogEvent(let, RPM.ID, desc);
                }
            }
        }
        override public bool HandleCommand(Connection cnn, Message message, String cmd, List <Object> args, Message response)
        {
            //return value of true/false determines whether response message is broadcast or not

            EngineRoomMessageSchema schema = new EngineRoomMessageSchema(response);
            Engine        engine;
            List <Engine> engines;
            bool          enable;

            Pump pump;

            switch (cmd)
            {
            case EngineRoomMessageSchema.COMMAND_TEST:
                //schema.AddPompaCelup(_pompaCelup);
                //Message alert = BBAlarmsService.BBAlarmsService.EngineRoomMessageSchema.RaiseAlarm(_pompaCelup.ID, true, "Test raising alarm");
                //Broadcast(alert);

                //Message
                return(false);

            case EngineRoomMessageSchema.COMMAND_LIST_ENGINES:
                engines = GetEngines();
                List <String> engineIDs = new List <String>();

                foreach (Engine eng in engines)
                {
                    if (eng.Enabled)
                    {
                        engineIDs.Add(eng.ID);
                    }
                }
                response.AddValue("Engines", engineIDs);
                return(true);

            case EngineRoomMessageSchema.COMMAND_ENGINE_STATUS:
                if (args == null || args.Count == 0 || args[0] == null)
                {
                    throw new Exception("No engine specified");
                }
                engine = GetEngine(args[0].ToString());
                if (engine == null)
                {
                    throw new Exception("Cannot find engine with ID " + args[0]);
                }
                schema.AddEngine(engine);

                if (engine.RPM != null)
                {
                    Task.Run(() => {
                        System.Threading.Thread.Sleep(250);
                        EngineRoomMessageSchema sc = new EngineRoomMessageSchema(new Message(MessageType.DATA, response.Target));
                        sc.AddRPM(engine.RPM);
                        SendMessage(sc.Message);
                    });
                }

                if (engine.OilSensor != null)
                {
                    Task.Run(() => {
                        System.Threading.Thread.Sleep(250);
                        EngineRoomMessageSchema sc = new EngineRoomMessageSchema(new Message(MessageType.DATA, response.Target));
                        sc.AddOilSensor(engine.OilSensor);
                        SendMessage(sc.Message);
                    });
                }

                if (engine.TempSensor != null)
                {
                    Task.Run(() => {
                        System.Threading.Thread.Sleep(250);
                        EngineRoomMessageSchema sc = new EngineRoomMessageSchema(new Message(MessageType.DATA, response.Target));
                        sc.AddDS18B20Sensor(engine.TempSensor);
                        SendMessage(sc.Message);
                    });
                }

                return(true);

            case EngineRoomMessageSchema.COMMAND_ENABLE_ENGINE:
                if (args == null || args.Count < 1)
                {
                    throw new Exception("No engine specified");
                }
                engine = GetEngine(args[0].ToString());
                if (engine == null)
                {
                    throw new Exception("Cannot find engine with ID " + args[0]);
                }
                enable = args.Count > 1 ? System.Convert.ToBoolean(args[1]) : true;
                if (enable != engine.Enabled)
                {
                    engine.Enable(enable);
                    EngineRoomServiceDB.LogEventType let = engine.Enabled ? EngineRoomServiceDB.LogEventType.ENABLE : EngineRoomServiceDB.LogEventType.DISABLE;
                    _erdb.LogEvent(let, engine.ID, let.ToString() + " engine " + engine.ID);
                    schema.AddEngine(engine);
                }
                return(true);

            case EngineRoomMessageSchema.COMMAND_PUMP_STATUS:
                if (args == null || args.Count == 0 || args[0] == null)
                {
                    throw new Exception("No pump specified");
                }
                pump = GetPump(args[0].ToString());
                schema.AddPump(pump);
                response.Type = MessageType.DATA;
                return(true);

            case EngineRoomMessageSchema.COMMAND_ENABLE_PUMP:
                if (args == null || args.Count == 0 || args[0] == null)
                {
                    throw new Exception("No pump specified");
                }
                pump   = GetPump(args[0].ToString());
                enable = args.Count > 1 ? System.Convert.ToBoolean(args[1]) : true;
                if (enable != pump.Enabled)
                {
                    pump.Enable(enable);
                    EngineRoomServiceDB.LogEventType let = pump.Enabled ? EngineRoomServiceDB.LogEventType.ENABLE : EngineRoomServiceDB.LogEventType.DISABLE;
                    _erdb.LogEvent(let, pump.ID, let.ToString() + " pump " + pump.ID);
                    schema.AddPump(pump);
                }
                return(true);

            case EngineRoomMessageSchema.COMMAND_WATER_TANK_STATUS:
                if (args == null || args.Count == 0 || args[0] == null)
                {
                    throw new Exception("No tank specified");
                }
                WaterTanks.FluidTank waterTank = (WaterTanks.FluidTank)_waterTanks.GetDevice(args[0].ToString());
                schema.AddWaterTank(waterTank);
                response.Type = MessageType.DATA;
                return(true);

            case EngineRoomMessageSchema.COMMAND_WATER_STATUS:
                schema.AddWaterTanks(_waterTanks);
                return(true);

            case EngineRoomMessageSchema.COMMAND_ENABLE_WATER:
                enable = args.Count > 0 ? System.Convert.ToBoolean(args[0]) : true;
                if (enable != _waterTanks.Enabled)
                {
                    _waterTanks.Enable(enable);
                    EngineRoomServiceDB.LogEventType let = _waterTanks.Enabled ? EngineRoomServiceDB.LogEventType.ENABLE : EngineRoomServiceDB.LogEventType.DISABLE;
                    _erdb.LogEvent(let, _waterTanks.ID, let.ToString() + " water tanks");
                    schema.AddWaterTanks(_waterTanks);
                }
                return(true);

            case BBAlarmsService.AlarmsMessageSchema.COMMAND_ALARM_STATUS:
                OnMonitorEngineRoomTimer(null, null);
                return(true);

            case BBAlarmsService.AlarmsMessageSchema.COMMAND_RAISE_ALARM:
                if (args == null || args.Count < 1)
                {
                    throw new Exception("No alarm specified");
                }
                String alarmID = args[0].ToString();
                BBAlarmsService.AlarmState alarmState = BBAlarmsService.AlarmState.CRITICAL;
                BBAlarmsService.AlarmsMessageSchema.RaiseAlarm(this, alarmID, alarmState, "Raised alarm", true);
                return(true);

            case BBAlarmsService.AlarmsMessageSchema.COMMAND_LOWER_ALARM:
                if (args == null || args.Count < 1)
                {
                    throw new Exception("No alarm specified");
                }
                BBAlarmsService.AlarmsMessageSchema.LowerAlarm(this, args[0].ToString(), BBAlarmsService.AlarmState.OFF, "Lowered alarm", true);
                return(true);

            default:
                return(base.HandleCommand(cnn, message, cmd, args, response));
            }
        }