Пример #1
0
        public async Task <Expression <Func <DatabaseContext, Sensor> > > EditSensor(DatabaseContext databaseContext, EditSensorParameters model, LogEntryHandler logEntryHandler)
        {
            var sensor = await databaseContext.Sensors.GetRequiredByIdAsync(model.Id);

            await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Edit, sensor: sensor))
            {
                try
                {
                    var plant = model.PlantId.HasValue ? await databaseContext.Plants.GetRequiredByIdAsync(model.PlantId.Value) : null;

                    sensor.MACAddress = model.MACAddress;
                    sensor.Name       = model.Name;
                    sensor.Plant      = plant;
                    await databaseContext.SaveChangesAsync();

                    logEntry.Success();
                    return(ctx => ctx.Sensors.GetRequiredById(sensor.Id));
                }
                catch (Exception ex)
                {
                    logEntry.Failure(ex, "Failed to edit Sensor!");
                    throw;
                }
            }
        }
        public async Task <Expression <Func <DatabaseContext, Device> > > AddDevice(DatabaseContext databaseContext, AddDeviceParameters model, LogEntryHandler logEntryHandler)
        {
            await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Add))
            {
                try
                {
                    var device = new Device()
                    {
                        MACAddress = model.MACAddress,
                        IPAddress  = model.IPAddress,
                        Port       = model.Port,
                        Name       = model.Name
                    };
                    databaseContext.Devices.Add(device);
                    await databaseContext.SaveChangesAsync();

                    logEntry.Attach(device);
                    logEntry.Success();
                    return(ctx => ctx.Devices.GetRequiredById(device.Id));
                }
                catch (Exception ex)
                {
                    logEntry.Failure(ex, "Failed to add device!");
                    throw;
                }
            }
        }
Пример #3
0
        public async Task <Expression <Func <DatabaseContext, Plant> > > AddPlant(DatabaseContext databaseContext, AddPlantParameters model, LogEntryHandler logEntryHandler)
        {
            await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Add))
            {
                try
                {
                    var plant = new Plant()
                    {
                        LatinName = model.LatinName,
                        Alias     = model.Alias,
                        Display   = model.Display,
                        ImageUrl  = model.ImageUrl,
                        Basic     = new PlantBasic
                        {
                            Blooming       = model.Blooming,
                            Category       = model.Category,
                            Color          = model.Color,
                            FloralLanguage = model.FloralLanguage,
                            Origin         = model.Origin,
                            Production     = model.Production
                        },
                        Maintenance = new PlantMaintenance
                        {
                            Fertilization = model.Fertilization,
                            Pruning       = model.Pruning,
                            Size          = model.Size,
                            Soil          = model.Soil,
                            Sunlight      = model.Sunlight,
                            Watering      = model.Watering
                        },
                        Parameters = new PlantParameters
                        {
                            EnvironmentHumidity = new Database.Range(model.MinEnvironmentHumidity, model.MaxEnvironmentHumidity),
                            LightLux            = new Database.Range(model.MinLightLux, model.MaxLightLux),
                            LightMmol           = new Database.Range(model.MinLightMmol, model.MaxLightMmol),
                            SoilFertility       = new Database.Range(model.MinSoilFertility, model.MaxSoilFertility),
                            SoilHumidity        = new Database.Range(model.MinSoilHumidity, model.MaxSoilHumidity),
                            Temperature         = new Database.Range(model.MinTemperature, model.MaxTemperature)
                        }
                    };
                    databaseContext.Plants.Add(plant);
                    await databaseContext.SaveChangesAsync();

                    logEntry.Attach(plant);
                    logEntry.Success();
                    return(ctx => ctx.Plants.GetRequiredById(plant.Id));
                }
                catch (Exception ex)
                {
                    logEntry.Failure(ex, "Failed to add plant!");
                    throw;
                }
            }
        }
