private async Task <Device?> HandleClientAsync(IPEndPoint endPoint, byte[] buffer, CancellationToken cancellationToken)
        {
            logger.LogTrace("HandleClientAsync");
            try
            {
                logger.LogInformation("Deserializing response");
                var response     = JsonSerializer.Deserialize <DeviceDiscoveryResponse>(buffer, this.jsonSerializerOptions);
                var restEndpoint = new IPEndPoint(endPoint.Address, response.Port);
                logger.LogInformation($"Adding device {endPoint}");
                using (await deviceLockManager.LockAsync(cancellationToken))
                {
                    var result = await deviceService.GetDeviceInfoAsync(restEndpoint, cancellationToken);

                    var macAddress = result.MACAddress.ToFormattedString();
                    var device     = await databaseContext.Devices.SingleOrDefaultAsync(x => x.MACAddress == macAddress);

                    if (databaseContext.ChangeTracker.Entries <Device>().Any(device => device.Entity.MACAddress == macAddress))
                    {
                        logger.LogInformation($"Device has already been queued!");
                        return(null);
                    }
                    if (device == null)
                    {
                        device = new Device()
                        {
                            IPAddress  = endPoint.Address.ToString(),
                            Port       = response.Port,
                            MACAddress = macAddress,
                            Name       = result.Name + " - " + macAddress,
                            Tags       = new[] {
                                new DeviceTag {
                                    Tag = PredefinedTags.Added, Value = DateTime.Now.ToString("g")
                                },
                                new DeviceTag {
                                    Tag = PredefinedTags.Source, Value = "ScanOrAutoConnect"
                                }
                            }
                        };
                        databaseContext.Add(device);
                        logger.LogInformation("Added new device with {MACAddress}", result.MACAddress);
                    }
                    else if (device.IPAddress != endPoint.Address.ToString())
                    {
                        device.IPAddress = endPoint.Address.ToString();
                        device.Port      = endPoint.Port;
                        databaseContext.DevicesTags.Add(new DeviceTag {
                            Device = device, Tag = PredefinedTags.IPAddressUpdated, Value = DateTime.Now.ToString("g")
                        });

                        logger.LogInformation("Updated device with {MACAddress}", result.MACAddress);
                    }
                    return(device);
                }
            }
            catch (HttpRequestException ex)
            {
                logger.LogCritical(ex, "Failed to communicate with MiFlora device!");
                throw;
            }
        }
        public async Task CommandAsync()
        {
            logger.LogTrace("CommandAsync");
            using (await deviceLockManager.LockAsync(cancellationToken))
            {
                foreach (var sensor in await databaseContext.Sensors.ToListAsync())
                {
                    logger.LogInformation("Getting device priority for {sensor}", sensor);
                    var devices = await databaseContext.GetDeviceUsagePriority(sensor)
                                  .ToListAsync(cancellationToken);

                    foreach (var device in devices)
                    {
                        try
                        {
                            logger.LogInformation("Trying to get values for {sensor} using {device}", sensor, device);
                            var result = await deviceService.GetValuesAsync(device, sensor.MACAddress, cancellationToken);

                            databaseContext.DeviceSensorDistances.Add(new DeviceSensorDistance {
                                Device = device, Sensor = sensor, When = DateTime.Now, Rssi = result.Rssi
                            });
                            databaseContext.SensorDataReadings.Add(new SensorDataReading {
                                Sensor = sensor, When = DateTime.Now, Brightness = result.Brightness, Conductivity = result.Conductivity, Moisture = result.Moisture, Temperature = result.Temperature
                            });
                            logger.LogTrace("Saving changes");
                            await databaseContext.SaveChangesAsync(cancellationToken);

                            logger.LogInformation("Saved new sensor values");

                            logger.LogInformation("Triggering a send of the new values!");
                            jobManager.Start <ISendValuesCommand>(command => command.CommandAsync(sensor.Id));
                            break; //We managed to scan the sensor successfully no need to try any other devices!
                        }
                        catch (Exception ex)
                        {
                            logger.LogError(ex, "Failed to read the sensor values from {sensor} using {device}", sensor, device);
                            //todo: if we failed x amount of times we should add a huge rssi so that we get lower priority!
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
        public async Task CommandAsync()
        {
            logger.LogTrace("CommandAsync");
            using (await deviceLockManager.LockAsync(cancellationToken))
            {
                foreach (var sensor in await databaseContext.Sensors.ToListAsync())
                {
                    logger.LogInformation("Getting device priority for {sensor}", sensor);
                    var devices = await databaseContext.GetDeviceUsagePriority(sensor)
                                  .ToListAsync(cancellationToken);

                    foreach (var device in devices)
                    {
                        try
                        {
                            logger.LogInformation("Trying to get battery and version for {sensor} using {device}", sensor, device);
                            var result = await deviceService.GetBatteryAndVersionAsync(device, sensor.MACAddress, cancellationToken);

                            databaseContext.DeviceSensorDistances.Add(new DeviceSensorDistance {
                                Device = device, Sensor = sensor, When = DateTime.Now, Rssi = result.Rssi
                            });
                            databaseContext.SensorBatteryReadings.Add(new SensorBatteryAndVersionReading {
                                Sensor = sensor, When = DateTime.Now, Battery = result.Battery, Version = result.Version
                            });
                            await databaseContext.SaveChangesAsync(cancellationToken);

                            logger.LogInformation("Saved new battery and version values");

                            logger.LogInformation("Triggering a send of the new values!");
                            jobManager.Start <ISendValuesCommand>(command => command.CommandAsync(sensor.Id));

                            break; //We managed to scan the sensor successfully no need to try any other devices!
                        }
                        catch (Exception ex)
                        {
                            logger.LogError(ex, "Failed to read the sensor values from {sensor} using {device}", sensor, device);
                        }
                    }
                }
            }
        }
Exemplo n.º 4
0
        public async Task <int[]> ScanAsync()
        {
            int retryCount        = 3;
            int delayAfterFailure = 5;

            logger.LogTrace("CommandAsync({retryCount}, {delayAfterFailure})", retryCount, delayAfterFailure);
            var token = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, new CancellationTokenSource(1000 * 30).Token).Token;

            var devices = await databaseContext.Devices.ToArrayAsync();

            var policy = Policy.Handle <HttpRequestException>().Or <OperationCanceledException>().WaitAndRetryAsync(retryCount, i => TimeSpan.FromSeconds(delayAfterFailure));

            using (await deviceLockManager.LockAsync(token))
            {
                var scanTasks = devices.Select(async device =>
                {
                    await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Scan, device: device))
                    {
                        var result = await policy.ExecuteAndCaptureAsync(() => deviceService.ScanAsync(device, token));
                        if (result.Outcome == OutcomeType.Successful)
                        {
                            var sensorInfos = result.Result;
                            logger.LogInformation("Scan using {device} was successful, found {number} sensors", device, sensorInfos.Count());
                            foreach (var sensorInfo in sensorInfos)
                            {
                                var sensor = databaseContext.ChangeTracker.Entries <Sensor>().SingleOrDefault(x => x.Entity.MACAddress == sensorInfo.MACAddress)?.Entity;
                                if (sensor == null)
                                {
                                    sensor = await databaseContext.Sensors.SingleOrDefaultAsync(x => x.MACAddress == sensorInfo.MACAddress);
                                }

                                //If the device does not exist
                                if (sensor == null)
                                {
                                    sensor = new Sensor
                                    {
                                        MACAddress = sensorInfo.MACAddress,
                                        Name       = sensorInfo.Name,
                                        Tags       = new Collection <SensorTag> {
                                            new SensorTag {
                                                Tag = PredefinedTags.Added, Value = DateTime.Now.ToString("g")
                                            },
                                            new SensorTag {
                                                Tag = PredefinedTags.Source, Value = "Scan"
                                            }
                                        }
                                    };
                                    logger.LogInformation("Added sensor with {MACAddress}", sensorInfo.MACAddress);
                                    databaseContext.Sensors.Add(sensor);
                                }
                                databaseContext.DeviceSensorDistances.Add(new DeviceSensorDistance
                                {
                                    Device = device,
                                    Sensor = sensor,
                                    When   = DateTime.Now,
                                    Rssi   = sensorInfo.Rssi
                                });
                            }

                            var foundSensorIds = sensorInfos.Select(x => x.MACAddress);
                            var missedSensors  = databaseContext.GetLatestSensorsForDevice(device).Where(sensor => !foundSensorIds.Contains(sensor.MACAddress));
                            foreach (var missedSensor in missedSensors)
                            {
                                //We found a sensor using this device before but not this time, so we should not use this device to scan for it again!
                                databaseContext.DeviceSensorDistances.Add(new DeviceSensorDistance
                                {
                                    Device = device,
                                    Sensor = missedSensor,
                                    When   = DateTime.Now,
                                    Rssi   = null
                                });

                                logger.LogInformation("Added missed sensor with {MACAddress}", missedSensor.MACAddress);
                            }
                            logEntry.Success();
                        }
                        else
                        {
                            logger.LogError(result.FinalException, "Failed to scan for sensors using {device}", device);
                            logEntry.Failure(result.FinalException.ToString());
                        }
                    }
                });
                await Task.WhenAll(scanTasks);

                var addedSensors = databaseContext.ChangeTracker.Entries <Sensor>().Where(x => x.State == EntityState.Added).Select(x => x.Entity).ToArray();
                logger.LogInformation("Saving changes");
                await databaseContext.SaveChangesAsync();

                return(addedSensors.Select(x => x.Id).ToArray());
            }
        }