コード例 #1
0
        async Task SendMacAddressToCosmos(List <WiFiDevice> wiFiDevices)
        {
            _sendListData = new SendDataAzure();
            double timeOffset = METHOD.DateTimeTZ().Offset.TotalHours;

            //prepare the list to send into CosmosDB
            var AllWiFiDevices = new List <Localdevice>();

            wiFiDevices.ForEach(x => AllWiFiDevices.Add(new Localdevice()
            {
                ActiveDuration = x.ActiveDuration,
                DeviceName     = x.DeviceName,
                DeviceOwner    = x.DeviceOwner,
                DeviceType     = x.DeviceType,
                MacAddress     = x.MacAddress,
                StatusFrom     = METHOD.UnixTimeStampToDateTime(x.StatusUnixTime).AddHours(timeOffset),
                IsPresent      = x.IsPresent,
                SignalType     = x.SignalType,
                AccessPoint    = x.AccessPoint,
                IsChanged      = x.IsChanged
            }));
            TelemetryDataClass.SourceInfo = $"WiFi Devices";
            //send data to CosmosDB
            var monitorData = new
            {
                DeviceID    = "HomeController",
                status      = TelemetryDataClass.SourceInfo,
                DateAndTime = METHOD.DateTimeTZ().DateTime,
                AllWiFiDevices
            };
            await _sendListData.PipeMessage(monitorData, Program.IoTHubModuleClient, TelemetryDataClass.SourceInfo, "output");
        }
コード例 #2
0
        public async Task SendData()
        {
            _sendListData = new SendDataAzure();
            var monitorData = new
            {
                DeviceID = "HomeController",
                status   = TelemetryDataClass.SourceInfo,
                TelemetryDataClass.RoomHeatingInMinutes,
                TelemetryDataClass.WaterHeatingInMinutes,
                TelemetryDataClass.VentilationInMinutes,
                UtcOffset   = METHOD.DateTimeTZ().Offset.Hours,
                DateAndTime = METHOD.DateTimeTZ(),
            };
            await _sendListData.PipeMessage(monitorData, Program.IoTHubModuleClient, TelemetryDataClass.SourceInfo, "outputStream");

            return;
        }
コード例 #3
0
        public async Task SendDataAsync()
        {
            _sendListData = new SendDataAzure();
            var monitorData = new
            {
                DeviceID = "SecurityController",
                door     = "Garage",
                status,
                isHomeSecured,
                date        = DateTimeTZ().ToString("dd.MM"),
                time        = DateTimeTZ().ToString("HH:mm"),
                DateAndTime = DateTimeTZ().DateTime,
                alertingSensors
            };
            var messageJson = JsonSerializer.Serialize(monitorData);
            var IoTmessage  = new Message(Encoding.ASCII.GetBytes(messageJson));
            await _sendListData.PipeMessage(IoTmessage, Program.IoTHubModuleClient, $"{Message}");

            alertingSensors.Clear();
        }