Пример #4
0
        public async Task <Expression <Func <DatabaseContext, Plant> > > EditPlant(DatabaseContext databaseContext, EditPlantParameters model, LogEntryHandler logEntryHandler)
        {
            var plant = await databaseContext.Plants.GetRequiredByIdAsync(model.Id);

            await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Edit, plant: plant))
            {
                try
                {
                    plant.LatinName = model.LatinName;
                    plant.Alias     = model.Alias;
                    plant.Display   = model.Display;
                    plant.ImageUrl  = model.ImageUrl;

                    plant.Basic.Blooming       = model.Blooming;
                    plant.Basic.Category       = model.Category;
                    plant.Basic.Color          = model.Color;
                    plant.Basic.FloralLanguage = model.FloralLanguage;
                    plant.Basic.Origin         = model.Origin;
                    plant.Basic.Production     = model.Production;

                    plant.Maintenance.Fertilization = model.Fertilization;
                    plant.Maintenance.Pruning       = model.Pruning;
                    plant.Maintenance.Size          = model.Size;
                    plant.Maintenance.Soil          = model.Soil;
                    plant.Maintenance.Sunlight      = model.Sunlight;
                    plant.Maintenance.Watering      = model.Watering;

                    plant.Parameters.EnvironmentHumidity = new Database.Range(model.MinEnvironmentHumidity, model.MaxEnvironmentHumidity);
                    plant.Parameters.LightLux            = new Database.Range(model.MinLightLux, model.MaxLightLux);
                    plant.Parameters.LightMmol           = new Database.Range(model.MinLightMmol, model.MaxLightMmol);
                    plant.Parameters.SoilFertility       = new Database.Range(model.MinSoilFertility, model.MaxSoilFertility);
                    plant.Parameters.SoilHumidity        = new Database.Range(model.MinSoilHumidity, model.MaxSoilHumidity);
                    plant.Parameters.Temperature         = new Database.Range(model.MinTemperature, model.MaxTemperature);

                    await databaseContext.SaveChangesAsync();

                    logEntry.Success();
                    return(ctx => ctx.Plants.GetRequiredById(plant.Id));
                }
                catch (Exception ex)
                {
                    logEntry.Failure(ex, "Failed to edit plant!");
                    throw;
                }
            }
        }
Пример #5
0
        public async Task <Plant> DeletePlant(DatabaseContext databaseContext, DeletePlantParameters model, LogEntryHandler logEntryHandler)
        {
            var plant = await databaseContext.Plants.GetRequiredByIdAsync(model.Id);

            await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Delete, plant: plant))
            {
                try
                {
                    databaseContext.Plants.Remove(plant);
                    await databaseContext.SaveChangesAsync();

                    logEntry.Success();
                    return(plant);
                }
                catch (Exception ex)
                {
                    logEntry.Failure(ex, "Failed to delete plant!");
                    throw;
                }
            }
        }
        public async Task <Device> DeleteDevice(DatabaseContext databaseContext, DeleteDeviceParameters model, LogEntryHandler logEntryHandler)
        {
            var device = await databaseContext.Devices.GetRequiredByIdAsync(model.Id);

            await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Delete, device: device))
            {
                try
                {
                    databaseContext.Devices.Remove(device);
                    await databaseContext.SaveChangesAsync();

                    logEntry.Success();
                    return(device);
                }
                catch (Exception ex)
                {
                    logEntry.Failure(ex, "Failed to delete device!");
                    throw;
                }
            }
        }
