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; } } }
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; } } }
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; } } }
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; } } }
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; } } }
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()); }