//React to data coming from ADM
        protected override void HandleADMMessage(ADMMessage message, ArduinoDeviceManager adm)
        {
            ArduinoDevice           dev;
            EngineRoomMessageSchema schema = new EngineRoomMessageSchema(message);

            switch (message.Type)
            {
            case MessageType.DATA:
                if (message.Sender == null)
                {
                    dev = adm.GetDeviceByBoardID(message.TargetID);
                    if (dev is DS18B20Array)
                    {
                        schema.AddDS18B20Array((DS18B20Array)dev);
                        foreach (var sensor in ((DS18B20Array)dev).ConnectedSensors)
                        {
                            //outputSampleData(sensor.Sampler.GetSubjectData(sensor));
                            if (Output2Console)
                            {
                                Console.WriteLine("------------------------------> Average temp {0}: {1}", sensor.ID, sensor.AverageTemperature);
                            }
                        }
                    }

                    if (dev is WaterTanks.FluidTank)
                    {
                        schema.AddWaterTanks(_waterTanks);
                        WaterTanks.FluidTank ft = ((WaterTanks.FluidTank)dev);
                        schema.AddWaterTank(ft);
                        if (Output2Console)
                        {
                            Console.WriteLine("****************>: Water Tank {0} distance / average distance / percent / percent full: {1} / {2} / {3} / {4}", ft.ID, ft.Distance, ft.AverageDistance, ft.Percentage, ft.PercentFull);
                        }
                    }
                }
                else
                {
                    dev = adm.GetDevice(message.Sender);
                    if (dev == _pompaCelup)
                    {
                        schema.AddPump(_pompaCelup);
                        if (Output2Console)
                        {
                            Console.WriteLine("+++++++++++++++> Pump {0} {1}", dev.ID, _pompaCelup.IsOn);
                        }
                    }

                    if (dev == _pompaSolar)
                    {
                        schema.AddPump(_pompaSolar);
                        _erdb.LogEvent(_pompaSolar.IsOn ? EngineRoomServiceDB.LogEventType.ON : EngineRoomServiceDB.LogEventType.OFF, _pompaSolar.ID, "Pompa Solar");
                        if (Output2Console)
                        {
                            Console.WriteLine("+++++++++++++++> Pump {0} {1}", dev.ID, _pompaSolar.IsOn);
                        }
                    }

                    if (dev is Engine.OilSensorSwitch)
                    {
                        Engine.OilSensorSwitch os = (Engine.OilSensorSwitch)dev;
                        schema.AddOilSensor(os);
                        if (Output2Console)
                        {
                            Console.WriteLine("+++++++++++++++> Oil Sensor {0} {1}", os.ID, os.IsOn);
                        }
                    }
                }
                break;

            case MessageType.COMMAND_RESPONSE:
                dev = adm.GetDeviceByBoardID(message.TargetID);
                if (dev is RPMCounter)
                {
                    RPMCounter rpm = (RPMCounter)dev;
                    schema.AddRPM(rpm);
                    message.Type = MessageType.DATA;     //change the type so that it's more meaingful for listeners...

                    //TODO: remove
                    if (Output2Console)
                    {
                        Console.WriteLine("===============================> RPM {0}: {1}", rpm.ID, rpm.AverageRPM);
                    }
                }
                break;

            case MessageType.NOTIFICATION:
                break;

            case MessageType.CONFIGURE_RESPONSE:
                dev = adm.GetDeviceByBoardID(message.TargetID);
                if (dev is DS18B20Array)
                {
                    Tracing?.TraceEvent(TraceEventType.Information, 0, "Temperature array {0} on board {1} configured {2} sensors on one wire pin {3}", dev.ID, adm.BoardID, ((DS18B20Array)dev).ConnectedSensors.Count, message.GetInt(DS18B20Array.PARAM_ONE_WIRE_PIN));
                }
                break;

            case MessageType.PING_RESPONSE:
                //Console.WriteLine("Ping received from {0} ... gives AI={1}, FM={2},  MS={3}", adm.BoardID, message.GetValue("AI"), message.GetValue("FM"), message.GetValue("MS")); ;
                break;

            case MessageType.ERROR:
                try
                {
                    _erdb.LogEvent(EngineRoomServiceDB.LogEventType.ERROR, message.HasValue("ErrorSource") ? message.GetString("ErrorSource") : adm.PortAndNodeID, message.Value);
                } catch (Exception e)
                {
                    Tracing?.TraceEvent(TraceEventType.Error, 0, e.Message);
                }
                break;
            }
            base.HandleADMMessage(message, adm);
        }
        protected override void AddADMDevices(ArduinoDeviceManager adm, ADMMessage message)
        {
            if (adm == null || adm.BoardID == 0)
            {
                Tracing?.TraceEvent(TraceEventType.Error, 0, "adm is null or does not have a BoardID value");
                return;
            }

            adm.Tracing = Tracing;

            DS18B20Array temp;
            Engine       engine;
            RPMCounter   rpm;

            Engine.OilSensorSwitch oilSensor;
            String desc;

            switch (adm.BoardID)
            {
            case BOARD_ER1:
                //Temperature array for all engines connected to a board
                //Important!: this must come first as it disrupts subsequent messages if not first
                temp = new DS18B20Array(4, "temp_arr");
                temp.SampleInterval = TEMP_SAMPLE_INTERVAL;
                temp.SampleSize     = TEMP_SAMPLE_SIZE;
                temp.AddSensor(INDUK_ID + "_temp");
                temp.AddSensor(BANTU_ID + "_temp");
                adm.AddDevice(temp);

                //Pompa celup
                _pompaCelup = new Pump(10, POMPA_CELUP_ID);
                _pompaCelup.MaxOnDuration = 12 * 60;     //raise an alarm if on for more than 15 minutes
                _pompaCelup.Initialise(_erdb);
                _pompaCelup.SampleInterval = REQUEST_STATE_INTERVAL;
                _pompaCelup.SampleSize     = 1;
                adm.AddDevice(_pompaCelup);

                //Pompa solar
                _pompaSolar = new Pump(11, POMPA_SOLAR_ID);
                _pompaSolar.MaxOnDuration = 15 * 60;     //raise an alarm if on for more than 15 minutes
                _pompaSolar.Initialise(_erdb);
                _pompaSolar.SampleInterval = REQUEST_STATE_INTERVAL;
                _pompaSolar.SampleSize     = 1;
                adm.AddDevice(_pompaSolar);

                //Induk
                rpm = new RPMCounter(5, INDUK_ID + "_rpm", "RPM");
                rpm.SampleInterval  = RPM_SAMPLE_INTERVAL;
                rpm.SampleSize      = RPM_SAMPLE_SIZE;
                rpm.SamplingOptions = RPM_SAMPLING_OPTIONS;
                rpm.Calibration     = RPM_CALIBRATION_INDUK;

                oilSensor = new Engine.OilSensorSwitch(8, INDUK_ID + "_oil");
                oilSensor.SampleInterval = REQUEST_STATE_INTERVAL;
                oilSensor.SampleSize     = 1;

                engine = new Engine(INDUK_ID, rpm, oilSensor, temp.GetSensor(INDUK_ID + "_temp"));
                engine.Initialise(_erdb);
                adm.AddDeviceGroup(engine);

                //Bantu
                rpm = new RPMCounter(6, BANTU_ID + "_rpm", "RPM");
                rpm.SampleInterval  = RPM_SAMPLE_INTERVAL;
                rpm.SampleSize      = RPM_SAMPLE_SIZE;
                rpm.SamplingOptions = RPM_SAMPLING_OPTIONS;
                rpm.Calibration     = RPM_CALIBRATION_BANTU;

                oilSensor = new Engine.OilSensorSwitch(9, BANTU_ID + "_oil");
                oilSensor.SampleInterval = REQUEST_STATE_INTERVAL;
                oilSensor.SampleSize     = 1;

                engine = new Engine(BANTU_ID, rpm, oilSensor, temp.GetSensor(BANTU_ID + "_temp"));
                engine.Initialise(_erdb);
                adm.AddDeviceGroup(engine);
                break;

            case BOARD_ER2:
                //temperature array for all engines connected to a board
                temp = new DS18B20Array(4, "temp_arr");
                temp.SampleInterval = 2 * TEMP_SAMPLE_INTERVAL;
                temp.SampleSize     = TEMP_SAMPLE_SIZE;
                temp.AddSensor(GENSET2_ID + "_temp");
                temp.AddSensor(GENSET1_ID + "_temp");
                adm.AddDevice(temp);

                //genset 1
                rpm = new RPMCounter(6, GENSET1_ID + "_rpm", "RPM");
                rpm.SampleInterval  = RPM_SAMPLE_INTERVAL;
                rpm.SampleSize      = RPM_SAMPLE_SIZE;
                rpm.SamplingOptions = RPM_SAMPLING_OPTIONS;
                rpm.Calibration     = RPM_CALIBRATION_GENSET1;

                oilSensor = new Engine.OilSensorSwitch(9, GENSET1_ID + "_oil");
                oilSensor.SampleInterval = REQUEST_STATE_INTERVAL;
                oilSensor.SampleSize     = 1;

                engine = new Engine(GENSET1_ID, rpm, oilSensor, temp.GetSensor(GENSET1_ID + "_temp"));
                engine.Initialise(_erdb);
                adm.AddDeviceGroup(engine);

                //genset 2
                rpm = new RPMCounter(5, GENSET2_ID + "_rpm", "RPM");
                rpm.SampleInterval  = RPM_SAMPLE_INTERVAL;
                rpm.SampleSize      = RPM_SAMPLE_SIZE;
                rpm.SamplingOptions = RPM_SAMPLING_OPTIONS;
                rpm.Calibration     = RPM_CALIBRATION_GENSET2;

                oilSensor = new Engine.OilSensorSwitch(8, GENSET2_ID + "_oil");
                oilSensor.SampleInterval = REQUEST_STATE_INTERVAL;
                oilSensor.SampleSize     = 1;

                engine = new Engine(GENSET2_ID, rpm, oilSensor, temp.GetSensor(GENSET2_ID + "_temp"));
                engine.Initialise(_erdb);
                adm.AddDeviceGroup(engine);
                break;

            case BOARD_ER3:
                _waterTanks = new WaterTanks();
                _waterTanks.AddTank("wt1", 4, 5, 1200, 28, 102);
                _waterTanks.AddTank("wt2", 6, 7, 1100, 28, 110);
                _waterTanks.AddTank("wt3", 8, 9, 1100, 28, 100);
                _waterTanks.AddTank("wt4", 10, 11, 1100, 32, 100);
                _waterTanks.Initialise(_erdb);
                adm.AddDeviceGroup(_waterTanks);
                break;
            } //end board switch
        }