Пример #7
0
        public async Task <Sensor> DeleteSensor(DatabaseContext databaseContext, DeleteSensorParameters model, LogEntryHandler logEntryHandler)
        {
            //get current user, try to convert this into a async method so we can get the user!
            var sensor = await databaseContext.Sensors.GetRequiredByIdAsync(model.Id);

            await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Delete, sensor: sensor))
            {
                try
                {
                    databaseContext.Sensors.Remove(sensor);
                    await databaseContext.SaveChangesAsync();

                    logEntry.Success();
                    return(sensor);
                }
                catch (Exception ex)
                {
                    logEntry.Failure(ex, "Failed to delete Sensor!");
                    throw;
                }
            }
        }
        public async Task <Expression <Func <DatabaseContext, Device> > > EditDevice(DatabaseContext databaseContext, EditDeviceParameters model, LogEntryHandler logEntryHandler)
        {
            var device = await databaseContext.Devices.GetRequiredByIdAsync(model.Id);

            await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Edit, device: device))
            {
                try
                {
                    device.MACAddress = model.MACAddress;
                    device.IPAddress  = model.IPAddress;
                    device.Port       = model.Port;
                    device.Name       = model.Name;
                    await databaseContext.SaveChangesAsync();

                    logEntry.Success();
                    return(ctx => ctx.Devices.Single(x => x.Id == device.Id));
                }
                catch (Exception ex)
                {
                    logEntry.Failure(ex, "Failed to edit device!");
                    throw;
                }
            }
        }
Пример #9
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());
            }
        }
        public async Task <int[]> ScanAsync()
        {
            logger.LogTrace("ScanAsync");
            var       token      = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, new CancellationTokenSource(3000).Token).Token;
            var       devices    = new List <Device>();
            const int serverPort = 16555;
            const int clientPort = 16556;

            logger.LogDebug("Starting UDPClient");
            using (var client = new UdpClient())
                await using (var logEntry = logEntryHandler.AddLogEntry(LogEntryEvent.Scan))
                    using (token.Register(() =>
                    {
                        logger.LogWarning("Timeout occurred closing udpClient");
                        client.Close();
                    }))
                    {
                        try
                        {
                            client.ExclusiveAddressUse = false;
                            client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                            client.Client.Bind(new IPEndPoint(IPAddress.Any, serverPort));
                            logger.LogDebug("UDPClient started");
                            var listeningTask = client.ReceiveAsync();
                            var sendTask      = SendScanAsync(client, clientPort, token);
                            var tasks         = new List <Task> {
                                listeningTask, sendTask
                            };
                            while (!token.IsCancellationRequested)
                            {
                                var completedTask = await Task.WhenAny(tasks);

                                tasks.Remove(completedTask);
                                logger.LogDebug("Task completed");
                                if (completedTask == listeningTask)
                                {
                                    if (completedTask.Exception != null)
                                    {
                                        logger.LogCritical(completedTask.Exception, "Listening task crashed!");
                                        throw new Exception("Listen task caused a exception", completedTask.Exception);
                                    }
                                    logger.LogInformation($"Received response from {listeningTask.Result.RemoteEndPoint}");
                                    tasks.Add(HandleClientAsync(listeningTask.Result.RemoteEndPoint, listeningTask.Result.Buffer, token));
                                    listeningTask = client.ReceiveAsync();
                                    tasks.Add(listeningTask);
                                }
                                else if (completedTask == sendTask)
                                {
                                    if (completedTask.Exception != null)
                                    {
                                        logger.LogCritical(completedTask.Exception, "Send task crashed!");
                                        throw new Exception("Send task caused a exception", completedTask.Exception);
                                    }
                                    logger.LogInformation("Send task finished!");
                                }
                                else
                                {
                                    if (completedTask.Exception != null)
                                    {
                                        logger.LogCritical(completedTask.Exception, "Handle client task crashed!");
                                        throw new Exception("Handle client task caused a exception", completedTask.Exception);
                                    }
                                    logger.LogInformation("Handle client task finished!");
                                    var device = ((Task <Device?>)completedTask).Result;
                                    if (device != null)
                                    {
                                        devices.Add(device);
                                    }
                                }
                            }
                            logEntry.Success("Scan successfully completed");
                        }
                        catch (Exception ex)
                        {
                            logger.LogError(ex, "Failed to scan for new devices");
                            logEntry.Failure(ex.ToString());
                        }
                    }
            logger.LogInformation("Saving changes");
            await databaseContext.SaveChangesAsync(cancellationToken);

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