Compare commits

...

11 Commits

12 changed files with 368 additions and 63 deletions

View File

@@ -1,13 +1,15 @@
package ru.spbstu.telematics.java;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
import java.util.Locale;
public class App {
public static void main(String[] args) {
Locale.setDefault(Locale.ENGLISH);
Room room = new Room();
Settings settings = new Settings(28, 0.4);
Controller controller = new Controller(room, settings);
Thread controllerThread = new Thread(controller);
controllerThread.start();
}
}

View File

@@ -10,11 +10,93 @@ public class Controller implements Runnable {
private Room room;
private Settings settings;
private Sensor sensor;
private Thread sensorThread;
private Heater heater;
private Thread heaterThread;
private Fan fan;
private Thread fanThread;
public Controller(Room room, Settings settings) {
this.room = room;
this.settings = settings;
sensor = new Sensor(room);
sensorThread = new Thread(sensor);
heater = new Heater(room);
heaterThread = new Thread(heater);
fan = new Fan(room);
fanThread = new Thread(fan);
}
private long updateIntervalMs = 500;
private double tolerance = 0.01;
private void log(String string) {
System.out.printf("[Controller in room %s] %s\n", room.name, string);
}
@Override
public void run() {
sensorThread.start();
heaterThread.start();
fanThread.start();
log("Started sensor, heater and fan threads");
while (!Thread.interrupted()) {
double realTemperature = room.getTemperature();
double sensorTemperature = sensor.getTemperature();
double desiredTemperature = settings.getTemperature();
if (sensorTemperature < desiredTemperature * (1 - tolerance)) {
if (!heater.isOn()) {
log(String.format(
"Turning heater ON (real - %.2fC°, sensor - %.2fC°, desired %.2fC°)",
realTemperature, sensorTemperature, desiredTemperature));
heater.turnOn();
}
} else {
if (heater.isOn()) {
log(String.format(
"Turning heater OFF (real - %.2fC°, sensor - %.2fC°, desired %.2fC°)",
realTemperature, sensorTemperature, desiredTemperature));
heater.turnOff();
}
}
double realHumidity = room.getHumidity();
double sensorHumidity = sensor.getHumidity();
double desiredHumidity = settings.getHumidity();
if (sensorHumidity > desiredHumidity * (1 + tolerance)) {
if (!fan.isOn()) {
log(String.format(
"Turning fan ON (real - %.2f%%, sensor - %.2f%%, desired %.2f%%)",
realHumidity * 100, sensorHumidity * 100, desiredHumidity * 100));
fan.turnOn();
}
} else {
if (fan.isOn()) {
log(String.format(
"Turning fan OFF (real - %.2f%%, sensor - %.2f%%, desired %.2f%%)",
realHumidity * 100, sensorHumidity * 100, desiredHumidity * 100));
fan.turnOff();
}
}
Utils.sleep(updateIntervalMs);
}
sensorThread.interrupt();
heaterThread.interrupt();
fanThread.interrupt();
try {
sensorThread.join();
heaterThread.join();
fanThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@@ -1,15 +1,43 @@
package ru.spbstu.telematics.java;
import java.util.Random;
/*
* Симулирует вентилятор, установленный в комнате. Может изменять поля комнаты,
* а именно - уменьшать влажность в ней.
*/
public class Fan implements Runnable {
Room room;
private boolean isOn;
private Room room;
public Fan(Room room) {
this.room = room;
}
private volatile boolean isOn;
public boolean isOn() {
return isOn;
}
public void turnOn() {
this.isOn = true;
}
public void turnOff() {
this.isOn = false;
}
private Random random = new Random();
private double humidityMaxStep = 0.03;
private long maxStepTimeMs = 3000;
@Override
public void run() {
while (!Thread.interrupted()) {
if (isOn)
room.adjustHumidity(-random.nextDouble() * humidityMaxStep);
Utils.sleepRandomTime((long) (maxStepTimeMs * 0.5), maxStepTimeMs);
}
}
}

View File

@@ -1,15 +1,43 @@
package ru.spbstu.telematics.java;
import java.util.Random;
/*
* Симулирует нагреватель, установленный в комнате. Может изменять поля комнаты,
* а именно - увеличивать температуру в ней.
*/
public class Heater implements Runnable {
Room room;
private boolean isOn;
private Room room;
public Heater(Room room) {
this.room = room;
}
private volatile boolean isOn;
public boolean isOn() {
return isOn;
}
public void turnOn() {
this.isOn = true;
}
public void turnOff() {
this.isOn = false;
}
private Random random = new Random();
private double temperatureMaxStep = 1;
private long maxStepTimeMs = 3000;
@Override
public void run() {
while (!Thread.interrupted()) {
if (isOn)
room.adjustTemperature(random.nextDouble() * temperatureMaxStep);
Utils.sleepRandomTime((long) (maxStepTimeMs * 0.5), maxStepTimeMs);
}
}
}

View File

@@ -6,6 +6,15 @@ import java.util.Random;
* Симулирует физические процессы, протекающие в команте.
*/
public class Room implements Runnable {
static private int roomCounter;
public final String name;
public Room() {
roomCounter++;
this.name = "#" + roomCounter;
}
// Температура измеряется в градусах цельсия
private volatile double temperature = 24.0;
@@ -13,6 +22,10 @@ public class Room implements Runnable {
return temperature;
}
public synchronized void adjustTemperature(double delta) {
this.temperature += delta;
}
// Относительная влажность в процентах
private volatile double humidity = 0.5;
@@ -20,6 +33,10 @@ public class Room implements Runnable {
return humidity;
}
public synchronized void adjustHumidity(double delta) {
this.humidity += delta;
}
// Параметры произвольного изменения температуры и влажности в комнате
private Random random = new Random();
private double temperatureMaxStep = 1;
@@ -33,16 +50,7 @@ public class Room implements Runnable {
temperature += (random.nextDouble() - 0.5) * 2 * temperatureMaxStep;
humidity += (random.nextDouble() - 0.5) * 2 * humidityMaxStep;
try {
Thread.sleep(getStepTime());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Utils.sleepRandomTime((long) (maxStepTimeMs * 0.5), maxStepTimeMs);
}
}
}
private long getStepTime() {
// Спим от 0.5 * maxStepTimeMs до maxSteTimeMs миллисекунд
return (long) (random.nextDouble() * 0.5 + 0.5) * maxStepTimeMs;
}
}

View File

@@ -40,11 +40,7 @@ public class Sensor implements Runnable {
temperature = room.getTemperature() + (random.nextDouble() - 0.5) * 2 * maxTemperatureError;
humidity = room.getHumidity() + (random.nextDouble() - 0.5) * 2 * maxHumidityError;
try {
Thread.sleep(updateIntervalMs);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Utils.sleep(updateIntervalMs);
}
}
}

View File

@@ -1,14 +1,41 @@
package ru.spbstu.telematics.java;
import java.util.Random;
/*
* Симулирует переодическое изменение настроек пользователем.
*/
public class Settings implements Runnable {
private double temperature;
public double getTemperature() {
return temperature;
}
private double humidity;
public double getHumidity() {
return humidity;
}
public Settings(double temperature, double humidity) {
this.temperature = temperature;
this.humidity = humidity;
}
// Параметры произвольного изменения настроек температуры и влажности в комнате
private Random random = new Random();
private double temperatureMaxStep = 10;
private double humidityMaxStep = 0.15;
private long maxStepTimeMs = 20000;
@Override
public void run() {
while (!Thread.interrupted()) {
temperature += (random.nextDouble() - 0.5) * 2 * temperatureMaxStep;
humidity += (random.nextDouble() - 0.5) * 2 * humidityMaxStep;
Utils.sleepRandomTime((long) (maxStepTimeMs * 0.5), maxStepTimeMs);
}
}
}

View File

@@ -0,0 +1,21 @@
package ru.spbstu.telematics.java;
import java.util.concurrent.ThreadLocalRandom;
public class Utils {
static public void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
static public void sleepRandomTime(long from, long to) {
try {
Thread.sleep(ThreadLocalRandom.current().nextLong(from, to));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}

View File

@@ -0,0 +1,57 @@
package ru.spbstu.telematics.java;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.*;
public class FanTests {
Room room;
double initialTemperature;
double initialHumidity;
Fan fan;
Thread fanThread;
@BeforeEach
public void setUp() {
room = new Room();
initialTemperature = room.getTemperature();
initialHumidity = room.getHumidity();
fan = new Fan(room);
fanThread = new Thread(fan);
}
/*
* Проверяет, что включенный вентилятор уменьшает влажность в комнате
* и при этом не изменяет температуру.
*/
@Test
public void testFanOn() throws InterruptedException {
fan.turnOn();
fanThread.start();
Thread.sleep(5000);
assertEquals(initialTemperature, room.getTemperature());
assertTrue(initialHumidity > room.getHumidity());
fanThread.interrupt();
fanThread.join();
}
/*
* Проверяет, что выключенный вентилятор не изменяет температуру и влажность
* в комнате.
*/
@Test
public void testFanOff() throws InterruptedException {
fanThread.start();
Thread.sleep(5000);
assertEquals(initialHumidity, room.getHumidity());
assertEquals(initialTemperature, room.getTemperature());
fanThread.interrupt();
fanThread.join();
}
}

View File

@@ -0,0 +1,57 @@
package ru.spbstu.telematics.java;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.*;
public class HeaterTests {
Room room;
double initialTemperature;
double initialHumidity;
Heater heater;
Thread heaterThread;
@BeforeEach
public void setUp() {
room = new Room();
initialTemperature = room.getTemperature();
initialHumidity = room.getHumidity();
heater = new Heater(room);
heaterThread = new Thread(heater);
}
/*
* Проверяет, что включенный нагреватель увеличивает температуру в комнате
* и при этом не изменяет влажность.
*/
@Test
public void testHeaterOn() throws InterruptedException {
heater.turnOn();
heaterThread.start();
Thread.sleep(5000);
assertEquals(initialHumidity, room.getHumidity());
assertTrue(initialTemperature < room.getTemperature());
heaterThread.interrupt();
heaterThread.join();
}
/*
* Проверяет, что выключенный нагреватель не изменяет температуру и влажность
* в комнате.
*/
@Test
public void testHeaterOff() throws InterruptedException {
heaterThread.start();
Thread.sleep(5000);
assertEquals(initialHumidity, room.getHumidity());
assertEquals(initialTemperature, room.getTemperature());
heaterThread.interrupt();
heaterThread.join();
}
}

View File

@@ -3,7 +3,6 @@ package ru.spbstu.telematics.java;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class RoomTests {
/*
* Проверяет, что температура и влажность изменяются со временем.

View File

@@ -3,7 +3,6 @@ package ru.spbstu.telematics.java;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class SensorTests {
/*
* Моковый класс комнаты для упрощения тестирования сенсоров.
@@ -29,7 +28,8 @@ public class SensorTests {
}
/*
* Проверяет, что сенсоры выдают реальную температуру и влажность комнаты в пределах
* Проверяет, что сенсоры выдают реальную температуру и влажность комнаты в
* пределах
* некоторой погрешности.
*/
@Test