コード例 #4
0
        public async void IRSensorsReading()
        {
            _sendListData = new SendDataAzure();
            State NONE = new State {
                DoorValue = false, IRValue = false
            };                                                             //door closed, IR passive
            State DOOR = new State {
                DoorValue = true, IRValue = false
            };                                                            //door open, IR passive
            State ALL = new State {
                DoorValue = true, IRValue = true
            };                                                          //door open, IR active
            State IR = new State {
                DoorValue = false, IRValue = true
            };                                                          //door closed, IR active
            List <State> Entry = new List <State> {
                NONE, DOOR, ALL, IR, NONE
            };
            List <State> Entry2 = new List <State> {
                NONE, DOOR, ALL, DOOR, NONE
            };
            List <State> Exit = new List <State> {
                NONE, IR, NONE, DOOR, ALL, IR, NONE
            };
            List <State> Exit1 = new List <State> {
                NONE, IR, NONE, DOOR, ALL, DOOR, NONE
            };
            List <State> Exit2 = new List <State> {
                NONE, IR, ALL, DOOR, ALL, IR, NONE
            };
            List <State> Exit3 = new List <State> {
                NONE, IR, ALL, IR, NONE
            };
            List <State> Exit4 = new List <State> {
                NONE, IR, ALL, DOOR, NONE
            };
            List <State> DoorOpenClose = new List <State> {
                NONE, DOOR, NONE
            };
            List <State> RepeatDoorAll = new List <State> {
                DOOR, ALL
            };                                                         //repeat
            List <State> RepeatAllDoor = new List <State> {
                ALL, DOOR
            };                                                         //repeat
            List <State> RepeatIRAll = new List <State> {
                IR, ALL
            };                                                     //repeat
            List <State> _queue = new List <State>
            {
                new State {
                    DoorValue = false, IRValue = false
                }
            };
            DateTime lastSentTime = METHOD.DateTimeTZ().DateTime;

            while (true)
            {
                try
                {
                    DateTime CurrentDateTime = METHOD.DateTimeTZ().DateTime;
                    //check the last zone event time to report is there anybody at home
                    Zone LastActiveZone            = Zones.First(x => x.ZoneId == LastActiveZoneID);
                    var  timerInMinutes            = TelemetryDataClass.isHomeSecured ? CONSTANT.TIMER_MINUTES_WHEN_SECURED_HOME_EMPTY : CONSTANT.TIMER_MINUTES_WHEN_HOME_EMPTY;
                    var  DurationUntilHouseIsEmpty = !LastActiveZone.IsZoneOpen ? (CurrentDateTime - LastActiveZone.ZoneEventTime).TotalMinutes : 0;
                    SomeoneAtHome.IsSomeoneAtHome = DurationUntilHouseIsEmpty < timerInMinutes || WiFiProbes.IsAnyMobileAtHome;

                    //check each zone in 2 minutes window to report the zone active time
                    foreach (var zone in Zones)
                    {
                        var durationUntilZoneIsEmpty = !zone.IsZoneOpen ? (CurrentDateTime - zone.ZoneEventTime).TotalSeconds : 0;
                        zone.IsZoneEmpty = durationUntilZoneIsEmpty > CONSTANT.TIMER_SECONDS_WHEN_ZONE_EMPTY;
                        if (zone.IsZoneEmpty && zone.ZoneEmptyDetectTime != DateTime.MinValue)
                        {
                            //add alerting sensors into list
                            alertingSensors.Add(new AlertingZone(zone.ZoneName, zone.ZoneEmptyDetectTime.ToString("dd.MM"), zone.ZoneEmptyDetectTime.ToString("HH:mm"), zone.ZoneEventTime.ToString("HH:mm"), zone.IsHomeSecured));
                            //Console.WriteLine($" {zone.ZoneName} {zone.ZoneEmptyDetectTime:t} - {zone.ZoneEventTime:t} {zone.ZoneEmptyDetectTime:dd.MM} {(zone.IsHomeSecured ? "SECURED" : null)}");
                            zone.ZoneEmptyDetectTime = new DateTime();
                        }
                        if (!zone.IsZoneEmpty && zone.ZoneEmptyDetectTime == DateTime.MinValue)
                        {
                            zone.ZoneEmptyDetectTime = CurrentDateTime;
                        }
                    }

                    //if home secured forcing outside lights ON
                    if (TelemetryDataClass.isHomeSecured && SomeoneAtHome.IsSomeoneAtHome && !TelemetryDataClass.isOutsideLightsOn)
                    {
                        SomeoneAtHome.LightsManuallyOnOff    = true;
                        TelemetryDataClass.isOutsideLightsOn = await Shelly.SetShellySwitch(true, Shelly.OutsideLight, nameof(Shelly.OutsideLight));
                    }

                    var DurationUntilToSendData = alertingSensors.Any() ? (CurrentDateTime - lastSentTime).TotalMinutes : 0;
                    var isTimeToSendData        = DurationUntilToSendData > CONSTANT.TIMER_MINUTES_TO_SEND_ZONE_COSMOS;
                    if (isTimeToSendData)
                    {
                        alertingSensors.Reverse();
                        TelemetryDataClass.SourceInfo = $"Zones activity {alertingSensors.Count}";

                        //check if the last zone was added into list during the home was secured
                        bool         isLastZoneSecured = false;
                        string       lastZoneName      = null;
                        AlertingZone LastZone          = alertingSensors.First();
                        lastZoneName      = LastZone.ZoneName;
                        isLastZoneSecured = LastZone.IsHomeSecured;
                        string sensorsOpen = "";
                        //run the alert only if home is secured and there are some alerting zone
                        if (TelemetryDataClass.isHomeSecured && isLastZoneSecured)
                        {
                            TelemetryDataClass.SourceInfo = $"Home secured {lastZoneName}";
                            sensorsOpen = "Look where someone is moving:\n\n";
                            foreach (var zone in alertingSensors)
                            {
                                //create a string with all zones for an e-mail
                                if (zone.IsHomeSecured)
                                {
                                    sensorsOpen += $" {zone.ZoneName} {zone.TimeStart} - {zone.TimeEnd}\n";
                                }
                            }
                            alertingSensors.ForEach(x => Console.WriteLine($"{x.ZoneName} {x.TimeStart} - {x.TimeEnd} {(x.IsHomeSecured ? "SECURED" : null)}"));
                        }
                        var monitorData = new
                        {
                            DeviceID = "HomeController",
                            TelemetryDataClass.SourceInfo,
                            TelemetryDataClass.isHomeSecured,
                            DateAndTime = CurrentDateTime,
                            alertingSensors,
                            date   = CurrentDateTime.ToString("dd.MM"),
                            time   = CurrentDateTime.ToString("HH:mm"),
                            status = sensorsOpen
                        };
                        await _sendListData.PipeMessage(monitorData, Program.IoTHubModuleClient, TelemetryDataClass.SourceInfo, "output");

                        alertingSensors.Clear();
                        lastSentTime = CurrentDateTime;
                    }

                    //maximum is 1000 items in alertingSensor list
                    if (alertingSensors.Count >= CONSTANT.MAX_ITEMS_IN_ALERTING_LIST)
                    {
                        alertingSensors.RemoveAt(0);
                    }

                    Zone doorZone    = Zones.First(ir => ir.ZoneId == 1);
                    Zone IrZone      = Zones.First(ir => ir.ZoneId == 2);
                    Zone smokeZone   = Zones.First(ir => ir.ZoneId == 7);
                    bool isDoorOpen  = doorZone.IsZoneOpen;
                    bool isIrOpen    = IrZone.IsZoneOpen;
                    bool isSmokeOpen = smokeZone.IsZoneOpen;
                    TelemetryDataClass.isHomeDoorOpen = isDoorOpen;

                    //if door opens or someone in entry then turn on Entry light. Shelly is configured to turn off after 2 minutes
                    if (isDoorOpen || isIrOpen)
                    {
                        await Shelly.SetShellySwitch(true, Shelly.EntryLight, nameof(Shelly.EntryLight));
                    }

                    //if door or IR is closed more that 2 minutes then clear the queue
                    var  LastActive         = doorZone.ZoneEventTime > IrZone.ZoneEventTime ? doorZone.ZoneEventTime : IrZone.ZoneEventTime;
                    var  durationUntilReset = _queue.Count > 1 ? (CurrentDateTime - LastActive).TotalSeconds : 0;
                    bool isClearTime        = durationUntilReset > CONSTANT.TIMER_SECONDS_CLEAR_DOOR_QUEUE;
                    if (isClearTime && !isDoorOpen)
                    {
                        _queue.Clear();
                        _queue.Add(new State {
                            DoorValue = false, IRValue = false
                        });
                        //Console.WriteLine($"{CurrentDateTime:T} queue cleared");
                    }

                    //save the door and IR statuses for the queue
                    State _state = new State {
                        DoorValue = isDoorOpen, IRValue = isIrOpen
                    };

                    if (_queue.Count > 6)
                    {
                        _queue = new List <State>(Helpers.Rotate(_queue, 1));
                        _queue.RemoveAt(_queue.Count - 1);
                    }

                    //if list is empty, then return both open, otherwise last item
                    State lastItem = (_queue.Count != 0) ? _queue[_queue.Count - 1] : new State {
                        DoorValue = true, IRValue = true
                    };
                    string status = "No pattern";

                    if (_state != lastItem)
                    {
                        _queue.Add(_state);
                        if (RemoveDuplicate(_queue, RepeatDoorAll))
                        {
                            Console.WriteLine($"Door-All duplicate removed");
                        }
                        if (RemoveDuplicate(_queue, RepeatAllDoor))
                        {
                            Console.WriteLine($"All-Door duplicate removed");
                        }
                        if (RemoveDuplicate(_queue, RepeatIRAll))
                        {
                            Console.WriteLine($"IR-All duplicate removed");
                        }

                        if (_queue.Count > 2) //only check pattern if there are more than 3 events in queue
                        {
                            if (ContainsPattern(_queue, Entry))
                            {
                                status = "entry";
                            }
                            if (ContainsPattern(_queue, Entry2))
                            {
                                status = "entry 2";
                            }
                            if (ContainsPattern(_queue, Exit))
                            {
                                status = "exit";
                            }
                            if (ContainsPattern(_queue, Exit1))
                            {
                                status = "exit 1";
                            }
                            if (ContainsPattern(_queue, Exit2))
                            {
                                status = "exit 2";
                            }
                            if (ContainsPattern(_queue, Exit3))
                            {
                                status = "exit 3";
                            }
                            if (ContainsPattern(_queue, Exit4))
                            {
                                status = "exit 4";
                            }
                            if (ContainsPattern(_queue, DoorOpenClose))
                            {
                                status = "door open-closed";
                            }
                        }
                    }
                    if (status != "No pattern")
                    {
                        _queue.Clear(); //clear queue and pattern
                        _queue.Add(new State {
                            DoorValue = false, IRValue = false
                        });                                                           //add first all-closed pattern

                        TelemetryDataClass.SourceInfo = $"Home {status}";
                        var monitorData = new
                        {
                            DeviceID = "SecurityController",
                            door     = "Home",
                            status   = TelemetryDataClass.SourceInfo,
                            TelemetryDataClass.isHomeSecured,
                            date        = CurrentDateTime.ToString("dd.MM"),
                            time        = CurrentDateTime.ToString("HH:mm"),
                            DateAndTime = CurrentDateTime
                        };
                        await _sendListData.PipeMessage(monitorData, Program.IoTHubModuleClient, TelemetryDataClass.SourceInfo, "output");

                        status = "No pattern";
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Paradox exception: {e}");
                }
                await Task.Delay(TimeSpan.FromMilliseconds(10)); //check statuses every 10 millisecond
            }
        }
コード例 #5
0
        public async void ReadTemperature()
        {
            var _receiveData   = new ReceiveData();
            var _sensorsClient = new RinsenOneWireClient();
            var _sendListData  = new SendDataAzure();
            var Methods        = new METHOD();
            //currentSumOfTempDeltas is some bigger number than the delta (0,5) is used to determine temperature changes
            double SumOfTemperatureDeltas = 10;

            //initiate the list with the temps and names
            ListOfAllSensors = await _sensorsClient.ReadSensors();

            //fill out LastTemperatures and initial Temperature trend which is initially always TRUE
            ListOfAllSensors = UpdateSensorsTrendAndLastTemp(ListOfAllSensors, ListOfAllSensors);

            var filename = Methods.GetFilePath(CONSTANT.FILENAME_ROOM_TEMPERATURES);

            if (File.Exists(filename))
            {
                var dataFromFile = await Methods.OpenExistingFile(filename);

                List <SensorReading> SetRoomTemps = JsonSerializer.Deserialize <List <SensorReading> >(dataFromFile);
                SetTemperatures(SetRoomTemps);
            }
            while (true)
            {
                //get a new sensor readings and then update
                SensorReadings sensorReadings = await _sensorsClient.ReadSensors();

                ListOfAllSensors = UpdateSensorsTrendAndLastTemp(ListOfAllSensors, sensorReadings);

                //summing all the room temperature changes together add new deltas until it bigger that 4 degrees
                SumOfTemperatureDeltas += ListOfAllSensors.Temperatures.Where(x => x.isRoom).Sum(x => Math.Abs(x.Temperature - x.LastTemperature));

                //manage Livingroom heating actuator
                if (ListOfAllSensors.Temperatures.FirstOrDefault(x => x.RoomName == LIVING).isHeatingRequired)
                {
                    Pins.PinWrite(Pins.livingRoomHeatControlOut, PinValue.High);
                }
                else
                {
                    Pins.PinWrite(Pins.livingRoomHeatControlOut, PinValue.Low);
                }

                //manage Office heating actuator
                if (ListOfAllSensors.Temperatures.FirstOrDefault(x => x.RoomName == OFFICE).isHeatingRequired)
                {
                    Pins.PinWrite(Pins.homeOfficeHeatControlOut, PinValue.High);
                }
                else
                {
                    Pins.PinWrite(Pins.homeOfficeHeatControlOut, PinValue.Low);
                }

                //manage Piano heating actuator
                bool isPianoHeatingOn = ListOfAllSensors.Temperatures.FirstOrDefault(x => x.RoomName == PIANO).isHeatingRequired;
                await Shelly.SetShellySwitch(isPianoHeatingOn, Shelly.PianoHeating, nameof(Shelly.PianoHeating));

                //manage Bedroom heating actuator
                bool isBedroomHeatingOn = ListOfAllSensors.Temperatures.FirstOrDefault(x => x.RoomName == BEDROOM).isHeatingRequired;
                await Shelly.SetShellySwitch(isBedroomHeatingOn, Shelly.BedroomHeating, nameof(Shelly.BedroomHeating));

                //manage sauna temperature
                if (ListOfAllSensors.Temperatures.FirstOrDefault(x => x.RoomName == SAUNA).isHeatingRequired&& TelemetryDataClass.isSaunaOn)
                {
                    Pins.PinWrite(Pins.saunaHeatOutPin, PinValue.Low);
                }
                else
                {
                    Pins.PinWrite(Pins.saunaHeatOutPin, PinValue.High);
                }
                //if sauna extremely hot, then turn off
                if (ListOfAllSensors.Temperatures.FirstOrDefault(x => x.RoomName == SAUNA).Temperature > CONSTANT.EXTREME_SAUNA_TEMP)
                {
                    _receiveData.ProcessCommand(CommandNames.TURN_OFF_SAUNA);
                }

                //if all rooms has achieved their target temperature then turn system off
                if (ListOfAllSensors.Temperatures.Where(x => x.isRoom).All(x => !x.isHeatingRequired))
                {
                    _receiveData.ProcessCommand(CommandNames.REDUCE_TEMP_COMMAND);
                }

                //if all room temperatures together has changed more that 3 degrees then send it out to database
                if (Math.Abs(SumOfTemperatureDeltas) > 4)
                {
                    TelemetryDataClass.SourceInfo = $"Room temp changed {SumOfTemperatureDeltas:0.0}";
                    var monitorData = new
                    {
                        DeviceID    = "RoomTemperatures",
                        UtcOffset   = METHOD.DateTimeTZ().Offset.Hours,
                        DateAndTime = METHOD.DateTimeTZ().DateTime,
                        time        = METHOD.DateTimeTZ().ToString("HH:mm"),
                        TelemetryDataClass.SourceInfo,
                        ListOfAllSensors.Temperatures
                    };
                    await _sendListData.PipeMessage(monitorData, Program.IoTHubModuleClient, TelemetryDataClass.SourceInfo, "output");

                    SumOfTemperatureDeltas = 0;            //resetting to start summing up again
                }
                await Task.Delay(TimeSpan.FromMinutes(1)); //check temperatures every minute
            }
        }
コード例 #6
0
        public async void QueryWiFiProbes()
        {
            http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{username}:{password}")));

            var filename = Methods.GetFilePath(CONSTANT.FILENAME_HOME_DEVICES);

            try
            {
                //open file and -> list of devices from Raspberry if the file exists
                if (File.Exists(filename))
                {
                    var result = await Methods.OpenExistingFile(filename);

                    WiFiDevice.WellKnownDevices = JsonSerializer.Deserialize <List <WiFiDevice> >(result).ToList();
                }
                else
                {
                    double unixTimestamp = DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
                    //following will happen only if there is no file on Raspberry and the list will be loaded from the environment variables
                    WiFiDevice.WellKnownDevices.ForEach(x => x.StatusUnixTime = unixTimestamp);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"open file {e}");
            }

            await SendMacAddressToCosmos(WiFiDevice.WellKnownDevices);

            bool isAnyDeviceChanged = true;
            var  UnknownDevices     = new List <WiFiDevice>();

            while (true)
            {
                double unixTimestamp = METHOD.DateTimeToUnixTimestamp(DateTime.UtcNow);
                double timeOffset    = METHOD.DateTimeTZ().Offset.TotalHours;

                //if there are some items from PowerApps then proceed
                if (WiFiDevicesFromPowerApps.Any())
                {
                    //Add, Remove or Change WiFiDevices list according to WiFiDevices From PowerApps
                    WiFiDevice.WellKnownDevices = AddRemoveChangeDevices(WiFiDevicesFromPowerApps, WiFiDevice.WellKnownDevices);
                    WiFiDevicesFromPowerApps.Clear();
                    //send all devices to CosmosDB
                    await SendMacAddressToCosmos(WiFiDevice.WellKnownDevices);
                }
                //prepare multimac query
                //create a list of the MAC Addresses for multimac query
                List <string> deviceMacs = new List <string>();
                WiFiDevice.WellKnownDevices.ForEach(x => deviceMacs.Add(x.MacAddress));
                string            jsonMacAddresses     = JsonSerializer.Serialize(deviceMacs);
                string            urlMultiMac          = $"{urlKismet}/devices/multimac/devices.json";
                string            jsonContentFieldsMac = "json={\"fields\":" + jsonFields + ",\"devices\":" + jsonMacAddresses + "}";
                List <WiFiDevice> KismetKnownDevices   = await GetDevices(urlMultiMac, jsonContentFieldsMac);

                //clear devices list.
                WiFiDevicesToPowerApps.Clear();
                //building list of the local devices which are last seen
                foreach (var knownDevice in WiFiDevice.WellKnownDevices)
                {
                    foreach (var kismet in KismetKnownDevices)
                    {
                        if (knownDevice.MacAddress == kismet.MacAddress)
                        {
                            knownDevice.LastUnixTime = kismet.LastUnixTime;
                            knownDevice.LastSignal   = kismet.LastSignal;
                            knownDevice.SignalType   = kismet.SignalType;
                            knownDevice.SSID         = kismet.SSID;
                            knownDevice.WiFiName     = kismet.ProbedSSID;
                            if (kismet.SignalType.Contains("Wi-Fi"))
                            {
                                knownDevice.AccessPoint = WiFiDevice.WellKnownDevices.Where(x => x.MacAddress == kismet.LastBSSID).Select(x => x.DeviceName).DefaultIfEmpty("No AP").First();
                                if (string.IsNullOrEmpty(knownDevice.WiFiName) || knownDevice.WiFiName == "0")
                                {
                                    knownDevice.WiFiName = WiFiDevice.WellKnownDevices.Where(x => x.MacAddress == kismet.LastBSSID).Select(x => x.SSID).DefaultIfEmpty("No AP").First();
                                }
                            }
                            break;
                        }
                    }
                    //checking active devices and setting Active/NonActive statuses. Each device can have individual timewindow
                    knownDevice.IsChanged = false;                                                //this is just for debugging, no other reason
                    var durationUntilNotActive = (unixTimestamp - knownDevice.LastUnixTime) / 60; //timestamp in minutes
                    knownDevice.IsPresent = durationUntilNotActive < knownDevice.ActiveDuration;
                    if (knownDevice.IsPresent && !knownDevice.StatusChange)
                    {
                        knownDevice.StatusUnixTime = unixTimestamp;
                        knownDevice.StatusChange   = true;
                        isAnyDeviceChanged         = true;
                        knownDevice.IsChanged      = true;
                    }
                    if (!knownDevice.IsPresent && knownDevice.StatusChange)
                    {
                        knownDevice.StatusUnixTime = knownDevice.LastUnixTime;
                        knownDevice.StatusChange   = false;
                        isAnyDeviceChanged         = true;
                        knownDevice.IsChanged      = true;
                    }
                    //following list WiFiDevicesToPowerApps is used to send minimal data to PowerApps (sending only userdevices)
                    //this list will be sent as a response after PowerApps asks something or refreshing it's data
                    if (knownDevice.DeviceType != WiFiDevice.DEVICE)
                    {
                        WiFiDevicesToPowerApps.Add(new Localdevice()
                        {
                            DeviceOwner    = knownDevice.DeviceOwner,
                            DeviceName     = knownDevice.DeviceName,
                            DeviceType     = knownDevice.DeviceType,
                            IsPresent      = knownDevice.IsPresent,
                            StatusFrom     = METHOD.UnixTimeStampToDateTime(knownDevice.StatusUnixTime),
                            ActiveDuration = knownDevice.ActiveDuration,
                            MacAddress     = knownDevice.MacAddress,
                            SignalType     = knownDevice.SignalType,
                            IsChanged      = knownDevice.IsChanged
                        });
                    }
                    //build a list with the names who is expected to track
                    //this list will be sent through Azure Functions to the owners e-mail
                    if (knownDevice.DeviceType == WiFiDevice.MOBILE || knownDevice.DeviceType == WiFiDevice.WATCH || knownDevice.DeviceType == WiFiDevice.CAR)
                    {
                        //to be sure that every person is listed just once
                        if (!WiFiDevicesWhoIsChanged.Any(x => x.DeviceOwner == knownDevice.DeviceOwner) || !WiFiDevicesWhoIsChanged.Any())
                        {
                            WiFiDevicesWhoIsChanged.Add(new Localdevice()
                            {
                                DeviceOwner = knownDevice.DeviceOwner,
                                DeviceName  = knownDevice.DeviceName,
                                IsPresent   = knownDevice.IsPresent,
                                StatusFrom  = METHOD.UnixTimeStampToDateTime(knownDevice.StatusUnixTime),
                                SignalType  = knownDevice.SignalType,
                                IsChanged   = knownDevice.IsChanged
                            });
                        }
                    }
                }

                //update the list of the correct statuses, are they home or away
                foreach (var item in WiFiDevicesWhoIsChanged)
                {
                    item.IsChanged = false;
                    foreach (var device in WiFiDevicesToPowerApps)
                    {
                        if (item.DeviceOwner == device.DeviceOwner && (device.DeviceType == WiFiDevice.MOBILE || device.DeviceType == WiFiDevice.WATCH || device.DeviceType == WiFiDevice.CAR))
                        {
                            if (device.IsChanged)
                            {
                                item.IsChanged  = device.IsChanged;
                                item.DeviceName = device.DeviceName;
                                item.StatusFrom = device.StatusFrom.AddHours(timeOffset);
                                item.SignalType = device.SignalType;
                                item.IsPresent  = device.IsPresent;
                            }
                            //if device is exist and has'nt been changed, then mark it as unchanged and move to next item
                            //if device is not exist (not seen) but has been changed then mark it as unchanged and move to next item = do not notify leaving devices
                            //this is XOR
                            if (device.IsPresent ^ device.IsChanged)
                            {
                                item.IsChanged = false;
                                break;
                            }
                        }
                    }
                }

                //save the data locally into Raspberry
                var jsonString = JsonSerializer.Serialize(WiFiDevice.WellKnownDevices);
                await Methods.SaveStringToLocalFile(filename, jsonString);

                //send an e-mail only if someone has arrived at home or left the home
                if (WiFiDevicesWhoIsChanged.Any(x => x.IsChanged))
                {
                    string status = "Look who is at home:\n\n";

                    WiFiDevicesWhoIsChanged.ForEach(x => status += $"{(x.IsPresent ? x.DeviceOwner + " " + x.DeviceName + " at home from" : x.DeviceOwner + " not seen since")} {x.StatusFrom:HH:mm dd.MM.yyyy} \n ");
                    var    x          = WiFiDevicesWhoIsChanged.First(x => x.IsChanged);
                    string whoChanged = $"{(x.IsPresent ? x.DeviceOwner + " at home " : x.DeviceOwner + " not seen since")} {x.StatusFrom:HH:mm dd.MM.yyyy}";
                    _sendListData = new SendDataAzure();
                    TelemetryDataClass.SourceInfo = $"{whoChanged}";
                    //send data to CosmosDB
                    var monitorData = new
                    {
                        DeviceID = "HomeController",
                        TelemetryDataClass.SourceInfo,
                        status,
                        DateAndTime   = METHOD.DateTimeTZ().DateTime,
                        isHomeSecured = true
                    };
                    await _sendListData.PipeMessage(monitorData, Program.IoTHubModuleClient, TelemetryDataClass.SourceInfo, "output");
                }


                //if any mobile phone or watch is present then someone is at home
                IsAnyMobileAtHome = WiFiDevice.WellKnownDevices.Any(x => x.IsPresent && (x.DeviceType == WiFiDevice.MOBILE || x.DeviceType == WiFiDevice.WATCH || x.DeviceType == WiFiDevice.CAR));
                //if security mode automatic and home secured then unsecure home if any known mobile device is seen
                if (IsAnyMobileAtHome && TelemetryDataClass.isHomeSecured && !SomeoneAtHome.IsSecurityManuallyOn)
                {
                    SomeoneAtHome.SomeoneAtHomeChanged();
                }

                #region Known Device Listing, only for debugging

                //for local debugging only show the active/non active devices in console window
                if (isAnyDeviceChanged)
                {
                    isAnyDeviceChanged = false;
                    var sortedList = WiFiDevice.WellKnownDevices.OrderByDescending(y => y.IsPresent).ThenBy(w => w.AccessPoint).ThenBy(z => z.SignalType).ThenBy(x => x.DeviceName).ToList();
                    Console.WriteLine();
                    Console.WriteLine($"All known devices at: {METHOD.DateTimeTZ().DateTime:G}");
                    Console.WriteLine();
                    Console.WriteLine($"   |   From   | Status  |          Device           |        WiFi network      |        AccessPoint       |  SignalType");
                    Console.WriteLine($"   |  ------  | ------- |         --------          |           -----          |           -----          |  --------  ");
                    foreach (var device in sortedList)
                    {
                        if (device.LastUnixTime > 0 && device.SignalType != "Wi-Fi AP" && device.DeviceOwner != "Unknown" && device.DeviceType != WiFiDevice.DEVICE) //show only my own ever seen LocalUserDevices devices
                        {
                            Console.WriteLine($" {(device.IsChanged ? "1" : " ")} " +
                                              $"| {METHOD.UnixTimeStampToDateTime(device.StatusUnixTime).AddHours(timeOffset):T} " +
                                              $"| {(device.IsPresent ? "Active " : "Not Act")} " +
                                              $"| {device.DeviceName}{"".PadRight(26 - (device.DeviceName.Length > 26 ? 26 : device.DeviceName.Length))}" +
                                              $"| {device.WiFiName}{"".PadRight(26 - (!string.IsNullOrEmpty(device.WiFiName) ? (device.WiFiName.Length > 26 ? 26 : device.WiFiName.Length) : 0))}" +
                                              $"| {device.AccessPoint}{"".PadRight(26 - (!string.IsNullOrEmpty(device.AccessPoint) ? (device.AccessPoint.Length > 26 ? 26 : device.AccessPoint.Length) : 0))}" +
                                              $"| {device.SignalType} ");
                        }
                    }
                    Console.WriteLine();
                }

                #endregion

                #region Unknown Devices Debugging

                //prepare last active devices query
                string            urlLastActive       = $"{urlKismet}/devices/last-time/{CONSTANT.ACTIVE_DEVICES_IN_LAST}/devices.json";
                string            jsonContentFields   = "json={\"fields\":" + jsonFields + "}";
                List <WiFiDevice> KismetActiveDevices = await GetDevices(urlLastActive, jsonContentFields);

                //removing all known devices from the last seen devices list
                //known devices are all locally registered devices in the list WiFiDevice.WifiDevices
                var tempDelList      = new List <WiFiDevice>();
                var AllActiveDevices = new List <WiFiDevice>(KismetActiveDevices);
                foreach (var kismet in KismetActiveDevices)
                {
                    foreach (var knownDevice in WiFiDevice.WellKnownDevices)
                    {
                        if (kismet.MacAddress == knownDevice.MacAddress || kismet.LastSignal < CONSTANT.SIGNAL_TRESHOLD || (kismet.CommonName == kismet.MacAddress && kismet.Manufacture == "Unknown"))
                        {
                            tempDelList.Add(kismet);
                            break;
                        }
                    }
                }
                KismetActiveDevices.RemoveAll(i => tempDelList.Contains(i));

                //adding new members to the close devices list
                if (KismetActiveDevices.Any())
                {
                    var  tempAddList = new List <WiFiDevice>();
                    bool isNewItem   = true;
                    foreach (var kismet in KismetActiveDevices)
                    {
                        foreach (var unknownDevice in UnknownDevices)
                        {
                            if (kismet.MacAddress == unknownDevice.MacAddress)
                            {
                                unknownDevice.Count++;
                                unknownDevice.LastUnixTime = kismet.LastUnixTime;
                                unknownDevice.WiFiName     = kismet.ProbedSSID;
                                if (kismet.SignalType.Contains("Wi-Fi"))
                                {
                                    //get device AccessPoint and WIFI network names from Kismet (if reported by device)
                                    List <WiFiDevice> KismetOneMac = new List <WiFiDevice>();
                                    string            urlOneMac    = $"{urlKismet}/devices/by-mac/{kismet.MacAddress}/devices.json";
                                    KismetOneMac = await GetDevices(urlOneMac, jsonContentFields);

                                    //have to check KismetOneMac list because sometimes it is empty
                                    if (KismetOneMac.Any())
                                    {
                                        unknownDevice.AccessPoint = AllActiveDevices.Where(x => x.MacAddress == KismetOneMac.First().LastBSSID).Select(x => x.BaseName).DefaultIfEmpty("No AP").First();
                                        if (string.IsNullOrEmpty(kismet.ProbedSSID) || unknownDevice.WiFiName == "0")
                                        {
                                            unknownDevice.WiFiName = AllActiveDevices.Where(x => x.MacAddress == KismetOneMac.First().LastBSSID).Select(x => x.SSID).DefaultIfEmpty("No AP").First();
                                        }
                                    }
                                }
                                isNewItem = false;
                                break;
                            }
                            else
                            {
                                isNewItem = true;
                            }
                        }
                        if (isNewItem)
                        {
                            tempAddList.Add(kismet);
                        }
                    }
                    UnknownDevices.AddRange(tempAddList.ToArray());

                    UnknownDevices.RemoveAll(x => (unixTimestamp - x.LastUnixTime) / 60 > 120); //remove all entries older that 2 hour

                    //local debugging: show the devices list in console only if some device has been added
                    if (tempAddList.Any() && UnknownDevices.Any())
                    {
                        var sortedList = UnknownDevices.OrderBy(x => x.SignalType).ThenByDescending(y => y.LastUnixTime).ToList();
                        Console.WriteLine();
                        Console.WriteLine($"All unknown devices at: {METHOD.DateTimeTZ().DateTime:G}");
                        Console.WriteLine();
                        Console.WriteLine($"dB  | First | Last  |    Mac Address    |Count |  SignalType   |         WiFi network      |         AccessPoint       |    Common Name     | Manufacturer ");
                        Console.WriteLine($" -  | ----  | ----  |    -----------    | ---  |  ----------   |          ---------        |          ---------        |    -----------     |  -----------  ");

                        foreach (var device in sortedList)
                        {
                            Console.WriteLine($"{device.LastSignal}{"".PadRight(device.LastSignal < 0 ? 1 : 3)}" +
                                              $"| {METHOD.UnixTimeStampToDateTime(device.FirstUnixTime).AddHours(timeOffset):t} " +
                                              $"| {METHOD.UnixTimeStampToDateTime(device.LastUnixTime).AddHours(timeOffset):t} " +
                                              $"| {device.MacAddress} " +
                                              $"| {device.Count}{"".PadRight(device.Count < 10 ? 3 : device.Count < 100 ? 2 : 1)} " +
                                              $"| {device.SignalType}{"".PadRight(14 - (!string.IsNullOrEmpty(device.SignalType) ? (device.SignalType.Length > 14 ? 14 : device.SignalType.Length) : 0))}" +
                                              $"| {device.WiFiName}{"".PadRight(26 - (!string.IsNullOrEmpty(device.WiFiName) ? (device.WiFiName.Length > 26 ? 26 : device.WiFiName.Length) : 0))}" +
                                              $"| {device.AccessPoint}{"".PadRight(26 - (!string.IsNullOrEmpty(device.AccessPoint) ? (device.AccessPoint.Length > 26 ? 26 : device.AccessPoint.Length) : 0))}" +
                                              $"| {device.CommonName}{"".PadRight(19 - (!string.IsNullOrEmpty(device.CommonName) ? (device.CommonName.Length > 19 ? 19 : device.CommonName.Length) : 0))}" +
                                              $"| {device.Manufacture}");
                        }
                        Console.WriteLine();
                    }
                }
                #endregion

                await Task.Delay(TimeSpan.FromSeconds(60)); //check statuses every 10 millisecond
            }
        }