1
0

added some improved classes from my custom backend and introduced DAOs

This commit is contained in:
Jose
2025-05-09 20:48:45 +02:00
parent b6f13cfff8
commit 02a2a2ce07
53 changed files with 4462 additions and 3239 deletions

View File

@@ -1,98 +1,104 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>net.miarma</groupId> <groupId>net.miarma</groupId>
<artifactId>contaminus</artifactId> <artifactId>contaminus</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
<name>ContaminUS</name> <name>ContaminUS</name>
<properties> <properties>
<maven.compiler.source>23</maven.compiler.source> <maven.compiler.source>23</maven.compiler.source>
<maven.compiler.target>23</maven.compiler.target> <maven.compiler.target>23</maven.compiler.target>
</properties> </properties>
<dependencies> <dependencies>
<!-- Vert.X Core --> <!-- Vert.X Core -->
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId> <artifactId>vertx-core</artifactId>
<version>4.5.13</version> <version>4.5.13</version>
</dependency> </dependency>
<!-- Vert.X Web --> <!-- Vert.X MariaDB/MySQL Client -->
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId> <artifactId>vertx-mysql-client</artifactId>
<version>4.5.13</version> <version>4.5.13</version>
</dependency> </dependency>
<!-- Vert.X Web Client --> <!-- Vert.X Web -->
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId> <artifactId>vertx-web</artifactId>
<version>4.5.13</version> <version>4.5.13</version>
</dependency> </dependency>
<!-- Vert.X MQTT --> <!-- Vert.X Web Client -->
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-mqtt</artifactId> <artifactId>vertx-web-client</artifactId>
<version>4.4.2</version> <version>4.5.13</version>
</dependency> </dependency>
<!-- Vert.X MariaDB/MySQL Client --> <!-- Vert.X MQTT -->
<dependency> <dependency>
<groupId>io.vertx</groupId> <groupId>io.vertx</groupId>
<artifactId>vertx-jdbc-client</artifactId> <artifactId>vertx-mqtt</artifactId>
<version>4.5.13</version> <version>4.4.2</version>
</dependency> </dependency>
<!-- JDBC Driver --> <!-- Vert.X MariaDB/MySQL Client -->
<dependency> <dependency>
<groupId>org.mariadb.jdbc</groupId> <groupId>io.vertx</groupId>
<artifactId>mariadb-java-client</artifactId> <artifactId>vertx-jdbc-client</artifactId>
<version>3.5.2</version> <version>4.5.13</version>
</dependency> </dependency>
<!-- Gson --> <!-- Gson -->
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>2.12.1</version> <version>2.12.1</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/io.quarkus/quarkus-agroal --> <!-- SLF4J + Logback -->
<dependency> <dependency>
<groupId>org.jboss.logmanager</groupId> <groupId>org.slf4j</groupId>
<artifactId>jboss-logmanager</artifactId> <artifactId>slf4j-api</artifactId>
<version>3.1.1.Final</version> <!-- O la versión más reciente --> <version>2.0.12</version>
</dependency> </dependency>
</dependencies> <dependency>
<groupId>ch.qos.logback</groupId>
<build> <artifactId>logback-classic</artifactId>
<plugins> <version>1.5.13</version>
<!-- Maven Shade Plugin --> </dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId> </dependencies>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version> <build>
<executions> <plugins>
<execution> <!-- Maven Shade Plugin -->
<phase>package</phase> <plugin>
<goals> <groupId>org.apache.maven.plugins</groupId>
<goal>shade</goal> <artifactId>maven-shade-plugin</artifactId>
</goals> <version>3.5.3</version>
<configuration> <executions>
<createDependencyReducedPom>false</createDependencyReducedPom> <execution>
<transformers> <phase>package</phase>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <goals>
<mainClass>net.miarma.contaminus.server.MainVerticle</mainClass> <goal>shade</goal>
</transformer> </goals>
</transformers> <configuration>
</configuration> <createDependencyReducedPom>false</createDependencyReducedPom>
</execution> <transformers>
</executions> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
</plugin> <mainClass>net.miarma.contaminus.server.MainVerticle</mainClass>
</plugins> </transformer>
</build> </transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project> </project>

View File

@@ -0,0 +1,113 @@
package net.miarma.contaminus.common;
import java.lang.reflect.Field;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Row;
public abstract class AbstractEntity {
public AbstractEntity() {}
public AbstractEntity(Row row) {
populateFromRow(row);
}
private void populateFromRow(Row row) {
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
Class<?> type = field.getType();
String name = field.getName();
Object value;
if (type.isEnum()) {
Integer intValue = row.getInteger(name);
if (intValue != null) {
try {
var method = type.getMethod("fromInt", int.class);
value = method.invoke(null, intValue);
} catch (Exception e) {
value = null;
}
} else {
value = null;
}
} else {
value = switch (type.getSimpleName()) {
case "Integer" -> row.getInteger(name);
case "String" -> row.getString(name);
case "Double" -> row.getDouble(name);
case "Long" -> row.getLong(name);
case "Boolean" -> row.getBoolean(name);
case "int" -> row.getInteger(name);
case "double" -> row.getDouble(name);
case "long" -> row.getLong(name);
case "boolean" -> row.getBoolean(name);
case "LocalDateTime" -> row.getLocalDateTime(name);
case "BigDecimal" -> {
try {
var numeric = row.get(io.vertx.sqlclient.data.Numeric.class, row.getColumnIndex(name));
yield numeric != null ? numeric.bigDecimalValue() : null;
} catch (Exception e) {
yield null;
}
}
default -> {
System.err.println("Type not supported yet: " + type.getName() + " for field " + name);
yield null;
}
};
}
field.set(this, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public String encode() {
JsonObject json = new JsonObject();
Class<?> clazz = this.getClass();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
try {
Object value = field.get(this);
if (value instanceof ValuableEnum ve) {
json.put(field.getName(), ve.getValue());
} else {
json.put(field.getName(), value);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
clazz = clazz.getSuperclass();
}
return json.encode();
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName()).append(" [ ");
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
sb.append(field.getName()).append("= ").append(field.get(this)).append(", ");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
sb.append("]");
return sb.toString();
}
}

View File

@@ -1,57 +1,42 @@
package net.miarma.contaminus.common; package net.miarma.contaminus.common;
import io.vertx.core.impl.logging.Logger; import org.slf4j.Logger;
import io.vertx.core.impl.logging.LoggerFactory; import org.slf4j.LoggerFactory;
public class Constants { public class Constants {
public static final String APP_NAME = "ContaminUS"; public static final String APP_NAME = "ContaminUS";
public static final String API_PREFIX = "/api/v1"; public static final String API_PREFIX = "/api/v1";
public static final String RAW_API_PREFIX = "/api/raw/v1"; public static final String RAW_API_PREFIX = "/api/raw/v1";
public static Logger LOGGER = LoggerFactory.getLogger(Constants.APP_NAME); public static final String CONTAMINUS_EB = "contaminus.eventbus";
public static Logger LOGGER = LoggerFactory.getLogger(Constants.APP_NAME);
/* API Endpoints */ /* API Endpoints */
public static final String POST_PAYLOAD = RAW_API_PREFIX + "/device-payload"; public static final String GROUPS = RAW_API_PREFIX + "/groups";
public static final String GROUP = RAW_API_PREFIX + "/groups/:groupId";
public static final String GET_GROUPS = RAW_API_PREFIX + "/groups";
public static final String POST_GROUPS = RAW_API_PREFIX + "/groups"; public static final String DEVICES = RAW_API_PREFIX + "/groups/:groupId/devices";
public static final String PUT_GROUP_BY_ID = RAW_API_PREFIX + "/groups/:groupId"; public static final String DEVICE = RAW_API_PREFIX + "/groups/:groupId/devices/:deviceId";
public static final String LATEST_VALUES = API_PREFIX + "/groups/:groupId/devices/:deviceId/latest-values";
public static final String GET_DEVICES = RAW_API_PREFIX + "/devices"; public static final String POLLUTION_MAP = API_PREFIX + "/groups/:groupId/devices/:deviceId/pollution-map";
public static final String POST_DEVICES = RAW_API_PREFIX + "/devices"; public static final String HISTORY = API_PREFIX + "/groups/:groupId/devices/:deviceId/history";
public static final String PUT_DEVICE_BY_ID = RAW_API_PREFIX + "/devices/:deviceId";
public static final String SENSORS = RAW_API_PREFIX + "/groups/:groupId/devices/:deviceId/sensors";
public static final String GET_SENSORS = RAW_API_PREFIX + "/sensors"; public static final String SENSOR = RAW_API_PREFIX + "/groups/:groupId/devices/:deviceId/sensors/:sensorId";
public static final String POST_SENSORS = RAW_API_PREFIX + "/sensors"; public static final String SENSOR_VALUES = API_PREFIX + "/groups/:groupId/devices/:deviceId/sensors/:sensorId/values";
public static final String PUT_SENSOR_BY_ID = RAW_API_PREFIX + "/sensors/:sensorId";
public static final String ACTUATORS = RAW_API_PREFIX + "/groups/:groupId/devices/:deviceId/actuators";
public static final String GET_ACTUATORS = RAW_API_PREFIX + "/actuators"; public static final String ACTUATOR = RAW_API_PREFIX + "/groups/:groupId/devices/:deviceId/actuators/:actuator_id";
public static final String POST_ACTUATORS = RAW_API_PREFIX + "/actuators"; public static final String ACTUATOR_STATUS = API_PREFIX + "/groups/:groupId/devices/:deviceId/actuators/:actuator_id/status";
public static final String PUT_ACTUATOR_BY_ID = RAW_API_PREFIX + "/actuators/:actuatorId";
public static final String VIEW_LATEST_VALUES = RAW_API_PREFIX + "/v_latest_values";
public static final String GET_CO_BY_DEVICE_VIEW = RAW_API_PREFIX + "/v_co_by_device"; public static final String VIEW_POLLUTION_MAP = RAW_API_PREFIX + "/v_pollution_map";
public static final String VIEW_SENSOR_HISTORY = RAW_API_PREFIX + "/v_sensor_history_by_device";
public static final String GET_GPS_BY_DEVICE_VIEW = RAW_API_PREFIX + "/v_gps_by_device"; public static final String VIEW_SENSOR_VALUES = RAW_API_PREFIX + "/v_sensor_values";
public static final String GET_LATEST_VALUES_VIEW = RAW_API_PREFIX + "/v_latest_values"; public static final String VIEW_CO_BY_DEVICE = RAW_API_PREFIX + "/v_co_by_device";
public static final String GET_POLLUTION_MAP_VIEW = RAW_API_PREFIX + "/v_pollution_map"; public static final String VIEW_GPS_BY_DEVICE = RAW_API_PREFIX + "/v_gps_by_device";
public static final String GET_SENSOR_HISTORY_BY_DEVICE_VIEW = RAW_API_PREFIX + "/v_sensor_history_by_device"; public static final String VIEW_WEATHER_BY_DEVICE = RAW_API_PREFIX + "/v_weather_by_device";
public static final String GET_SENSOR_VALUES_VIEW = RAW_API_PREFIX + "/v_sensor_values";
public static final String GET_WEATHER_BY_DEVICE_VIEW = RAW_API_PREFIX + "/v_weather_by_device"; private Constants() {
throw new AssertionError("Utility class cannot be instantiated.");
/* Bussiness Logic API */ }
public static final String GET_GROUP_BY_ID = API_PREFIX + "/groups/:groupId"; }
public static final String GET_GROUP_DEVICES = API_PREFIX + "/groups/:groupId/devices";
public static final String GET_DEVICE_BY_ID = API_PREFIX + "/devices/:deviceId";
public static final String GET_DEVICE_SENSORS = API_PREFIX + "/devices/:deviceId/sensors";
public static final String GET_DEVICE_ACTUATORS = API_PREFIX + "/devices/:deviceId/actuators";
public static final String GET_DEVICE_LATEST_VALUES = API_PREFIX + "/devices/:deviceId/latest";
public static final String GET_DEVICE_POLLUTION_MAP = API_PREFIX + "/devices/:deviceId/pollution-map";
public static final String GET_DEVICE_HISTORY = API_PREFIX + "/devices/:deviceId/history";
public static final String GET_SENSOR_BY_ID = API_PREFIX + "/sensors/:sensorId";
public static final String GET_SENSOR_VALUES = API_PREFIX + "/sensors/:sensorId/values";
public static final String GET_ACTUATOR_BY_ID = API_PREFIX + "/actuators/:actuatorId";
private Constants() {
throw new AssertionError("Utility class cannot be instantiated.");
}
}

View File

@@ -0,0 +1,5 @@
package net.miarma.contaminus.common;
public interface ValuableEnum {
int getValue();
}

View File

@@ -0,0 +1,129 @@
package net.miarma.contaminus.dao;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.Actuator;
public class ActuatorDAO implements DataAccessObject<Actuator, Integer>{
private final DatabaseManager db;
public ActuatorDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<Actuator>> getAll() {
Promise<List<Actuator>> promise = Promise.promise();
String query = QueryBuilder.select(Actuator.class).build();
db.execute(query, Actuator.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
public Future<List<Actuator>> getAllByDeviceId(String deviceId) {
Promise<List<Actuator>> promise = Promise.promise();
Actuator actuator = new Actuator();
actuator.setDeviceId(deviceId);
String query = QueryBuilder
.select(Actuator.class)
.where(actuator)
.build();
db.execute(query, Actuator.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<Actuator> getById(Integer id) {
Promise<Actuator> promise = Promise.promise();
Actuator actuator = new Actuator();
actuator.setActuatorId(id);
String query = QueryBuilder
.select(Actuator.class)
.where(actuator)
.build();
db.execute(query, Actuator.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
public Future<Actuator> getByIdAndDeviceId(Integer actuatorId, String deviceId) {
Promise<Actuator> promise = Promise.promise();
Actuator actuator = new Actuator();
actuator.setDeviceId(deviceId);
actuator.setActuatorId(actuatorId);
String query = QueryBuilder
.select(Actuator.class)
.where(actuator)
.build();
db.execute(query, Actuator.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Actuator> insert(Actuator t) {
Promise<Actuator> promise = Promise.promise();
String query = QueryBuilder.insert(t).build();
db.execute(query, Actuator.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Actuator> update(Actuator t) {
Promise<Actuator> promise = Promise.promise();
String query = QueryBuilder.update(t).build();
db.execute(query, Actuator.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Actuator> delete(Integer id) {
Promise<Actuator> promise = Promise.promise();
Actuator actuator = new Actuator();
actuator.setActuatorId(id);
String query = QueryBuilder.delete(actuator).build();
db.executeOne(query, Actuator.class,
_ -> promise.complete(actuator),
promise::fail
);
return promise.future();
}
}

View File

@@ -0,0 +1,82 @@
package net.miarma.contaminus.dao;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.COValue;
public class COValueDAO implements DataAccessObject<COValue, Integer> {
private final DatabaseManager db;
public COValueDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<COValue>> getAll() {
Promise<List<COValue>> promise = Promise.promise();
String query = QueryBuilder.select(COValue.class).build();
db.execute(query, COValue.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<COValue> getById(Integer id) {
Promise<COValue> promise = Promise.promise();
COValue coValue = new COValue();
coValue.setValueId(id);
String query = QueryBuilder
.select(COValue.class)
.where(coValue)
.build();
db.execute(query, COValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<COValue> insert(COValue t) {
Promise<COValue> promise = Promise.promise();
String query = QueryBuilder.insert(t).build();
db.execute(query, COValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<COValue> update(COValue t) {
Promise<COValue> promise = Promise.promise();
String query = QueryBuilder.update(t).build();
db.execute(query, COValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<COValue> delete(Integer id) {
throw new UnsupportedOperationException("Cannot delete samples");
}
}

View File

@@ -0,0 +1,128 @@
package net.miarma.contaminus.dao;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.Device;
public class DeviceDAO implements DataAccessObject<Device, String> {
private final DatabaseManager db;
public DeviceDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<Device>> getAll() {
Promise<List<Device>> promise = Promise.promise();
String query = QueryBuilder.select(Device.class).build();
db.execute(query, Device.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
public Future<List<Device>> getAllByGroupId(Integer groupId) {
Promise<List<Device>> promise = Promise.promise();
Device device = new Device();
device.setGroupId(groupId);
String query = QueryBuilder
.select(Device.class)
.where(device)
.build();
db.execute(query, Device.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<Device> getById(String id) {
Promise<Device> promise = Promise.promise();
Device device = new Device();
device.setDeviceId(id);
String query = QueryBuilder
.select(Device.class)
.where(device)
.build();
db.execute(query, Device.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
public Future<Device> getByIdAndGroupId(String id, Integer groupId) {
Promise<Device> promise = Promise.promise();
Device device = new Device();
device.setDeviceId(id);
device.setGroupId(groupId);
String query = QueryBuilder
.select(Device.class)
.where(device)
.build();
db.execute(query, Device.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Device> insert(Device t) {
Promise<Device> promise = Promise.promise();
String query = QueryBuilder.insert(t).build();
db.execute(query, Device.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Device> update(Device t) {
Promise<Device> promise = Promise.promise();
String query = QueryBuilder.update(t).build();
db.execute(query, Device.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Device> delete(String id) {
Promise<Device> promise = Promise.promise();
Device device = new Device();
device.setDeviceId(id);
String query = QueryBuilder.delete(device).build();
db.execute(query, Device.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
}

View File

@@ -0,0 +1,81 @@
package net.miarma.contaminus.dao;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.GpsValue;
public class GpsValueDAO implements DataAccessObject<GpsValue, Integer> {
private final DatabaseManager db;
public GpsValueDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<GpsValue>> getAll() {
Promise<List<GpsValue>> promise = Promise.promise();
String query = QueryBuilder.select(GpsValue.class).build();
db.execute(query, GpsValue.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<GpsValue> getById(Integer id) {
Promise<GpsValue> promise = Promise.promise();
GpsValue gpsValue = new GpsValue();
gpsValue.setValueId(id);
String query = QueryBuilder
.select(GpsValue.class)
.where(gpsValue)
.build();
db.execute(query, GpsValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<GpsValue> insert(GpsValue t) {
Promise<GpsValue> promise = Promise.promise();
String query = QueryBuilder.insert(t).build();
db.execute(query, GpsValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<GpsValue> update(GpsValue t) {
Promise<GpsValue> promise = Promise.promise();
String query = QueryBuilder.update(t).build();
db.execute(query, GpsValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<GpsValue> delete(Integer id) {
throw new UnsupportedOperationException("Cannot delete samples");
}
}

View File

@@ -0,0 +1,93 @@
package net.miarma.contaminus.dao;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.Group;
public class GroupDAO implements DataAccessObject<Group, Integer> {
private final DatabaseManager db;
public GroupDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<Group>> getAll() {
Promise<List<Group>> promise = Promise.promise();
String query = QueryBuilder.select(Group.class).build();
db.execute(query, Group.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<Group> getById(Integer id) {
Promise<Group> promise = Promise.promise();
Group group = new Group();
group.setGroupId(id);
String query = QueryBuilder
.select(Group.class)
.where(group)
.build();
db.execute(query, Group.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Group> insert(Group t) {
Promise<Group> promise = Promise.promise();
String query = QueryBuilder.insert(t).build();
db.execute(query, Group.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Group> update(Group t) {
Promise<Group> promise = Promise.promise();
String query = QueryBuilder.update(t).build();
db.execute(query, Group.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Group> delete(Integer id) {
Promise<Group> promise = Promise.promise();
Group group = new Group();
group.setGroupId(id);
String query = QueryBuilder.delete(group).build();
db.execute(query, Group.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
}

View File

@@ -0,0 +1,130 @@
package net.miarma.contaminus.dao;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.Sensor;
public class SensorDAO implements DataAccessObject<Sensor, Integer> {
private final DatabaseManager db;
public SensorDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<Sensor>> getAll() {
Promise<List<Sensor>> promise = Promise.promise();
String query = QueryBuilder.select(Sensor.class).build();
db.execute(query, Sensor.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
public Future<List<Sensor>> getAllByDeviceId(String deviceId) {
Promise<List<Sensor>> promise = Promise.promise();
Sensor sensor = new Sensor();
sensor.setDeviceId(deviceId);
String query = QueryBuilder
.select(Sensor.class)
.where(sensor)
.build();
db.execute(query, Sensor.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<Sensor> getById(Integer id) {
Promise<Sensor> promise = Promise.promise();
Sensor sensor = new Sensor();
sensor.setSensorId(id);
String query = QueryBuilder
.select(Sensor.class)
.where(sensor)
.build();
db.execute(query, Sensor.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
public Future<Sensor> getByIdAndDeviceId(Integer sensorId, String deviceId) {
Promise<Sensor> promise = Promise.promise();
Sensor sensor = new Sensor();
sensor.setDeviceId(deviceId);
sensor.setSensorId(sensorId);
String query = QueryBuilder
.select(Sensor.class)
.where(sensor)
.build();
db.execute(query, Sensor.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Sensor> insert(Sensor t) {
Promise<Sensor> promise = Promise.promise();
String query = QueryBuilder.insert(t).build();
db.execute(query, Sensor.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Sensor> update(Sensor t) {
Promise<Sensor> promise = Promise.promise();
String query = QueryBuilder.update(t).build();
db.execute(query, Sensor.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<Sensor> delete(Integer id) {
Promise<Sensor> promise = Promise.promise();
Sensor sensor = new Sensor();
sensor.setSensorId(id);
String query = QueryBuilder.delete(sensor).build();
db.execute(query, Sensor.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
}

View File

@@ -0,0 +1,81 @@
package net.miarma.contaminus.dao;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.WeatherValue;
public class WeatherValueDAO implements DataAccessObject<WeatherValue, Integer> {
private final DatabaseManager db;
public WeatherValueDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<WeatherValue>> getAll() {
Promise<List<WeatherValue>> promise = Promise.promise();
String query = QueryBuilder.select(WeatherValue.class).build();
db.execute(query, WeatherValue.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<WeatherValue> getById(Integer id) {
Promise<WeatherValue> promise = Promise.promise();
WeatherValue weatherValue = new WeatherValue();
weatherValue.setValueId(id);
String query = QueryBuilder
.select(WeatherValue.class)
.where(weatherValue)
.build();
db.execute(query, WeatherValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<WeatherValue> insert(WeatherValue t) {
Promise<WeatherValue> promise = Promise.promise();
String query = QueryBuilder.insert(t).build();
db.execute(query, WeatherValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<WeatherValue> update(WeatherValue t) {
Promise<WeatherValue> promise = Promise.promise();
String query = QueryBuilder.update(t).build();
db.execute(query, WeatherValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<WeatherValue> delete(Integer id) {
throw new UnsupportedOperationException("Cannot delete samples");
}
}

View File

@@ -0,0 +1,66 @@
package net.miarma.contaminus.dao.views;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.ViewLatestValues;
public class ViewLatestValuesDAO implements DataAccessObject<ViewLatestValues, String> {
private final DatabaseManager db;
public ViewLatestValuesDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<ViewLatestValues>> getAll() {
Promise<List<ViewLatestValues>> promise = Promise.promise();
String query = QueryBuilder.select(ViewLatestValues.class).build();
db.execute(query, ViewLatestValues.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewLatestValues> getById(String id) {
Promise<ViewLatestValues> promise = Promise.promise();
ViewLatestValues view = new ViewLatestValues();
view.setDeviceId(id);
String query = QueryBuilder
.select(ViewLatestValues.class)
.where(view)
.build();
db.execute(query, ViewLatestValues.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewLatestValues> insert(ViewLatestValues t) {
throw new UnsupportedOperationException("Insert not supported for views");
}
@Override
public Future<ViewLatestValues> update(ViewLatestValues t) {
throw new UnsupportedOperationException("Update not supported for views");
}
@Override
public Future<ViewLatestValues> delete(String id) {
throw new UnsupportedOperationException("Delete not supported for views");
}
}

View File

@@ -0,0 +1,66 @@
package net.miarma.contaminus.dao.views;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.ViewPollutionMap;
@Table("v_pollution_map")
public class ViewPollutionMapDAO implements DataAccessObject<ViewPollutionMap, String> {
private final DatabaseManager db;
public ViewPollutionMapDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<ViewPollutionMap>> getAll() {
Promise<List<ViewPollutionMap>> promise = Promise.promise();
String query = QueryBuilder.select(ViewPollutionMap.class).build();
db.execute(query, ViewPollutionMap.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewPollutionMap> getById(String id) {
Promise<ViewPollutionMap> promise = Promise.promise();
ViewPollutionMap view = new ViewPollutionMap();
view.setDeviceId(id);
String query = QueryBuilder
.select(ViewPollutionMap.class)
.where(view)
.build();
db.execute(query, ViewPollutionMap.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewPollutionMap> insert(ViewPollutionMap t) {
throw new UnsupportedOperationException("Insert not supported for views");
}
@Override
public Future<ViewPollutionMap> update(ViewPollutionMap t) {
throw new UnsupportedOperationException("Update not supported for views");
}
@Override
public Future<ViewPollutionMap> delete(String id) {
throw new UnsupportedOperationException("Delete not supported for views");
}
}

View File

@@ -0,0 +1,67 @@
package net.miarma.contaminus.dao.views;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.ViewSensorHistory;
public class ViewSensorHistoryDAO implements DataAccessObject<ViewSensorHistory, String> {
private final DatabaseManager db;
public ViewSensorHistoryDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<ViewSensorHistory>> getAll() {
Promise<List<ViewSensorHistory>> promise = Promise.promise();
String query = QueryBuilder.select(ViewSensorHistory.class).build();
db.execute(query, ViewSensorHistory.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewSensorHistory> getById(String id) {
Promise<ViewSensorHistory> promise = Promise.promise();
ViewSensorHistory viewSensorHistory = new ViewSensorHistory();
viewSensorHistory.setDeviceId(id);
String query = QueryBuilder
.select(ViewSensorHistory.class)
.where(viewSensorHistory)
.build();
db.execute(query, ViewSensorHistory.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewSensorHistory> insert(ViewSensorHistory t) {
throw new UnsupportedOperationException("Insert not supported for views");
}
@Override
public Future<ViewSensorHistory> update(ViewSensorHistory t) {
throw new UnsupportedOperationException("Update not supported for views");
}
@Override
public Future<ViewSensorHistory> delete(String id) {
throw new UnsupportedOperationException("Delete not supported for views");
}
}

View File

@@ -0,0 +1,66 @@
package net.miarma.contaminus.dao.views;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.db.DataAccessObject;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.ViewSensorValue;
public class ViewSensorValueDAO implements DataAccessObject<ViewSensorValue, Integer> {
private final DatabaseManager db;
public ViewSensorValueDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<ViewSensorValue>> getAll() {
Promise<List<ViewSensorValue>> promise = Promise.promise();
String query = QueryBuilder.select(ViewSensorValue.class).build();
db.execute(query, ViewSensorValue.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewSensorValue> getById(Integer id) {
Promise<ViewSensorValue> promise = Promise.promise();
ViewSensorValue view = new ViewSensorValue();
view.setSensorId(id);
String query = QueryBuilder
.select(ViewSensorValue.class)
.where(view)
.build();
db.execute(query, ViewSensorValue.class,
list -> promise.complete(list.isEmpty() ? null : list.get(0)),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewSensorValue> insert(ViewSensorValue t) {
throw new UnsupportedOperationException("Insert not supported for views");
}
@Override
public Future<ViewSensorValue> update(ViewSensorValue t) {
throw new UnsupportedOperationException("Update not supported for views");
}
@Override
public Future<ViewSensorValue> delete(Integer id) {
throw new UnsupportedOperationException("Delete not supported for views");
}
}

View File

@@ -1,58 +0,0 @@
package net.miarma.contaminus.database;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.jdbcclient.JDBCPool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import net.miarma.contaminus.common.Constants;
public class DatabaseManager {
private static DatabaseManager instance;
private final JDBCPool pool;
private DatabaseManager(JDBCPool pool) {
this.pool = pool;
}
public static synchronized DatabaseManager getInstance(JDBCPool pool) {
if (instance == null) {
instance = new DatabaseManager(pool);
}
return instance;
}
public Future<RowSet<Row>> testConnection() {
return pool.query("SELECT 1").execute();
}
public <T> Future<List<T>> execute(String query, Class<T> clazz,
Handler<List<T>> onSuccess, Handler<Throwable> onFailure) {
return pool.query(query).execute()
.map(rows -> {
List<T> results = new ArrayList<>();
for (Row row : rows) {
try {
Constructor<T> constructor = clazz.getConstructor(Row.class);
results.add(constructor.newInstance(row));
} catch (NoSuchMethodException | InstantiationException |
IllegalAccessException | InvocationTargetException e) {
Constants.LOGGER.error("Error instantiating class: " + e.getMessage());
}
}
return results;
})
.onComplete(ar -> {
if (ar.succeeded()) {
onSuccess.handle(ar.result());
} else {
onFailure.handle(ar.cause());
}
});
}
}

View File

@@ -1,196 +0,0 @@
package net.miarma.contaminus.database;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.StringJoiner;
import net.miarma.contaminus.common.Constants;
import net.miarma.contaminus.common.Table;
public class QueryBuilder {
private StringBuilder query;
private String sort;
private String order;
private String limit;
public QueryBuilder() {
this.query = new StringBuilder();
}
private static <T> String getTableName(Class<T> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class cannot be null");
}
if (clazz.isAnnotationPresent(Table.class)) {
Table annotation = clazz.getAnnotation(Table.class);
return annotation.value();
}
throw new IllegalArgumentException("Class does not have @Table annotation");
}
public String getQuery() {
return query.toString();
}
public static <T> QueryBuilder select(Class<T> clazz, String... columns) {
if (clazz == null) {
throw new IllegalArgumentException("Class cannot be null");
}
QueryBuilder qb = new QueryBuilder();
String tableName = getTableName(clazz);
qb.query.append("SELECT ");
if (columns.length == 0) {
qb.query.append("* ");
} else {
StringJoiner joiner = new StringJoiner(", ");
for (String column : columns) {
if (column != null) {
joiner.add(column);
}
}
qb.query.append(joiner).append(" ");
}
qb.query.append("FROM ").append(tableName).append(" ");
return qb;
}
public static <T> QueryBuilder where(QueryBuilder qb, T object) {
if (qb == null || object == null) {
throw new IllegalArgumentException("QueryBuilder and object cannot be null");
}
List<String> conditions = new ArrayList<>();
Class<?> clazz = object.getClass();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
try {
Object value = field.get(object);
if (value != null) {
if (value instanceof String) {
conditions.add(field.getName() + " = '" + value + "'");
} else {
conditions.add(field.getName() + " = " + value);
}
}
} catch (IllegalAccessException e) {
Constants.LOGGER.error("(REFLECTION) Error reading field: " + e.getMessage());
}
}
if (!conditions.isEmpty()) {
qb.query.append("WHERE ").append(String.join(" AND ", conditions)).append(" ");
}
return qb;
}
public static <T> QueryBuilder select(T object, String... columns) {
if (object == null) {
throw new IllegalArgumentException("Object cannot be null");
}
Class<?> clazz = object.getClass();
QueryBuilder qb = select(clazz, columns);
return where(qb, object);
}
public static <T> QueryBuilder insert(T object) {
if (object == null) {
throw new IllegalArgumentException("Object cannot be null");
}
QueryBuilder qb = new QueryBuilder();
String table = getTableName(object.getClass());
qb.query.append("INSERT INTO ").append(table).append(" ");
qb.query.append("(");
StringJoiner columns = new StringJoiner(", ");
StringJoiner values = new StringJoiner(", ");
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
columns.add(field.getName());
Object fieldValue = field.get(object);
if (fieldValue != null) {
if (fieldValue instanceof String) {
values.add("'" + fieldValue + "'");
} else {
values.add(fieldValue.toString());
}
} else {
values.add("NULL");
}
} catch (IllegalArgumentException | IllegalAccessException e) {
Constants.LOGGER.error("(REFLECTION) Error reading field: " + e.getMessage());
}
}
qb.query.append(columns).append(") ");
qb.query.append("VALUES (").append(values).append(") ");
return qb;
}
public static <T> QueryBuilder update(T object) {
if (object == null) {
throw new IllegalArgumentException("Object cannot be null");
}
QueryBuilder qb = new QueryBuilder();
String table = getTableName(object.getClass());
qb.query.append("UPDATE ").append(table).append(" ");
qb.query.append("SET ");
StringJoiner joiner = new StringJoiner(", ");
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
Object fieldValue = field.get(object);
if (fieldValue != null) {
if (fieldValue instanceof String) {
joiner.add(field.getName() + " = '" + fieldValue + "'");
} else {
joiner.add(field.getName() + " = " + fieldValue.toString());
}
} else {
joiner.add(field.getName() + " = NULL");
}
} catch (IllegalArgumentException | IllegalAccessException e) {
Constants.LOGGER.error("(REFLECTION) Error reading field: " + e.getMessage());
}
}
qb.query.append(joiner).append(" ");
return qb;
}
public QueryBuilder orderBy(Optional<String> column, Optional<String> order) {
column.ifPresent(c -> {
sort = "ORDER BY " + c + " ";
order.ifPresent(o -> {
sort += o.equalsIgnoreCase("asc") ? "ASC" : "DESC" + " ";
});
});
return this;
}
public QueryBuilder limit(Optional<Integer> limitParam) {
limitParam.ifPresent(param -> limit = "LIMIT " + param + " ");
return this;
}
public String build() {
if (order != null && !order.isEmpty()) {
query.append(order);
}
if (sort != null && !sort.isEmpty()) {
query.append(sort);
}
if (limit != null && !limit.isEmpty()) {
query.append(limit);
}
return query.toString().trim() + ";";
}
}

View File

@@ -1,67 +0,0 @@
package net.miarma.contaminus.database.entities;
import java.util.Objects;
import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser;
@Table("v_co_by_device")
public class DeviceCO {
private String deviceId;
private Float carbonMonoxide;
private Long timestamp;
public DeviceCO() {}
public DeviceCO(Row row) {
this.deviceId = row.getString("deviceId");
this.carbonMonoxide = row.getFloat("carbonMonoxide");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
}
public DeviceCO(String deviceId, Float carbonMonoxide, Long timestamp) {
super();
this.deviceId = deviceId;
this.carbonMonoxide = carbonMonoxide;
this.timestamp = timestamp;
}
public String getDeviceId() {
return deviceId;
}
public Float getCarbonMonoxide() {
return carbonMonoxide;
}
public Long getTimestamp() {
return timestamp;
}
@Override
public int hashCode() {
return Objects.hash(carbonMonoxide, deviceId, timestamp);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DeviceCO other = (DeviceCO) obj;
return Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId)
&& Objects.equals(timestamp, other.timestamp);
}
@Override
public String toString() {
return "DeviceCO [deviceId=" + deviceId + ", carbonMonoxide=" + carbonMonoxide + ", timestamp=" + timestamp
+ "]";
}
}

View File

@@ -1,72 +0,0 @@
package net.miarma.contaminus.database.entities;
import java.util.Objects;
import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser;
@Table("v_gps_by_device")
public class DeviceGPS {
private String deviceId;
private Float lat;
private Float lon;
private Long timestamp;
public DeviceGPS() {}
public DeviceGPS(Row row) {
this.deviceId = row.getString("deviceId");
this.lat = row.getFloat("lat");
this.lon = row.getFloat("lon");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
}
public DeviceGPS(String deviceId, Float lat, Float lon) {
super();
this.deviceId = deviceId;
this.lat = lat;
this.lon = lon;
}
public String getDeviceId() {
return deviceId;
}
public Float getLat() {
return lat;
}
public Float getLon() {
return lon;
}
public Long getTimestamp() {
return timestamp;
}
@Override
public int hashCode() {
return Objects.hash(deviceId, lat, lon, timestamp);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DeviceGPS other = (DeviceGPS) obj;
return Objects.equals(deviceId, other.deviceId) && Objects.equals(lat, other.lat)
&& Objects.equals(lon, other.lon) && Objects.equals(timestamp, other.timestamp);
}
@Override
public String toString() {
return "DeviceGPS [deviceId=" + deviceId + ", lat=" + lat + ", lon=" + lon + ", timestamp=" + timestamp + "]";
}
}

View File

@@ -1,74 +0,0 @@
package net.miarma.contaminus.database.entities;
import java.util.Objects;
import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser;
@Table("v_weather_by_device")
public class DeviceWeather {
private String deviceId;
private Float temperature;
private Float humidity;
private Long timestamp;
public DeviceWeather() {}
public DeviceWeather(Row row) {
this.deviceId = row.getString("deviceId");
this.temperature = row.getFloat("temperature");
this.humidity = row.getFloat("humidity");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
}
public DeviceWeather(String deviceId, Float temperature, Float humidity, Long timestamp) {
super();
this.deviceId = deviceId;
this.temperature = temperature;
this.humidity = humidity;
this.timestamp = timestamp;
}
public String getDeviceId() {
return deviceId;
}
public Float getTemperature() {
return temperature;
}
public Float getHumidity() {
return humidity;
}
public Long getTimestamp() {
return timestamp;
}
@Override
public int hashCode() {
return Objects.hash(deviceId, humidity, temperature, timestamp);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DeviceWeather other = (DeviceWeather) obj;
return Objects.equals(deviceId, other.deviceId) && Objects.equals(humidity, other.humidity)
&& Objects.equals(temperature, other.temperature) && Objects.equals(timestamp, other.timestamp);
}
@Override
public String toString() {
return "DeviceWeather [deviceId=" + deviceId + ", temperature=" + temperature + ", humidity=" + humidity
+ ", timestamp=" + timestamp + "]";
}
}

View File

@@ -0,0 +1,13 @@
package net.miarma.contaminus.db;
import java.util.List;
import io.vertx.core.Future;
public interface DataAccessObject<T, ID> {
Future<List<T>> getAll();
Future<T> getById(ID id);
Future<T> insert(T t);
Future<T> update(T t);
Future<T> delete(ID id);
}

View File

@@ -0,0 +1,82 @@
package net.miarma.contaminus.db;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import net.miarma.contaminus.common.Constants;
public class DatabaseManager {
private static DatabaseManager instance;
private final Pool pool;
private DatabaseManager(Pool pool) {
this.pool = pool;
}
public static synchronized DatabaseManager getInstance(Pool pool) {
if (instance == null) {
instance = new DatabaseManager(pool);
}
return instance;
}
public Pool getPool() {
return pool;
}
public Future<RowSet<Row>> testConnection() {
return pool.query("SELECT 1").execute();
}
public <T> Future<List<T>> execute(String query, Class<T> clazz, Handler<List<T>> onSuccess,
Handler<Throwable> onFailure) {
return pool.query(query).execute().map(rows -> {
List<T> results = new ArrayList<>();
for (Row row : rows) {
try {
Constructor<T> constructor = clazz.getConstructor(Row.class);
results.add(constructor.newInstance(row));
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException
| InvocationTargetException e) {
Constants.LOGGER.error("Error instantiating class: " + e.getMessage());
}
}
return results;
}).onComplete(ar -> {
if (ar.succeeded()) {
onSuccess.handle(ar.result());
} else {
onFailure.handle(ar.cause());
}
});
}
public <T> Future<T> executeOne(String query, Class<T> clazz, Handler<T> onSuccess, Handler<Throwable> onFailure) {
return pool.query(query).execute().map(rows -> {
for (Row row : rows) {
try {
Constructor<T> constructor = clazz.getConstructor(Row.class);
return constructor.newInstance(row);
} catch (Exception e) {
Constants.LOGGER.error("Error instantiating class: " + e.getMessage());
}
}
return null; // Si no hay filas
}).onComplete(ar -> {
if (ar.succeeded()) {
onSuccess.handle(ar.result());
} else {
onFailure.handle(ar.cause());
}
});
}
}

View File

@@ -0,0 +1,21 @@
package net.miarma.contaminus.db;
import io.vertx.core.Vertx;
import io.vertx.mysqlclient.MySQLConnectOptions;
import io.vertx.sqlclient.Pool;
import io.vertx.sqlclient.PoolOptions;
import net.miarma.contaminus.common.ConfigManager;
public class DatabaseProvider {
public static Pool createPool(Vertx vertx, ConfigManager config) {
MySQLConnectOptions connectOptions = new MySQLConnectOptions()
.setPort(config.getIntProperty("db.port"))
.setHost(config.getStringProperty("db.host"))
.setDatabase(config.getStringProperty("db.name"))
.setUser(config.getStringProperty("db.user"))
.setPassword(config.getStringProperty("db.password"));
PoolOptions poolOptions = new PoolOptions().setMaxSize(10);
return Pool.pool(vertx, connectOptions, poolOptions);
}
}

View File

@@ -0,0 +1,357 @@
package net.miarma.contaminus.db;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import net.miarma.contaminus.common.Constants;
import net.miarma.contaminus.common.Table;
public class QueryBuilder {
private final StringBuilder query;
private String sort;
private String order;
private String limit;
private Class<?> entityClass;
public QueryBuilder() {
this.query = new StringBuilder();
}
private static <T> String getTableName(Class<T> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class cannot be null");
}
if (clazz.isAnnotationPresent(Table.class)) {
Table annotation = clazz.getAnnotation(Table.class);
return annotation.value();
}
throw new IllegalArgumentException("Class does not have @Table annotation");
}
public String getQuery() {
return query.toString();
}
private static Object extractValue(Object fieldValue) {
if (fieldValue instanceof Enum<?>) {
try {
var method = fieldValue.getClass().getMethod("getValue");
return method.invoke(fieldValue);
} catch (Exception e) {
return ((Enum<?>) fieldValue).name();
}
}
return fieldValue;
}
public static <T> QueryBuilder select(Class<T> clazz, String... columns) {
if (clazz == null) {
throw new IllegalArgumentException("Class cannot be null");
}
QueryBuilder qb = new QueryBuilder();
qb.entityClass = clazz;
String tableName = getTableName(clazz);
qb.query.append("SELECT ");
if (columns.length == 0) {
qb.query.append("* ");
} else {
StringJoiner joiner = new StringJoiner(", ");
for (String column : columns) {
if (column != null) {
joiner.add(column);
}
}
qb.query.append(joiner).append(" ");
}
qb.query.append("FROM ").append(tableName).append(" ");
return qb;
}
public QueryBuilder where(Map<String, String> filters) {
if (filters == null || filters.isEmpty()) {
return this;
}
Set<String> validFields = entityClass != null
? Arrays.stream(entityClass.getDeclaredFields()).map(Field::getName).collect(Collectors.toSet())
: Collections.emptySet();
List<String> conditions = new ArrayList<>();
for (Map.Entry<String, String> entry : filters.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (!validFields.contains(key)) {
Constants.LOGGER.warn("[QueryBuilder] Ignorando campo invalido en WHERE: " + key);
continue;
}
if (value.startsWith("(") && value.endsWith(")")) {
conditions.add(key + " IN " + value);
} else if (value.matches("-?\\d+(\\.\\d+)?")) {
conditions.add(key + " = " + value);
} else {
conditions.add(key + " = '" + value + "'");
}
}
if (!conditions.isEmpty()) {
query.append("WHERE ").append(String.join(" AND ", conditions)).append(" ");
}
return this;
}
public <T> QueryBuilder where(T object) {
if (object == null) {
throw new IllegalArgumentException("Object cannot be null");
}
Set<String> validFields = entityClass != null
? Arrays.stream(entityClass.getDeclaredFields()).map(Field::getName).collect(Collectors.toSet())
: Collections.emptySet();
List<String> conditions = new ArrayList<>();
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
Object fieldValue = field.get(object);
if (fieldValue != null) {
String key = field.getName();
if (!validFields.contains(key)) {
Constants.LOGGER.warn("[QueryBuilder] Ignorando campo invalido en WHERE: " + key);
continue;
}
Object value = extractValue(fieldValue);
if (value instanceof String || value instanceof LocalDateTime) {
conditions.add(key + " = '" + value + "'");
} else {
conditions.add(key + " = " + value);
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
Constants.LOGGER.error("(REFLECTION) Error reading field: " + e.getMessage());
}
}
if (!conditions.isEmpty()) {
query.append("WHERE ").append(String.join(" AND ", conditions)).append(" ");
}
return this;
}
public static <T> QueryBuilder insert(T object) {
if (object == null) {
throw new IllegalArgumentException("Object cannot be null");
}
QueryBuilder qb = new QueryBuilder();
String table = getTableName(object.getClass());
qb.query.append("INSERT INTO ").append(table).append(" ");
qb.query.append("(");
StringJoiner columns = new StringJoiner(", ");
StringJoiner values = new StringJoiner(", ");
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
columns.add(field.getName());
Object fieldValue = field.get(object);
if (fieldValue != null) {
Object value = extractValue(fieldValue);
if (value instanceof String || value instanceof LocalDateTime) {
values.add("'" + value + "'");
} else {
values.add(value.toString());
}
} else {
values.add("NULL");
}
} catch (IllegalArgumentException | IllegalAccessException e) {
Constants.LOGGER.error("(REFLECTION) Error reading field: " + e.getMessage());
}
}
qb.query.append(columns).append(") ");
qb.query.append("VALUES (").append(values).append(") RETURNING * ");
return qb;
}
public static <T> QueryBuilder update(T object) {
if (object == null) {
throw new IllegalArgumentException("Object cannot be null");
}
QueryBuilder qb = new QueryBuilder();
String table = getTableName(object.getClass());
qb.query.append("UPDATE ").append(table).append(" SET ");
StringJoiner setJoiner = new StringJoiner(", ");
StringJoiner whereJoiner = new StringJoiner(" AND ");
Field idField = null;
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
Object fieldValue = field.get(object);
if (fieldValue == null) continue;
String fieldName = field.getName();
Object value = extractValue(fieldValue);
if (fieldName.endsWith("_id")) {
idField = field;
whereJoiner.add(fieldName + " = " + (value instanceof String
|| value instanceof LocalDateTime ? "'" + value + "'" : value));
continue;
}
setJoiner.add(fieldName + " = " + (value instanceof String
|| value instanceof LocalDateTime ? "'" + value + "'" : value));
} catch (Exception e) {
Constants.LOGGER.error("(REFLECTION) Error reading field: " + e.getMessage());
}
}
if (idField == null) {
throw new IllegalArgumentException("No ID field (ending with _id) found for WHERE clause");
}
qb.query.append(setJoiner).append(" WHERE ").append(whereJoiner);
return qb;
}
public static <T> QueryBuilder updateWithNulls(T object) {
if (object == null) {
throw new IllegalArgumentException("Object cannot be null");
}
QueryBuilder qb = new QueryBuilder();
String table = getTableName(object.getClass());
qb.query.append("UPDATE ").append(table).append(" SET ");
StringJoiner setJoiner = new StringJoiner(", ");
StringJoiner whereJoiner = new StringJoiner(" AND ");
Field idField = null;
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
String fieldName = field.getName();
Object fieldValue = field.get(object);
if (fieldName.endsWith("_id")) {
idField = field;
Object value = extractValue(fieldValue);
whereJoiner.add(fieldName + " = " + (value instanceof String || value instanceof LocalDateTime ? "'" + value + "'" : value));
continue;
}
if (fieldValue == null) {
setJoiner.add(fieldName + " = NULL"); // ✅ esto lo borra en la BD
} else {
Object value = extractValue(fieldValue);
setJoiner.add(fieldName + " = " + (value instanceof String || value instanceof LocalDateTime ? "'" + value + "'" : value));
}
} catch (Exception e) {
Constants.LOGGER.error("(REFLECTION) Error reading field: " + e.getMessage());
}
}
if (idField == null) {
throw new IllegalArgumentException("No ID field (ending with _id) found for WHERE clause");
}
qb.query.append(setJoiner).append(" WHERE ").append(whereJoiner);
return qb;
}
public static <T> QueryBuilder delete(T object) {
if (object == null) throw new IllegalArgumentException("Object cannot be null");
QueryBuilder qb = new QueryBuilder();
String table = getTableName(object.getClass());
qb.query.append("DELETE FROM ").append(table).append(" WHERE ");
StringJoiner joiner = new StringJoiner(" AND ");
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
Object fieldValue = field.get(object);
if (fieldValue != null) {
Object value = extractValue(fieldValue);
joiner.add(field.getName() + " = " + (value instanceof String
|| value instanceof LocalDateTime ? "'" + value + "'" : value.toString()));
}
} catch (Exception e) {
Constants.LOGGER.error("(REFLECTION) Error reading field: " + e.getMessage());
}
}
qb.query.append(joiner).append(" ");
return qb;
}
public QueryBuilder orderBy(Optional<String> column, Optional<String> order) {
column.ifPresent(c -> {
if (entityClass != null) {
boolean isValid = Arrays.stream(entityClass.getDeclaredFields())
.map(Field::getName)
.anyMatch(f -> f.equals(c));
if (!isValid) {
Constants.LOGGER.warn("[QueryBuilder] Ignorando campo invalido en ORDER BY: " + c);
return;
}
}
sort = "ORDER BY " + c + " ";
order.ifPresent(o -> {
sort += o.equalsIgnoreCase("asc") ? "ASC" : "DESC" + " ";
});
});
return this;
}
public QueryBuilder limit(Optional<Integer> limitParam) {
limitParam.ifPresent(param -> limit = "LIMIT " + param + " ");
return this;
}
public QueryBuilder offset(Optional<Integer> offsetParam) {
offsetParam.ifPresent(param -> limit += "OFFSET " + param + " ");
return this;
}
public String build() {
if (order != null && !order.isEmpty()) {
query.append(order);
}
if (sort != null && !sort.isEmpty()) {
query.append(sort);
}
if (limit != null && !limit.isEmpty()) {
query.append(limit);
}
return query.toString().trim() + ";";
}
}

View File

@@ -1,92 +1,92 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("actuators") @Table("actuators")
public class Actuator { public class Actuator {
private Integer actuatorId; private Integer actuatorId;
private String deviceId; private String deviceId;
private Integer status; private Integer status;
private Long timestamp; private Long timestamp;
public Actuator() {} public Actuator() {}
public Actuator(Row row) { public Actuator(Row row) {
this.actuatorId = row.getInteger("actuatorId"); this.actuatorId = row.getInteger("actuatorId");
this.deviceId = row.getString("deviceId"); this.deviceId = row.getString("deviceId");
this.status = row.getInteger("status"); this.status = row.getInteger("status");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp")); this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
} }
public Actuator(Integer actuatorId, String deviceId, Integer status, Long timestamp) { public Actuator(Integer actuatorId, String deviceId, Integer status, Long timestamp) {
super(); super();
this.actuatorId = actuatorId; this.actuatorId = actuatorId;
this.deviceId = deviceId; this.deviceId = deviceId;
this.status = status; this.status = status;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public Integer getActuatorId() { public Integer getActuatorId() {
return actuatorId; return actuatorId;
} }
public void setActuatorId(Integer actuatorId) { public void setActuatorId(Integer actuatorId) {
this.actuatorId = actuatorId; this.actuatorId = actuatorId;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public void setDeviceId(String deviceId) { public void setDeviceId(String deviceId) {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public Integer getStatus() { public Integer getStatus() {
return status; return status;
} }
public void setStatus(Integer status) { public void setStatus(Integer status) {
this.status = status; this.status = status;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
public void setTimestamp(Long timestamp) { public void setTimestamp(Long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(actuatorId, deviceId, status, timestamp); return Objects.hash(actuatorId, deviceId, status, timestamp);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
Actuator other = (Actuator) obj; Actuator other = (Actuator) obj;
return actuatorId == other.actuatorId && deviceId == other.deviceId return actuatorId == other.actuatorId && deviceId == other.deviceId
&& status == other.status && timestamp == other.timestamp; && status == other.status && timestamp == other.timestamp;
} }
@Override @Override
public String toString() { public String toString() {
return "Actuator [actuatorId=" + actuatorId + ", deviceId=" + deviceId + ", status=" + status + ", timestamp=" return "Actuator [actuatorId=" + actuatorId + ", deviceId=" + deviceId + ", status=" + status + ", timestamp="
+ timestamp + "]"; + timestamp + "]";
} }
} }

View File

@@ -1,107 +1,107 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("co_values") @Table("co_values")
public class COValue { public class COValue {
private Integer valueId; private Integer valueId;
private String deviceId; private String deviceId;
private Integer sensorId; private Integer sensorId;
private Float value; private Float value;
private Long timestamp; private Long timestamp;
public COValue() {} public COValue() {}
public COValue(Row row) { public COValue(Row row) {
this.valueId = row.getInteger("valueId"); this.valueId = row.getInteger("valueId");
this.deviceId = row.getString("deviceId"); this.deviceId = row.getString("deviceId");
this.sensorId = row.getInteger("sensorId"); this.sensorId = row.getInteger("sensorId");
this.value = row.getFloat("value"); this.value = row.getFloat("value");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp")); this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
} }
public COValue(Integer valueId, String deviceId, Integer sensorId, Float value, Long timestamp) { public COValue(Integer valueId, String deviceId, Integer sensorId, Float value, Long timestamp) {
super(); super();
this.valueId = valueId; this.valueId = valueId;
this.deviceId = deviceId; this.deviceId = deviceId;
this.sensorId = sensorId; this.sensorId = sensorId;
this.value = value; this.value = value;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public Integer getValueId() { public Integer getValueId() {
return valueId; return valueId;
} }
public void setValueId(Integer valueId) { public void setValueId(Integer valueId) {
this.valueId = valueId; this.valueId = valueId;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public void setDeviceId(String deviceId) { public void setDeviceId(String deviceId) {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public Integer getSensorId() { public Integer getSensorId() {
return sensorId; return sensorId;
} }
public void setSensorId(Integer sensorId) { public void setSensorId(Integer sensorId) {
this.sensorId = sensorId; this.sensorId = sensorId;
} }
public Float getValue() { public Float getValue() {
return value; return value;
} }
public void setValue(Float value) { public void setValue(Float value) {
this.value = value; this.value = value;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
public void setTimestamp(Long timestamp) { public void setTimestamp(Long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(deviceId, sensorId, timestamp, value, valueId); return Objects.hash(deviceId, sensorId, timestamp, value, valueId);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
COValue other = (COValue) obj; COValue other = (COValue) obj;
return Objects.equals(deviceId, other.deviceId) && Objects.equals(sensorId, other.sensorId) return Objects.equals(deviceId, other.deviceId) && Objects.equals(sensorId, other.sensorId)
&& Objects.equals(timestamp, other.timestamp) && Objects.equals(value, other.value) && Objects.equals(timestamp, other.timestamp) && Objects.equals(value, other.value)
&& Objects.equals(valueId, other.valueId); && Objects.equals(valueId, other.valueId);
} }
@Override @Override
public String toString() { public String toString() {
return "COValue [valueId=" + valueId + ", deviceId=" + deviceId + ", sensorId=" + sensorId + ", value=" + value return "COValue [valueId=" + valueId + ", deviceId=" + deviceId + ", sensorId=" + sensorId + ", value=" + value
+ ", timestamp=" + timestamp + "]"; + ", timestamp=" + timestamp + "]";
} }
public static COValue fromPayload(DevicePayload payload) { public static COValue fromPayload(DevicePayload payload) {
return new COValue(null, payload.getDeviceId(), payload.getSensorId(), payload.getCarbonMonoxide(), payload.getTimestamp()); return new COValue(null, payload.getDeviceId(), payload.getSensorId(), payload.getCarbonMonoxide(), payload.getTimestamp());
} }
} }

View File

@@ -1,57 +1,57 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
@Table("devices") @Table("devices")
public class Device { public class Device {
private String deviceId; private String deviceId;
private Integer groupId; private Integer groupId;
private String deviceName; private String deviceName;
public Device() {} public Device() {}
public Device(Row row) { public Device(Row row) {
this.deviceId = row.getString("deviceId"); this.deviceId = row.getString("deviceId");
this.groupId = row.getInteger("groupId"); this.groupId = row.getInteger("groupId");
this.deviceName = row.getString("deviceName"); this.deviceName = row.getString("deviceName");
} }
public Device(String deviceId, Integer groupId, String deviceName) { public Device(String deviceId, Integer groupId, String deviceName) {
super(); super();
this.deviceId = deviceId; this.deviceId = deviceId;
this.groupId = groupId; this.groupId = groupId;
this.deviceName = deviceName; this.deviceName = deviceName;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public void setDeviceId(String deviceId) { public void setDeviceId(String deviceId) {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public Integer getGroupId() { public Integer getGroupId() {
return groupId; return groupId;
} }
public void setGroupId(Integer groupId) { public void setGroupId(Integer groupId) {
this.groupId = groupId; this.groupId = groupId;
} }
public String getDeviceName() { public String getDeviceName() {
return deviceName; return deviceName;
} }
public void setDeviceName(String deviceName) { public void setDeviceName(String deviceName) {
this.deviceName = deviceName; this.deviceName = deviceName;
} }
} }

View File

@@ -1,130 +1,130 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
public class DevicePayload { public class DevicePayload {
private String deviceId; private String deviceId;
private Integer sensorId; private Integer sensorId;
private Float temperature; private Float temperature;
private Float humidity; private Float humidity;
private Float pressure; private Float pressure;
private Float carbonMonoxide; private Float carbonMonoxide;
private Float lat; private Float lat;
private Float lon; private Float lon;
private Long timestamp; private Long timestamp;
public DevicePayload() {} public DevicePayload() {}
public DevicePayload(String deviceId, Integer sensorId, String sensorType, String unit, Integer sensorStatus, public DevicePayload(String deviceId, Integer sensorId, String sensorType, String unit, Integer sensorStatus,
Float temperature, Float humidity, Float pressure, Float carbonMonoxide, Float lat, Float lon, Long timestamp) { Float temperature, Float humidity, Float pressure, Float carbonMonoxide, Float lat, Float lon, Long timestamp) {
super(); super();
this.deviceId = deviceId; this.deviceId = deviceId;
this.sensorId = sensorId; this.sensorId = sensorId;
this.temperature = temperature; this.temperature = temperature;
this.humidity = humidity; this.humidity = humidity;
this.pressure = pressure; this.pressure = pressure;
this.carbonMonoxide = carbonMonoxide; this.carbonMonoxide = carbonMonoxide;
this.lat = lat; this.lat = lat;
this.lon = lon; this.lon = lon;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public void setDeviceId(String deviceId) { public void setDeviceId(String deviceId) {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public Integer getSensorId() { public Integer getSensorId() {
return sensorId; return sensorId;
} }
public void setSensorId(Integer sensorId) { public void setSensorId(Integer sensorId) {
this.sensorId = sensorId; this.sensorId = sensorId;
} }
public Float getTemperature() { public Float getTemperature() {
return temperature; return temperature;
} }
public void setTemperature(Float temperature) { public void setTemperature(Float temperature) {
this.temperature = temperature; this.temperature = temperature;
} }
public Float getHumidity() { public Float getHumidity() {
return humidity; return humidity;
} }
public void setHumidity(Float humidity) { public void setHumidity(Float humidity) {
this.humidity = humidity; this.humidity = humidity;
} }
public Float getPressure() { public Float getPressure() {
return pressure; return pressure;
} }
public Float getCarbonMonoxide() { public Float getCarbonMonoxide() {
return carbonMonoxide; return carbonMonoxide;
} }
public void setCarbonMonoxide(Float carbonMonoxide) { public void setCarbonMonoxide(Float carbonMonoxide) {
this.carbonMonoxide = carbonMonoxide; this.carbonMonoxide = carbonMonoxide;
} }
public Float getLat() { public Float getLat() {
return lat; return lat;
} }
public void setLat(Float lat) { public void setLat(Float lat) {
this.lat = lat; this.lat = lat;
} }
public Float getLon() { public Float getLon() {
return lon; return lon;
} }
public void setLon(Float lon) { public void setLon(Float lon) {
this.lon = lon; this.lon = lon;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
public void setTimestamp(Long timestamp) { public void setTimestamp(Long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(carbonMonoxide, deviceId, humidity, lat, lon, pressure, sensorId, temperature, timestamp); return Objects.hash(carbonMonoxide, deviceId, humidity, lat, lon, pressure, sensorId, temperature, timestamp);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
DevicePayload other = (DevicePayload) obj; DevicePayload other = (DevicePayload) obj;
return Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId) return Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId)
&& Objects.equals(humidity, other.humidity) && Objects.equals(lat, other.lat) && Objects.equals(humidity, other.humidity) && Objects.equals(lat, other.lat)
&& Objects.equals(lon, other.lon) && Objects.equals(pressure, other.pressure) && Objects.equals(lon, other.lon) && Objects.equals(pressure, other.pressure)
&& Objects.equals(sensorId, other.sensorId) && Objects.equals(temperature, other.temperature) && Objects.equals(sensorId, other.sensorId) && Objects.equals(temperature, other.temperature)
&& Objects.equals(timestamp, other.timestamp); && Objects.equals(timestamp, other.timestamp);
} }
@Override @Override
public String toString() { public String toString() {
return "DevicePayload [deviceId=" + deviceId + ", sensorId=" + sensorId + ", temperature=" + temperature return "DevicePayload [deviceId=" + deviceId + ", sensorId=" + sensorId + ", temperature=" + temperature
+ ", humidity=" + humidity + ", pressure=" + pressure + ", carbonMonoxide=" + carbonMonoxide + ", lat=" + ", humidity=" + humidity + ", pressure=" + pressure + ", carbonMonoxide=" + carbonMonoxide + ", lat="
+ lat + ", lon=" + lon + ", timestamp=" + timestamp + "]"; + lat + ", lon=" + lon + ", timestamp=" + timestamp + "]";
} }
} }

View File

@@ -1,118 +1,118 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("gps_values") @Table("gps_values")
public class GpsValue { public class GpsValue {
private Integer valueId; private Integer valueId;
private String deviceId; private String deviceId;
private Integer sensorId; private Integer sensorId;
private Float lat; private Float lat;
private Float lon; private Float lon;
private Long timestamp; private Long timestamp;
public GpsValue() {} public GpsValue() {}
public GpsValue(Row row) { public GpsValue(Row row) {
this.valueId = row.getInteger("valueId"); this.valueId = row.getInteger("valueId");
this.deviceId = row.getString("deviceId"); this.deviceId = row.getString("deviceId");
this.sensorId = row.getInteger("sensorId"); this.sensorId = row.getInteger("sensorId");
this.lat = row.getFloat("lat"); this.lat = row.getFloat("lat");
this.lon = row.getFloat("lon"); this.lon = row.getFloat("lon");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp")); this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
} }
public GpsValue(Integer valueId, String deviceId, Integer sensorId, Float lat, Float lon, Long timestamp) { public GpsValue(Integer valueId, String deviceId, Integer sensorId, Float lat, Float lon, Long timestamp) {
super(); super();
this.valueId = valueId; this.valueId = valueId;
this.deviceId = deviceId; this.deviceId = deviceId;
this.sensorId = sensorId; this.sensorId = sensorId;
this.lat = lat; this.lat = lat;
this.lon = lon; this.lon = lon;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public Integer getValueId() { public Integer getValueId() {
return valueId; return valueId;
} }
public void setValueId(Integer valueId) { public void setValueId(Integer valueId) {
this.valueId = valueId; this.valueId = valueId;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public void setDeviceId(String deviceId) { public void setDeviceId(String deviceId) {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public Integer getSensorId() { public Integer getSensorId() {
return sensorId; return sensorId;
} }
public void setSensorId(Integer sensorId) { public void setSensorId(Integer sensorId) {
this.sensorId = sensorId; this.sensorId = sensorId;
} }
public Float getLat() { public Float getLat() {
return lat; return lat;
} }
public void setLat(Float lat) { public void setLat(Float lat) {
this.lat = lat; this.lat = lat;
} }
public Float getLon() { public Float getLon() {
return lon; return lon;
} }
public void setLon(Float lon) { public void setLon(Float lon) {
this.lon = lon; this.lon = lon;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
public void setTimestamp(Long timestamp) { public void setTimestamp(Long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(deviceId, lat, lon, sensorId, timestamp, valueId); return Objects.hash(deviceId, lat, lon, sensorId, timestamp, valueId);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
GpsValue other = (GpsValue) obj; GpsValue other = (GpsValue) obj;
return Objects.equals(deviceId, other.deviceId) && Objects.equals(lat, other.lat) return Objects.equals(deviceId, other.deviceId) && Objects.equals(lat, other.lat)
&& Objects.equals(lon, other.lon) && Objects.equals(sensorId, other.sensorId) && Objects.equals(lon, other.lon) && Objects.equals(sensorId, other.sensorId)
&& Objects.equals(timestamp, other.timestamp) && Objects.equals(valueId, other.valueId); && Objects.equals(timestamp, other.timestamp) && Objects.equals(valueId, other.valueId);
} }
@Override @Override
public String toString() { public String toString() {
return "GpsValue [valueId=" + valueId + ", deviceId=" + deviceId + ", sensorId=" + sensorId + ", lat=" + lat return "GpsValue [valueId=" + valueId + ", deviceId=" + deviceId + ", sensorId=" + sensorId + ", lat=" + lat
+ ", lon=" + lon + ", timestamp=" + timestamp + "]"; + ", lon=" + lon + ", timestamp=" + timestamp + "]";
} }
public static GpsValue fromPayload(DevicePayload payload) { public static GpsValue fromPayload(DevicePayload payload) {
return new GpsValue(null, payload.getDeviceId(), payload.getSensorId(), payload.getLat(), payload.getLon(), return new GpsValue(null, payload.getDeviceId(), payload.getSensorId(), payload.getLat(), payload.getLon(),
payload.getTimestamp()); payload.getTimestamp());
} }
} }

View File

@@ -1,66 +1,66 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
@Table("groups") @Table("groups")
public class Group { public class Group {
private Integer groupId; private Integer groupId;
private String groupName; private String groupName;
public Group() {} public Group() {}
public Group(Row row) { public Group(Row row) {
this.groupId = row.getInteger("groupId"); this.groupId = row.getInteger("groupId");
this.groupName = row.getString("groupName"); this.groupName = row.getString("groupName");
} }
public Group(Integer groupId, String groupName) { public Group(Integer groupId, String groupName) {
super(); super();
this.groupId = groupId; this.groupId = groupId;
this.groupName = groupName; this.groupName = groupName;
} }
public Integer getGroupId() { public Integer getGroupId() {
return groupId; return groupId;
} }
public void setGroupId(Integer groupId) { public void setGroupId(Integer groupId) {
this.groupId = groupId; this.groupId = groupId;
} }
public String getGroupName() { public String getGroupName() {
return groupName; return groupName;
} }
public void setGroupName(String groupName) { public void setGroupName(String groupName) {
this.groupName = groupName; this.groupName = groupName;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(groupId, groupName); return Objects.hash(groupId, groupName);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
Group other = (Group) obj; Group other = (Group) obj;
return Objects.equals(groupId, other.groupId) && Objects.equals(groupName, other.groupName); return Objects.equals(groupId, other.groupId) && Objects.equals(groupName, other.groupName);
} }
@Override @Override
public String toString() { public String toString() {
return "Group [groupId=" + groupId + ", groupName=" + groupName + "]"; return "Group [groupId=" + groupId + ", groupName=" + groupName + "]";
} }
} }

View File

@@ -1,114 +1,114 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("sensors") @Table("sensors")
public class Sensor { public class Sensor {
private Integer sensorId; private Integer sensorId;
private String deviceId; private String deviceId;
private String sensorType; private String sensorType;
private String unit; private String unit;
private Integer status; private Integer status;
private Long timestamp; private Long timestamp;
public Sensor() {} public Sensor() {}
public Sensor(Row row) { public Sensor(Row row) {
this.sensorId = row.getInteger("sensorId"); this.sensorId = row.getInteger("sensorId");
this.deviceId = row.getString("deviceId"); this.deviceId = row.getString("deviceId");
this.sensorType = row.getString("sensorType"); this.sensorType = row.getString("sensorType");
this.unit = row.getString("unit"); this.unit = row.getString("unit");
this.status = row.getInteger("status"); this.status = row.getInteger("status");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp")); this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
} }
public Sensor(Integer sensorId, String deviceId, String sensorType, String unit, Integer status, Long timestamp) { public Sensor(Integer sensorId, String deviceId, String sensorType, String unit, Integer status, Long timestamp) {
super(); super();
this.sensorId = sensorId; this.sensorId = sensorId;
this.deviceId = deviceId; this.deviceId = deviceId;
this.sensorType = sensorType; this.sensorType = sensorType;
this.unit = unit; this.unit = unit;
this.status = status; this.status = status;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public Integer getSensorId() { public Integer getSensorId() {
return sensorId; return sensorId;
} }
public void setSensorId(Integer sensorId) { public void setSensorId(Integer sensorId) {
this.sensorId = sensorId; this.sensorId = sensorId;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public void setDeviceId(String deviceId) { public void setDeviceId(String deviceId) {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public String getSensorType() { public String getSensorType() {
return sensorType; return sensorType;
} }
public void setSensorType(String sensorType) { public void setSensorType(String sensorType) {
this.sensorType = sensorType; this.sensorType = sensorType;
} }
public String getUnit() { public String getUnit() {
return unit; return unit;
} }
public void setUnit(String unit) { public void setUnit(String unit) {
this.unit = unit; this.unit = unit;
} }
public Integer getStatus() { public Integer getStatus() {
return status; return status;
} }
public void setStatus(Integer status) { public void setStatus(Integer status) {
this.status = status; this.status = status;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
public void setTimestamp(Long timestamp) { public void setTimestamp(Long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(deviceId, sensorId, sensorType, status, timestamp, unit); return Objects.hash(deviceId, sensorId, sensorType, status, timestamp, unit);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
Sensor other = (Sensor) obj; Sensor other = (Sensor) obj;
return Objects.equals(deviceId, other.deviceId) && Objects.equals(sensorId, other.sensorId) return Objects.equals(deviceId, other.deviceId) && Objects.equals(sensorId, other.sensorId)
&& Objects.equals(sensorType, other.sensorType) && Objects.equals(status, other.status) && Objects.equals(sensorType, other.sensorType) && Objects.equals(status, other.status)
&& Objects.equals(timestamp, other.timestamp) && Objects.equals(unit, other.unit); && Objects.equals(timestamp, other.timestamp) && Objects.equals(unit, other.unit);
} }
@Override @Override
public String toString() { public String toString() {
return "Sensor [sensorId=" + sensorId + ", deviceId=" + deviceId + ", sensorType=" + sensorType + ", unit=" return "Sensor [sensorId=" + sensorId + ", deviceId=" + deviceId + ", sensorType=" + sensorType + ", unit="
+ unit + ", status=" + status + ", timestamp=" + timestamp + "]"; + unit + ", status=" + status + ", timestamp=" + timestamp + "]";
} }
} }

View File

@@ -1,142 +1,201 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("v_latest_values") @Table("v_latest_values")
public class DeviceLatestValuesView { public class ViewLatestValues {
private String deviceId;
private Integer sensorId; private String deviceId;
private String sensorType; private Integer sensorId;
private String unit; private String sensorType;
private Integer sensorStatus; private String unit;
private Long sensorTimestamp; private Integer sensorStatus;
private Float temperature; private Long sensorTimestamp;
private Float humidity; private Float temperature;
private Float carbonMonoxide; private Float humidity;
private Float lat; private Float pressure;
private Float lon; private Float carbonMonoxide;
private Long airValuesTimestamp; private Float lat;
private Float lon;
public DeviceLatestValuesView() {} private Long airValuesTimestamp;
public DeviceLatestValuesView(Row row) { public ViewLatestValues() {}
this.deviceId = row.getString("deviceId");
this.sensorId = row.getInteger("sensorId"); public ViewLatestValues(Row row) {
this.sensorType = row.getString("sensorType"); this.deviceId = row.getString("deviceId");
this.unit = row.getString("unit"); this.sensorId = row.getInteger("sensorId");
this.sensorStatus = row.getInteger("sensorStatus"); this.sensorType = row.getString("sensorType");
this.sensorTimestamp = DateParser.parseDate(row.getLocalDateTime("sensorTimestamp")); this.unit = row.getString("unit");
this.temperature = row.getFloat("temperature"); this.sensorStatus = row.getInteger("sensorStatus");
this.humidity = row.getFloat("humidity"); this.sensorTimestamp = DateParser.parseDate(row.getLocalDateTime("sensorTimestamp"));
this.carbonMonoxide = row.getFloat("carbonMonoxide"); this.temperature = row.getFloat("temperature");
this.lat = row.getFloat("lat"); this.humidity = row.getFloat("humidity");
this.lon = row.getFloat("lon"); this.pressure = row.getFloat("pressure");
this.airValuesTimestamp = DateParser.parseDate(row.getLocalDateTime("airValuesTimestamp")); this.carbonMonoxide = row.getFloat("carbonMonoxide");
} this.lat = row.getFloat("lat");
this.lon = row.getFloat("lon");
public DeviceLatestValuesView(String deviceId, Integer sensorId, String sensorType, String unit, Integer sensorStatus, this.airValuesTimestamp = DateParser.parseDate(row.getLocalDateTime("airValuesTimestamp"));
Long sensorTimestamp, Float temperature, Float humidity, Float carbonMonoxide, Float lat, Float lon, }
Long airValuesTimestamp) {
super(); public ViewLatestValues(String deviceId, Integer sensorId, String sensorType, String unit, Integer sensorStatus,
this.deviceId = deviceId; Long sensorTimestamp, Float temperature, Float humidity, Float pressure, Float carbonMonoxide, Float lat, Float lon,
this.sensorId = sensorId; Long airValuesTimestamp) {
this.sensorType = sensorType; super();
this.unit = unit; this.deviceId = deviceId;
this.sensorStatus = sensorStatus; this.sensorId = sensorId;
this.sensorTimestamp = sensorTimestamp; this.sensorType = sensorType;
this.temperature = temperature; this.unit = unit;
this.humidity = humidity; this.sensorStatus = sensorStatus;
this.carbonMonoxide = carbonMonoxide; this.sensorTimestamp = sensorTimestamp;
this.lat = lat; this.temperature = temperature;
this.lon = lon; this.humidity = humidity;
this.airValuesTimestamp = airValuesTimestamp; this.carbonMonoxide = carbonMonoxide;
} this.lat = lat;
this.lon = lon;
public String getDeviceId() { this.airValuesTimestamp = airValuesTimestamp;
return deviceId; }
}
public String getDeviceId() {
public Integer getSensorId() { return deviceId;
return sensorId; }
}
public Integer getSensorId() {
public String getSensorType() { return sensorId;
return sensorType; }
}
public String getSensorType() {
public String getUnit() { return sensorType;
return unit; }
}
public String getUnit() {
public Integer getSensorStatus() { return unit;
return sensorStatus; }
}
public Integer getSensorStatus() {
public Long getSensorTimestamp() { return sensorStatus;
return sensorTimestamp; }
}
public Long getSensorTimestamp() {
public Float getTemperature() { return sensorTimestamp;
return temperature; }
}
public Float getTemperature() {
public Float getHumidity() { return temperature;
return humidity; }
}
public Float getHumidity() {
public Float getCarbonMonoxide() { return humidity;
return carbonMonoxide; }
}
public Float getPressure() {
public Float getLat() { return pressure;
return lat; }
}
public Float getCarbonMonoxide() {
public Float getLon() { return carbonMonoxide;
return lon; }
}
public Float getLat() {
public Long getAirValuesTimestamp() { return lat;
return airValuesTimestamp; }
}
public Float getLon() {
@Override return lon;
public int hashCode() { }
return Objects.hash(airValuesTimestamp, carbonMonoxide, deviceId, humidity, lat, lon, sensorId, sensorStatus,
sensorTimestamp, sensorType, temperature, unit); public Long getAirValuesTimestamp() {
} return airValuesTimestamp;
}
@Override
public boolean equals(Object obj) { public void setDeviceId(String deviceId) {
if (this == obj) this.deviceId = deviceId;
return true; }
if (obj == null)
return false; public void setSensorId(Integer sensorId) {
if (getClass() != obj.getClass()) this.sensorId = sensorId;
return false; }
DeviceLatestValuesView other = (DeviceLatestValuesView) obj;
return Objects.equals(airValuesTimestamp, other.airValuesTimestamp) public void setSensorType(String sensorType) {
&& Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId) this.sensorType = sensorType;
&& Objects.equals(humidity, other.humidity) && Objects.equals(lat, other.lat) }
&& Objects.equals(lon, other.lon) && Objects.equals(sensorId, other.sensorId)
&& Objects.equals(sensorStatus, other.sensorStatus) public void setUnit(String unit) {
&& Objects.equals(sensorTimestamp, other.sensorTimestamp) this.unit = unit;
&& Objects.equals(sensorType, other.sensorType) && Objects.equals(temperature, other.temperature) }
&& Objects.equals(unit, other.unit);
} public void setSensorStatus(Integer sensorStatus) {
this.sensorStatus = sensorStatus;
@Override }
public String toString() {
return "DeviceLatestValuesView [deviceId=" + deviceId + ", sensorId=" + sensorId + ", sensorType=" + sensorType public void setSensorTimestamp(Long sensorTimestamp) {
+ ", unit=" + unit + ", sensorStatus=" + sensorStatus + ", sensorTimestamp=" + sensorTimestamp this.sensorTimestamp = sensorTimestamp;
+ ", temperature=" + temperature + ", humidity=" + humidity + ", carbonMonoxide=" + carbonMonoxide }
+ ", lat=" + lat + ", lon=" + lon + ", airValuesTimestamp=" + airValuesTimestamp + "]";
} public void setTemperature(Float temperature) {
this.temperature = temperature;
}
public void setHumidity(Float humidity) {
} this.humidity = humidity;
}
public void setPressure(Float pressure) {
this.pressure = pressure;
}
public void setCarbonMonoxide(Float carbonMonoxide) {
this.carbonMonoxide = carbonMonoxide;
}
public void setLat(Float lat) {
this.lat = lat;
}
public void setLon(Float lon) {
this.lon = lon;
}
public void setAirValuesTimestamp(Long airValuesTimestamp) {
this.airValuesTimestamp = airValuesTimestamp;
}
@Override
public int hashCode() {
return Objects.hash(airValuesTimestamp, carbonMonoxide, deviceId, humidity, lat, lon, pressure, sensorId,
sensorStatus, sensorTimestamp, sensorType, temperature, unit);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ViewLatestValues other = (ViewLatestValues) obj;
return Objects.equals(airValuesTimestamp, other.airValuesTimestamp)
&& Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId)
&& Objects.equals(humidity, other.humidity) && Objects.equals(lat, other.lat)
&& Objects.equals(lon, other.lon) && Objects.equals(pressure, other.pressure)
&& Objects.equals(sensorId, other.sensorId) && Objects.equals(sensorStatus, other.sensorStatus)
&& Objects.equals(sensorTimestamp, other.sensorTimestamp)
&& Objects.equals(sensorType, other.sensorType) && Objects.equals(temperature, other.temperature)
&& Objects.equals(unit, other.unit);
}
@Override
public String toString() {
return "ViewLatestValues [deviceId=" + deviceId + ", sensorId=" + sensorId + ", sensorType=" + sensorType
+ ", unit=" + unit + ", sensorStatus=" + sensorStatus + ", sensorTimestamp=" + sensorTimestamp
+ ", temperature=" + temperature + ", humidity=" + humidity + ", pressure=" + pressure
+ ", carbonMonoxide=" + carbonMonoxide + ", lat=" + lat + ", lon=" + lon + ", airValuesTimestamp="
+ airValuesTimestamp + "]";
}
}

View File

@@ -1,90 +1,116 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("v_pollution_map") @Table("v_pollution_map")
public class DevicePollutionMap { public class ViewPollutionMap {
private String deviceId; private String deviceId;
private String deviceName; private String deviceName;
private Float lat; private Float lat;
private Float lon; private Float lon;
private Float carbonMonoxide; private Float carbonMonoxide;
private Long timestamp; private Long timestamp;
public DevicePollutionMap() {} public ViewPollutionMap() {}
public DevicePollutionMap(Row row) { public ViewPollutionMap(Row row) {
this.deviceId = row.getString("deviceId"); this.deviceId = row.getString("deviceId");
this.deviceName = row.getString("deviceName"); this.deviceName = row.getString("deviceName");
this.lat = row.getFloat("lat"); this.lat = row.getFloat("lat");
this.lon = row.getFloat("lon"); this.lon = row.getFloat("lon");
this.carbonMonoxide = row.getFloat("carbonMonoxide"); this.carbonMonoxide = row.getFloat("carbonMonoxide");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp")); this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
} }
public DevicePollutionMap(String deviceId, String deviceName, Float lat, Float lon, Float carbonMonoxide, public ViewPollutionMap(String deviceId, String deviceName, Float lat, Float lon, Float carbonMonoxide,
Long timestamp) { Long timestamp) {
super(); super();
this.deviceId = deviceId; this.deviceId = deviceId;
this.deviceName = deviceName; this.deviceName = deviceName;
this.lat = lat; this.lat = lat;
this.lon = lon; this.lon = lon;
this.carbonMonoxide = carbonMonoxide; this.carbonMonoxide = carbonMonoxide;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public String getDeviceName() { public String getDeviceName() {
return deviceName; return deviceName;
} }
public Float getLat() { public Float getLat() {
return lat; return lat;
} }
public Float getLon() { public Float getLon() {
return lon; return lon;
} }
public Float getCarbonMonoxide() { public Float getCarbonMonoxide() {
return carbonMonoxide; return carbonMonoxide;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
@Override
public int hashCode() {
return Objects.hash(carbonMonoxide, deviceId, deviceName, lat, lon, timestamp); public void setDeviceId(String deviceId) {
} this.deviceId = deviceId;
}
@Override
public boolean equals(Object obj) { public void setDeviceName(String deviceName) {
if (this == obj) this.deviceName = deviceName;
return true; }
if (obj == null)
return false; public void setLat(Float lat) {
if (getClass() != obj.getClass()) this.lat = lat;
return false; }
DevicePollutionMap other = (DevicePollutionMap) obj;
return Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId) public void setLon(Float lon) {
&& Objects.equals(deviceName, other.deviceName) && Objects.equals(lat, other.lat) this.lon = lon;
&& Objects.equals(lon, other.lon) && Objects.equals(timestamp, other.timestamp); }
}
public void setCarbonMonoxide(Float carbonMonoxide) {
@Override this.carbonMonoxide = carbonMonoxide;
public String toString() { }
return "DevicePollutionMap [deviceId=" + deviceId + ", deviceName=" + deviceName + ", lat=" + lat + ", lon="
+ lon + ", carbonMonoxide=" + carbonMonoxide + ", timestamp=" + timestamp + "]"; public void setTimestamp(Long timestamp) {
} this.timestamp = timestamp;
}
@Override
public int hashCode() {
return Objects.hash(carbonMonoxide, deviceId, deviceName, lat, lon, timestamp);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ViewPollutionMap other = (ViewPollutionMap) obj;
return Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId)
&& Objects.equals(deviceName, other.deviceName) && Objects.equals(lat, other.lat)
&& Objects.equals(lon, other.lon) && Objects.equals(timestamp, other.timestamp);
}
@Override
public String toString() {
return "DevicePollutionMap [deviceId=" + deviceId + ", deviceName=" + deviceName + ", lat=" + lat + ", lon="
+ lon + ", carbonMonoxide=" + carbonMonoxide + ", timestamp=" + timestamp + "]";
}
} }

View File

@@ -1,82 +1,104 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("v_sensor_history_by_device") @Table("v_sensor_history_by_device")
public class DeviceSensorHistory { public class ViewSensorHistory {
private String deviceId; private String deviceId;
private String deviceName; private String deviceName;
private Float value; private Float value;
private String valueType; private String valueType;
private Long timestamp; private Long timestamp;
public DeviceSensorHistory() {} public ViewSensorHistory() {}
public DeviceSensorHistory(Row row) { public ViewSensorHistory(Row row) {
this.deviceId = row.getString("deviceId"); this.deviceId = row.getString("deviceId");
this.deviceName = row.getString("deviceName"); this.deviceName = row.getString("deviceName");
this.value = row.getFloat("value"); this.value = row.getFloat("value");
this.valueType = row.getString("valueType"); this.valueType = row.getString("valueType");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp")); this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
} }
public DeviceSensorHistory(String deviceId, String deviceName, Float value, String valueType, Long timestamp) { public ViewSensorHistory(String deviceId, String deviceName, Float value, String valueType, Long timestamp) {
super(); super();
this.deviceId = deviceId; this.deviceId = deviceId;
this.deviceName = deviceName; this.deviceName = deviceName;
this.value = value; this.value = value;
this.valueType = valueType; this.valueType = valueType;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public String getDeviceName() { public String getDeviceName() {
return deviceName; return deviceName;
} }
public Float getValue() { public Float getValue() {
return value; return value;
} }
public String getValueType() { public String getValueType() {
return valueType; return valueType;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
@Override
public int hashCode() {
return Objects.hash(deviceId, deviceName, timestamp, value, valueType); public void setDeviceId(String deviceId) {
} this.deviceId = deviceId;
}
@Override
public boolean equals(Object obj) { public void setDeviceName(String deviceName) {
if (this == obj) this.deviceName = deviceName;
return true; }
if (obj == null)
return false; public void setValue(Float value) {
if (getClass() != obj.getClass()) this.value = value;
return false; }
DeviceSensorHistory other = (DeviceSensorHistory) obj;
return Objects.equals(deviceId, other.deviceId) && Objects.equals(deviceName, other.deviceName) public void setValueType(String valueType) {
&& Objects.equals(timestamp, other.timestamp) && Objects.equals(value, other.value) this.valueType = valueType;
&& Objects.equals(valueType, other.valueType); }
}
public void setTimestamp(Long timestamp) {
@Override this.timestamp = timestamp;
public String toString() { }
return "DeviceSensorHistory [deviceId=" + deviceId + ", deviceName=" + deviceName + ", value=" + value
+ ", valueType=" + valueType + ", timestamp=" + timestamp + "]"; @Override
} public int hashCode() {
return Objects.hash(deviceId, deviceName, timestamp, value, valueType);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ViewSensorHistory other = (ViewSensorHistory) obj;
return Objects.equals(deviceId, other.deviceId) && Objects.equals(deviceName, other.deviceName)
&& Objects.equals(timestamp, other.timestamp) && Objects.equals(value, other.value)
&& Objects.equals(valueType, other.valueType);
}
@Override
public String toString() {
return "DeviceSensorHistory [deviceId=" + deviceId + ", deviceName=" + deviceName + ", value=" + value
+ ", valueType=" + valueType + ", timestamp=" + timestamp + "]";
}
}

View File

@@ -1,131 +1,189 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("v_sensor_values") @Table("v_sensor_values")
public class DeviceSensorValue { public class ViewSensorValue {
private Integer sensorId; private Integer sensorId;
private String deviceId; private String deviceId;
private String sensorType; private String sensorType;
private String unit; private String unit;
private Integer sensorStatus; private Integer sensorStatus;
private Float temperature; private Float temperature;
private Float humidity; private Float humidity;
private Float carbonMonoxide; private Float pressure;
private Float lat; private Float carbonMonoxide;
private Float lon; private Float lat;
private Long timestamp; private Float lon;
private Long timestamp;
public DeviceSensorValue() {}
public ViewSensorValue() {}
public DeviceSensorValue(Row row) {
this.sensorId = row.getInteger("sensorId"); public ViewSensorValue(Row row) {
this.deviceId = row.getString("deviceId"); this.sensorId = row.getInteger("sensorId");
this.sensorType = row.getString("sensorType"); this.deviceId = row.getString("deviceId");
this.unit = row.getString("unit"); this.sensorType = row.getString("sensorType");
this.sensorStatus = row.getInteger("sensorStatus"); this.unit = row.getString("unit");
this.temperature = row.getFloat("temperature"); this.sensorStatus = row.getInteger("sensorStatus");
this.humidity = row.getFloat("humidity"); this.temperature = row.getFloat("temperature");
this.carbonMonoxide = row.getFloat("carbonMonoxide"); this.humidity = row.getFloat("humidity");
this.lat = row.getFloat("lat"); this.pressure = row.getFloat("pressure");
this.lon = row.getFloat("lon"); this.carbonMonoxide = row.getFloat("carbonMonoxide");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp")); this.lat = row.getFloat("lat");
} this.lon = row.getFloat("lon");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
public DeviceSensorValue(Integer sensorId, String deviceId, String sensorType, String unit, Integer sensorStatus, }
Float temperature, Float humidity, Float carbonMonoxide, Float lat, Float lon, Long timestamp) {
super(); public ViewSensorValue(Integer sensorId, String deviceId, String sensorType, String unit, Integer sensorStatus,
this.sensorId = sensorId; Float temperature, Float humidity, Float pressure, Float carbonMonoxide, Float lat, Float lon, Long timestamp) {
this.deviceId = deviceId; super();
this.sensorType = sensorType; this.sensorId = sensorId;
this.unit = unit; this.deviceId = deviceId;
this.sensorStatus = sensorStatus; this.sensorType = sensorType;
this.temperature = temperature; this.unit = unit;
this.humidity = humidity; this.sensorStatus = sensorStatus;
this.carbonMonoxide = carbonMonoxide; this.temperature = temperature;
this.lat = lat; this.humidity = humidity;
this.lon = lon; this.pressure = pressure;
this.timestamp = timestamp; this.carbonMonoxide = carbonMonoxide;
} this.lat = lat;
this.lon = lon;
public Integer getSensorId() { this.timestamp = timestamp;
return sensorId; }
}
public Integer getSensorId() {
public String getDeviceId() { return sensorId;
return deviceId; }
}
public String getDeviceId() {
public String getSensorType() { return deviceId;
return sensorType; }
}
public String getSensorType() {
public String getUnit() { return sensorType;
return unit; }
}
public String getUnit() {
public Integer getSensorStatus() { return unit;
return sensorStatus; }
}
public Integer getSensorStatus() {
public Float getTemperature() { return sensorStatus;
return temperature; }
}
public Float getTemperature() {
public Float getHumidity() { return temperature;
return humidity; }
}
public Float getHumidity() {
public Float getCarbonMonoxide() { return humidity;
return carbonMonoxide; }
}
public Float getPressure() {
public Float getLat() { return pressure;
return lat; }
}
public Float getCarbonMonoxide() {
public Float getLon() { return carbonMonoxide;
return lon; }
}
public Float getLat() {
public Long getTimestamp() { return lat;
return timestamp; }
}
public Float getLon() {
@Override return lon;
public int hashCode() { }
return Objects.hash(carbonMonoxide, deviceId, humidity, lat, lon, sensorId, sensorStatus, sensorType,
temperature, timestamp, unit); public Long getTimestamp() {
} return timestamp;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true; public void setSensorId(Integer sensorId) {
if (obj == null) this.sensorId = sensorId;
return false; }
if (getClass() != obj.getClass())
return false; public void setDeviceId(String deviceId) {
DeviceSensorValue other = (DeviceSensorValue) obj; this.deviceId = deviceId;
return Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId) }
&& Objects.equals(humidity, other.humidity) && Objects.equals(lat, other.lat)
&& Objects.equals(lon, other.lon) && Objects.equals(sensorId, other.sensorId) public void setSensorType(String sensorType) {
&& Objects.equals(sensorStatus, other.sensorStatus) && Objects.equals(sensorType, other.sensorType) this.sensorType = sensorType;
&& Objects.equals(temperature, other.temperature) && Objects.equals(timestamp, other.timestamp) }
&& Objects.equals(unit, other.unit);
} public void setUnit(String unit) {
this.unit = unit;
@Override }
public String toString() {
return "DeviceSensorValue [sensorId=" + sensorId + ", deviceId=" + deviceId + ", sensorType=" + sensorType public void setSensorStatus(Integer sensorStatus) {
+ ", unit=" + unit + ", sensorStatus=" + sensorStatus + ", temperature=" + temperature + ", humidity=" this.sensorStatus = sensorStatus;
+ humidity + ", carbonMonoxide=" + carbonMonoxide + ", lat=" + lat + ", lon=" + lon + ", timestamp=" }
+ timestamp + "]";
} public void setTemperature(Float temperature) {
this.temperature = temperature;
}
}
public void setHumidity(Float humidity) {
this.humidity = humidity;
}
public void setPressure(Float pressure) {
this.pressure = pressure;
}
public void setCarbonMonoxide(Float carbonMonoxide) {
this.carbonMonoxide = carbonMonoxide;
}
public void setLat(Float lat) {
this.lat = lat;
}
public void setLon(Float lon) {
this.lon = lon;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
@Override
public int hashCode() {
return Objects.hash(carbonMonoxide, deviceId, humidity, lat, lon, pressure, sensorId, sensorStatus, sensorType,
temperature, timestamp, unit);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ViewSensorValue other = (ViewSensorValue) obj;
return Objects.equals(carbonMonoxide, other.carbonMonoxide) && Objects.equals(deviceId, other.deviceId)
&& Objects.equals(humidity, other.humidity) && Objects.equals(lat, other.lat)
&& Objects.equals(lon, other.lon) && Objects.equals(pressure, other.pressure)
&& Objects.equals(sensorId, other.sensorId) && Objects.equals(sensorStatus, other.sensorStatus)
&& Objects.equals(sensorType, other.sensorType) && Objects.equals(temperature, other.temperature)
&& Objects.equals(timestamp, other.timestamp) && Objects.equals(unit, other.unit);
}
@Override
public String toString() {
return "ViewSensorValue [sensorId=" + sensorId + ", deviceId=" + deviceId + ", sensorType=" + sensorType
+ ", unit=" + unit + ", sensorStatus=" + sensorStatus + ", temperature=" + temperature + ", humidity="
+ humidity + ", pressure=" + pressure + ", carbonMonoxide=" + carbonMonoxide + ", lat=" + lat + ", lon="
+ lon + ", timestamp=" + timestamp + "]";
}
}

View File

@@ -1,131 +1,131 @@
package net.miarma.contaminus.database.entities; package net.miarma.contaminus.entities;
import java.util.Objects; import java.util.Objects;
import io.vertx.sqlclient.Row; import io.vertx.sqlclient.Row;
import net.miarma.contaminus.common.Table; import net.miarma.contaminus.common.Table;
import net.miarma.contaminus.util.DateParser; import net.miarma.contaminus.util.DateParser;
@Table("weather_values") @Table("weather_values")
public class WeatherValue { public class WeatherValue {
private Integer valueId; private Integer valueId;
private String deviceId; private String deviceId;
private Integer sensorId; private Integer sensorId;
private Float temperature; private Float temperature;
private Float humidity; private Float humidity;
private Float pressure; private Float pressure;
private Long timestamp; private Long timestamp;
public WeatherValue() {} public WeatherValue() {}
public WeatherValue(Row row) { public WeatherValue(Row row) {
this.valueId = row.getInteger("valueId"); this.valueId = row.getInteger("valueId");
this.deviceId = row.getString("deviceId"); this.deviceId = row.getString("deviceId");
this.sensorId = row.getInteger("sensorId"); this.sensorId = row.getInteger("sensorId");
this.temperature = row.getFloat("temperature"); this.temperature = row.getFloat("temperature");
this.humidity = row.getFloat("humidity"); this.humidity = row.getFloat("humidity");
this.pressure = row.getFloat("pressure"); this.pressure = row.getFloat("pressure");
this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp")); this.timestamp = DateParser.parseDate(row.getLocalDateTime("timestamp"));
} }
public WeatherValue(Integer valueId, String deviceId, Integer sensorId, Float temperature, Float humidity, Float pressure, Long timestamp) { public WeatherValue(Integer valueId, String deviceId, Integer sensorId, Float temperature, Float humidity, Float pressure, Long timestamp) {
super(); super();
this.valueId = valueId; this.valueId = valueId;
this.deviceId = deviceId; this.deviceId = deviceId;
this.sensorId = sensorId; this.sensorId = sensorId;
this.temperature = temperature; this.temperature = temperature;
this.humidity = humidity; this.humidity = humidity;
this.pressure = pressure; this.pressure = pressure;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public Integer getValueId() { public Integer getValueId() {
return valueId; return valueId;
} }
public void setValueId(Integer valueId) { public void setValueId(Integer valueId) {
this.valueId = valueId; this.valueId = valueId;
} }
public String getDeviceId() { public String getDeviceId() {
return deviceId; return deviceId;
} }
public void setDeviceId(String deviceId) { public void setDeviceId(String deviceId) {
this.deviceId = deviceId; this.deviceId = deviceId;
} }
public Integer getSensorId() { public Integer getSensorId() {
return sensorId; return sensorId;
} }
public void setSensorId(Integer sensorId) { public void setSensorId(Integer sensorId) {
this.sensorId = sensorId; this.sensorId = sensorId;
} }
public Float getTemperature() { public Float getTemperature() {
return temperature; return temperature;
} }
public void setTemperature(Float temperature) { public void setTemperature(Float temperature) {
this.temperature = temperature; this.temperature = temperature;
} }
public Float getHumidity() { public Float getHumidity() {
return humidity; return humidity;
} }
public void setHumidity(Float humidity) { public void setHumidity(Float humidity) {
this.humidity = humidity; this.humidity = humidity;
} }
public Float getPressure() { public Float getPressure() {
return pressure; return pressure;
} }
public void setPressure(Float pressure) { public void setPressure(Float pressure) {
this.pressure = pressure; this.pressure = pressure;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
public void setTimestamp(Long timestamp) { public void setTimestamp(Long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(deviceId, humidity, pressure, sensorId, temperature, timestamp, valueId); return Objects.hash(deviceId, humidity, pressure, sensorId, temperature, timestamp, valueId);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null) if (obj == null)
return false; return false;
if (getClass() != obj.getClass()) if (getClass() != obj.getClass())
return false; return false;
WeatherValue other = (WeatherValue) obj; WeatherValue other = (WeatherValue) obj;
return Objects.equals(deviceId, other.deviceId) && Objects.equals(humidity, other.humidity) return Objects.equals(deviceId, other.deviceId) && Objects.equals(humidity, other.humidity)
&& Objects.equals(pressure, other.pressure) && Objects.equals(sensorId, other.sensorId) && Objects.equals(pressure, other.pressure) && Objects.equals(sensorId, other.sensorId)
&& Objects.equals(temperature, other.temperature) && Objects.equals(timestamp, other.timestamp) && Objects.equals(temperature, other.temperature) && Objects.equals(timestamp, other.timestamp)
&& Objects.equals(valueId, other.valueId); && Objects.equals(valueId, other.valueId);
} }
@Override @Override
public String toString() { public String toString() {
return "WeatherValue [valueId=" + valueId + ", deviceId=" + deviceId + ", sensorId=" + sensorId return "WeatherValue [valueId=" + valueId + ", deviceId=" + deviceId + ", sensorId=" + sensorId
+ ", temperature=" + temperature + ", humidity=" + humidity + ", pressure=" + pressure + ", timestamp=" + ", temperature=" + temperature + ", humidity=" + humidity + ", pressure=" + pressure + ", timestamp="
+ timestamp + "]"; + timestamp + "]";
} }
public static WeatherValue fromPayload(DevicePayload payload) { public static WeatherValue fromPayload(DevicePayload payload) {
return new WeatherValue(null, payload.getDeviceId(), payload.getSensorId(), payload.getTemperature(), return new WeatherValue(null, payload.getDeviceId(), payload.getSensorId(), payload.getTemperature(),
payload.getHumidity(), payload.getPressure(), payload.getTimestamp()); payload.getHumidity(), payload.getPressure(), payload.getTimestamp());
} }
} }

View File

@@ -1,529 +0,0 @@
package net.miarma.contaminus.server;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;
import io.vertx.jdbcclient.JDBCPool;
import net.miarma.contaminus.common.ConfigManager;
import net.miarma.contaminus.common.Constants;
import net.miarma.contaminus.common.SingleJsonResponse;
import net.miarma.contaminus.database.DatabaseManager;
import net.miarma.contaminus.database.QueryBuilder;
import net.miarma.contaminus.database.entities.Actuator;
import net.miarma.contaminus.database.entities.COValue;
import net.miarma.contaminus.database.entities.Device;
import net.miarma.contaminus.database.entities.DeviceLatestValuesView;
import net.miarma.contaminus.database.entities.DevicePayload;
import net.miarma.contaminus.database.entities.DevicePollutionMap;
import net.miarma.contaminus.database.entities.DeviceSensorHistory;
import net.miarma.contaminus.database.entities.DeviceSensorValue;
import net.miarma.contaminus.database.entities.GpsValue;
import net.miarma.contaminus.database.entities.Group;
import net.miarma.contaminus.database.entities.Sensor;
import net.miarma.contaminus.database.entities.WeatherValue;
/*
* This class is a Verticle that will handle the Data Layer API.
*/
@SuppressWarnings("unused")
public class DataLayerAPIVerticle extends AbstractVerticle {
private JDBCPool pool;
private DatabaseManager dbManager;
private ConfigManager configManager;
private final Gson gson = new GsonBuilder().serializeNulls().create();
@SuppressWarnings("deprecation")
public DataLayerAPIVerticle() {
this.configManager = ConfigManager.getInstance();
String jdbcUrl = configManager.getJdbcUrl();
String dbUser = configManager.getStringProperty("db.user");
String dbPwd = configManager.getStringProperty("db.pwd");
Integer poolSize = configManager.getIntProperty("db.poolSize");
JsonObject dbConfig = new JsonObject()
.put("url", jdbcUrl)
.put("user", dbUser)
.put("password", dbPwd)
.put("max_pool_size", poolSize != null ? poolSize : 10);
this.pool = JDBCPool.pool(Vertx.vertx(), dbConfig);
}
@Override
public void start(Promise<Void> startPromise) {
Constants.LOGGER.info("📡 Iniciando DataLayerAPIVerticle...");
dbManager = DatabaseManager.getInstance(pool);
Router router = Router.router(vertx);
Set<HttpMethod> allowedMethods = new HashSet<>(
Arrays.asList(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.OPTIONS)); // Por ejemplo
Set<String> allowedHeaders = new HashSet<>(Arrays.asList("Content-Type", "Authorization"));
router.route().handler(CorsHandler.create()
.allowCredentials(true)
.allowedHeaders(allowedHeaders)
.allowedMethods(allowedMethods));
router.route().handler(BodyHandler.create());
// Payload
router.route(HttpMethod.POST, Constants.POST_PAYLOAD).handler(this::addDevicePayload);
// Group Routes
router.route(HttpMethod.GET, Constants.GET_GROUPS).handler(this::getAllGroups);
router.route(HttpMethod.GET, Constants.GET_GROUP_BY_ID).handler(this::getGroupById);
router.route(HttpMethod.POST, Constants.POST_GROUPS).handler(this::addGroup);
router.route(HttpMethod.PUT, Constants.PUT_GROUP_BY_ID).handler(this::updateGroup);
// Device Routes
router.route(HttpMethod.GET, Constants.GET_DEVICES).handler(this::getAllDevices);
router.route(HttpMethod.GET, Constants.GET_DEVICE_BY_ID).handler(this::getDeviceById);
router.route(HttpMethod.POST, Constants.POST_DEVICES).handler(this::addDevice);
router.route(HttpMethod.PUT, Constants.PUT_DEVICE_BY_ID).handler(this::updateDevice);
// Sensor Routes
router.route(HttpMethod.GET, Constants.GET_SENSORS).handler(this::getAllSensors);
router.route(HttpMethod.GET, Constants.GET_SENSOR_BY_ID).handler(this::getSensorById);
router.route(HttpMethod.POST, Constants.POST_SENSORS).handler(this::addSensor);
router.route(HttpMethod.PUT, Constants.PUT_SENSOR_BY_ID).handler(this::updateSensor);
// Actuator Routes
router.route(HttpMethod.GET, Constants.GET_ACTUATORS).handler(this::getAllActuators);
router.route(HttpMethod.GET, Constants.GET_ACTUATOR_BY_ID).handler(this::getActuatorById);
router.route(HttpMethod.POST, Constants.POST_ACTUATORS).handler(this::addActuator);
router.route(HttpMethod.PUT, Constants.PUT_ACTUATOR_BY_ID).handler(this::updateActuator);
// Views Routes
router.route(HttpMethod.GET, Constants.GET_LATEST_VALUES_VIEW).handler(this::getLatestValuesView);
router.route(HttpMethod.GET, Constants.GET_POLLUTION_MAP_VIEW).handler(this::getDevicePollutionMapView);
router.route(HttpMethod.GET, Constants.GET_SENSOR_VALUES_VIEW).handler(this::getSensorValuesView);
router.route(HttpMethod.GET, Constants.GET_SENSOR_HISTORY_BY_DEVICE_VIEW).handler(this::getSensorHistoryByDeviceView);
vertx.createHttpServer()
.requestHandler(router)
.listen(configManager.getDataApiPort(), configManager.getHost());
pool.query("SELECT 1").execute(ar -> {
if (ar.succeeded()) {
Constants.LOGGER.info("🟢 Connected to DB");
startPromise.complete();
} else {
Constants.LOGGER.error("🔴 Failed to connect to DB: " + ar.cause());
startPromise.fail(ar.cause());
}
});
}
private void addDevicePayload(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
DevicePayload devicePayload = gson.fromJson(body.toString(), DevicePayload.class);
COValue coValue = COValue.fromPayload(devicePayload);
GpsValue gpsValue = GpsValue.fromPayload(devicePayload);
WeatherValue weatherValue = WeatherValue.fromPayload(devicePayload);
String coQuery = QueryBuilder
.insert(coValue)
.build();
String gpsQuery = QueryBuilder
.insert(gpsValue)
.build();
String weatherQuery = QueryBuilder
.insert(weatherValue)
.build();
dbManager.execute(coQuery, COValue.class,
onSuccess -> {
dbManager.execute(gpsQuery, GpsValue.class,
onSuccess2 -> {
dbManager.execute(weatherQuery, WeatherValue.class,
onSuccess3 -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Payload added successfully")));
},
onFailure3 -> {
context.fail(500, onFailure3);
});
},
onFailure2 -> {
context.fail(500, onFailure2);
});
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getAllGroups(RoutingContext context) {
String query = QueryBuilder
.select(Group.class)
.build();
dbManager.execute(query, Group.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getGroupById(RoutingContext context) {
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
Group group = new Group(groupId, null);
String query = QueryBuilder
.select(group)
.build();
dbManager.execute(query, Group.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void addGroup(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Group group = gson.fromJson(body.toString(), Group.class);
String query = QueryBuilder
.insert(group)
.build();
dbManager.execute(query, Group.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Group added successfully")));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void updateGroup(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Group group = gson.fromJson(body.toString(), Group.class);
String query = QueryBuilder
.update(group)
.build();
dbManager.execute(query, Group.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Group updated successfully")));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getAllDevices(RoutingContext context) {
String query = QueryBuilder
.select(Device.class)
.build();
dbManager.execute(query, Device.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getDeviceById(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Device device = new Device(deviceId, null, null);
String query = QueryBuilder
.select(device)
.build();
dbManager.execute(query, Device.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void addDevice(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Device device = gson.fromJson(body.toString(), Device.class);
String query = QueryBuilder
.insert(device)
.build();
dbManager.execute(query, Device.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Device added successfully")));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void updateDevice(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Device device = gson.fromJson(body.toString(), Device.class);
String query = QueryBuilder
.update(device)
.build();
dbManager.execute(query, Device.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Device updated successfully")));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getAllSensors(RoutingContext context) {
String query = QueryBuilder
.select(Sensor.class)
.build();
dbManager.execute(query, Sensor.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getSensorById(RoutingContext context) {
Integer sensorId = Integer.parseInt(context.request().getParam("sensorId"));
Sensor sensor = new Sensor(sensorId, null, null, null, null, null);
String query = QueryBuilder
.select(sensor)
.build();
dbManager.execute(query, Sensor.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void addSensor(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Sensor sensor = gson.fromJson(body.toString(), Sensor.class);
String query = QueryBuilder
.insert(sensor)
.build();
dbManager.execute(query, Sensor.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Sensor added successfully")));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void updateSensor(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Sensor sensor = gson.fromJson(body.toString(), Sensor.class);
String query = QueryBuilder
.update(sensor)
.build();
dbManager.execute(query, Sensor.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Sensor updated successfully")));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getAllActuators(RoutingContext context) {
String query = QueryBuilder
.select(Actuator.class)
.build();
dbManager.execute(query, Actuator.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getActuatorById(RoutingContext context) {
Integer actuatorId = Integer.parseInt(context.request().getParam("actuatorId"));
Actuator actuator = new Actuator(actuatorId, null, null, null);
String query = QueryBuilder
.select(actuator)
.build();
dbManager.execute(query, Actuator.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void addActuator(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Actuator actuator = gson.fromJson(body.toString(), Actuator.class);
String query = QueryBuilder
.insert(actuator)
.build();
dbManager.execute(query, Actuator.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Actuator added successfully")));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void updateActuator(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Actuator actuator = gson.fromJson(body.toString(), Actuator.class);
String query = QueryBuilder
.update(actuator)
.build();
dbManager.execute(query, Actuator.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Actuator updated successfully")));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getLatestValuesView(RoutingContext context) {
String query = QueryBuilder
.select(DeviceLatestValuesView.class)
.build();
dbManager.execute(query, DeviceLatestValuesView.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getDevicePollutionMapView(RoutingContext context) {
String query = QueryBuilder
.select(DevicePollutionMap.class)
.build();
dbManager.execute(query, DevicePollutionMap.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getSensorValuesView(RoutingContext context) {
String query = QueryBuilder
.select(DeviceSensorValue.class)
.build();
dbManager.execute(query, DeviceSensorValue.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getSensorHistoryByDeviceView(RoutingContext context) {
String query = QueryBuilder
.select(DeviceSensorHistory.class)
.build();
dbManager.execute(query, DeviceSensorHistory.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
}

View File

@@ -1,225 +0,0 @@
package net.miarma.contaminus.server;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;
import net.miarma.contaminus.common.ConfigManager;
import net.miarma.contaminus.common.Constants;
import net.miarma.contaminus.database.entities.Actuator;
import net.miarma.contaminus.database.entities.Device;
import net.miarma.contaminus.database.entities.DeviceLatestValuesView;
import net.miarma.contaminus.database.entities.DevicePollutionMap;
import net.miarma.contaminus.database.entities.DeviceSensorHistory;
import net.miarma.contaminus.database.entities.DeviceSensorValue;
import net.miarma.contaminus.database.entities.Sensor;
import net.miarma.contaminus.util.RestClientUtil;
public class LogicLayerAPIVerticle extends AbstractVerticle {
private ConfigManager configManager;
private final Gson gson = new GsonBuilder().serializeNulls().create();
private RestClientUtil restClient;
public LogicLayerAPIVerticle() {
this.configManager = ConfigManager.getInstance();
WebClientOptions options = new WebClientOptions()
.setUserAgent("ContaminUS");
this.restClient = new RestClientUtil(WebClient.create(Vertx.vertx(), options));
}
@Override
public void start(Promise<Void> startPromise) {
Constants.LOGGER.info("📡 Iniciando LogicApiVerticle...");
Router router = Router.router(vertx);
Set<HttpMethod> allowedMethods = new HashSet<>(
Arrays.asList(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.OPTIONS)); // Por ejemplo
Set<String> allowedHeaders = new HashSet<>(Arrays.asList("Content-Type", "Authorization"));
router.route().handler(CorsHandler.create()
.allowCredentials(true)
.allowedHeaders(allowedHeaders)
.allowedMethods(allowedMethods));
router.route().handler(BodyHandler.create());
router.route(HttpMethod.GET, Constants.GET_GROUP_DEVICES).handler(this::getGroupDevices);
router.route(HttpMethod.GET, Constants.GET_DEVICE_SENSORS).handler(this::getDeviceSensors);
router.route(HttpMethod.GET, Constants.GET_DEVICE_ACTUATORS).handler(this::getDeviceActuators);
router.route(HttpMethod.GET, Constants.GET_DEVICE_LATEST_VALUES).handler(this::getDeviceLatestValues);
router.route(HttpMethod.GET, Constants.GET_DEVICE_POLLUTION_MAP).handler(this::getDevicePollutionMap);
router.route(HttpMethod.GET, Constants.GET_DEVICE_HISTORY).handler(this::getDeviceHistory);
router.route(HttpMethod.GET, Constants.GET_SENSOR_VALUES).handler(this::getSensorValues);
vertx.createHttpServer()
.requestHandler(router)
.listen(configManager.getLogicApiPort(), configManager.getHost());
startPromise.complete();
}
private void getGroupDevices(RoutingContext context) {
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
Promise<Device[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if(complete.succeeded()) {
List<Device> aux = Stream.of(complete.result())
.filter(d -> d.getGroupId() == groupId)
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.GET_DEVICES, Device[].class, resultList);
}
private void getDeviceSensors(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Promise<Sensor[]> resultList = Promise.promise();
resultList.future().onComplete(result -> {
if (result.succeeded()) {
Sensor[] sensors = result.result();
List<Sensor> aux = Arrays.stream(sensors)
.filter(s -> s.getDeviceId() == deviceId)
.toList();
context.response().putHeader("Content-Type", "application/json").end(gson.toJson(aux));
} else {
context.response().setStatusCode(500).end(result.cause().getMessage());
}
});
restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.GET_SENSORS, Sensor[].class, resultList);
}
private void getDeviceActuators(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Promise<Actuator[]> resultList = Promise.promise();
resultList.future().onComplete(result -> {
if (result.succeeded()) {
Actuator[] devices = result.result();
List<Actuator> aux = Arrays.stream(devices)
.filter(a -> a.getDeviceId() == deviceId)
.toList();
context.response().putHeader("Content-Type", "application/json").end(gson.toJson(aux));
} else {
context.response().setStatusCode(500).end(result.cause().getMessage());
}
});
restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.GET_ACTUATORS, Actuator[].class, resultList);
}
private void getDeviceLatestValues(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Promise<DeviceLatestValuesView[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if (complete.succeeded()) {
List<DeviceLatestValuesView> aux = Stream.of(complete.result())
.filter(elem -> elem.getDeviceId() == deviceId)
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.GET_LATEST_VALUES_VIEW, DeviceLatestValuesView[].class, resultList);
}
private void getDevicePollutionMap(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Promise<DevicePollutionMap[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if (complete.succeeded()) {
List<DevicePollutionMap> aux = Arrays.asList(complete.result()).stream()
.filter(elem -> elem.getDeviceId() == deviceId)
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.GET_POLLUTION_MAP_VIEW, DevicePollutionMap[].class, resultList);
}
private void getDeviceHistory(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Promise<DeviceSensorHistory[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if (complete.succeeded()) {
List<DeviceSensorHistory> aux = Arrays.asList(complete.result()).stream()
.filter(elem -> elem.getDeviceId() == deviceId)
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.GET_SENSOR_HISTORY_BY_DEVICE_VIEW, DeviceSensorHistory[].class, resultList);
}
private void getSensorValues(RoutingContext context) {
Integer sensorId = Integer.parseInt(context.request().getParam("sensorId"));
Promise<DeviceSensorValue[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if (complete.succeeded()) {
List<DeviceSensorValue> aux = Arrays.asList(complete.result()).stream()
.filter(val -> val.getSensorId() == sensorId)
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.GET_SENSOR_VALUES_VIEW, DeviceSensorValue[].class, resultList);
}
}

View File

@@ -0,0 +1,479 @@
package net.miarma.contaminus.verticles;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;
import io.vertx.sqlclient.Pool;
import net.miarma.contaminus.common.ConfigManager;
import net.miarma.contaminus.common.Constants;
import net.miarma.contaminus.common.SingleJsonResponse;
import net.miarma.contaminus.dao.ActuatorDAO;
import net.miarma.contaminus.dao.COValueDAO;
import net.miarma.contaminus.dao.DeviceDAO;
import net.miarma.contaminus.dao.GpsValueDAO;
import net.miarma.contaminus.dao.GroupDAO;
import net.miarma.contaminus.dao.SensorDAO;
import net.miarma.contaminus.dao.WeatherValueDAO;
import net.miarma.contaminus.dao.views.ViewLatestValuesDAO;
import net.miarma.contaminus.dao.views.ViewPollutionMapDAO;
import net.miarma.contaminus.dao.views.ViewSensorHistoryDAO;
import net.miarma.contaminus.dao.views.ViewSensorValueDAO;
import net.miarma.contaminus.db.DatabaseManager;
import net.miarma.contaminus.db.DatabaseProvider;
import net.miarma.contaminus.db.QueryBuilder;
import net.miarma.contaminus.entities.Actuator;
import net.miarma.contaminus.entities.Device;
import net.miarma.contaminus.entities.Group;
import net.miarma.contaminus.entities.Sensor;
import net.miarma.contaminus.entities.ViewLatestValues;
import net.miarma.contaminus.entities.ViewPollutionMap;
import net.miarma.contaminus.entities.ViewSensorHistory;
import net.miarma.contaminus.entities.ViewSensorValue;
/*
* This class is a Verticle that will handle the Data Layer API.
*/
@SuppressWarnings("unused")
public class DataLayerAPIVerticle extends AbstractVerticle {
private DatabaseManager dbManager;
private ConfigManager configManager;
private final Gson gson = new GsonBuilder().serializeNulls().create();
private Pool pool;
private GroupDAO groupDAO;
private DeviceDAO deviceDAO;
private SensorDAO sensorDAO;
private ActuatorDAO actuatorDAO;
private COValueDAO coValueDAO;
private WeatherValueDAO weatherValueDAO;
private GpsValueDAO gpsValueDAO;
private ViewLatestValuesDAO viewLatestValuesDAO;
private ViewPollutionMapDAO viewPollutionMapDAO;
private ViewSensorHistoryDAO viewSensorHistoryDAO;
private ViewSensorValueDAO viewSensorValueDAO;
public DataLayerAPIVerticle() {
this.configManager = ConfigManager.getInstance();
}
@Override
public void start(Promise<Void> startPromise) {
Constants.LOGGER.info("📡 Iniciando DataLayerAPIVerticle...");
this.pool = DatabaseProvider.createPool(vertx, configManager);
this.dbManager = DatabaseManager.getInstance(pool);
this.groupDAO = new GroupDAO(pool);
this.deviceDAO = new DeviceDAO(pool);
this.sensorDAO = new SensorDAO(pool);
this.actuatorDAO = new ActuatorDAO(pool);
this.coValueDAO = new COValueDAO(pool);
this.weatherValueDAO = new WeatherValueDAO(pool);
this.gpsValueDAO = new GpsValueDAO(pool);
this.viewLatestValuesDAO = new ViewLatestValuesDAO(pool);
this.viewPollutionMapDAO = new ViewPollutionMapDAO(pool);
this.viewSensorHistoryDAO = new ViewSensorHistoryDAO(pool);
this.viewSensorValueDAO = new ViewSensorValueDAO(pool);
Router router = Router.router(vertx);
Set<HttpMethod> allowedMethods = new HashSet<>(
Arrays.asList(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.OPTIONS)); // Por ejemplo
Set<String> allowedHeaders = new HashSet<>(Arrays.asList("Content-Type", "Authorization"));
router.route().handler(CorsHandler.create()
.allowCredentials(true)
.allowedHeaders(allowedHeaders)
.allowedMethods(allowedMethods));
router.route().handler(BodyHandler.create());
// Group Routes
router.route(HttpMethod.GET, Constants.GROUPS).handler(this::getAllGroups);
router.route(HttpMethod.GET, Constants.GROUP).handler(this::getGroupById);
router.route(HttpMethod.POST, Constants.GROUPS).handler(this::addGroup);
router.route(HttpMethod.PUT, Constants.GROUP).handler(this::updateGroup);
// Device Routes
router.route(HttpMethod.GET, Constants.DEVICES).handler(this::getAllDevices);
router.route(HttpMethod.GET, Constants.DEVICE).handler(this::getDeviceById);
router.route(HttpMethod.POST, Constants.DEVICES).handler(this::addDevice);
router.route(HttpMethod.PUT, Constants.DEVICE).handler(this::updateDevice);
// Sensor Routes
router.route(HttpMethod.GET, Constants.SENSORS).handler(this::getAllSensors);
router.route(HttpMethod.GET, Constants.SENSOR).handler(this::getSensorById);
router.route(HttpMethod.POST, Constants.SENSORS).handler(this::addSensor);
router.route(HttpMethod.PUT, Constants.SENSOR).handler(this::updateSensor);
// Actuator Routes
router.route(HttpMethod.GET, Constants.ACTUATORS).handler(this::getAllActuators);
router.route(HttpMethod.GET, Constants.ACTUATOR).handler(this::getActuatorById);
router.route(HttpMethod.POST, Constants.ACTUATORS).handler(this::addActuator);
router.route(HttpMethod.PUT, Constants.ACTUATOR).handler(this::updateActuator);
// Views Routes
router.route(HttpMethod.GET, Constants.VIEW_LATEST_VALUES).handler(this::getLatestValuesView);
router.route(HttpMethod.GET, Constants.VIEW_POLLUTION_MAP).handler(this::getDevicePollutionMapView);
router.route(HttpMethod.GET, Constants.VIEW_SENSOR_VALUES).handler(this::getSensorValuesView);
router.route(HttpMethod.GET, Constants.VIEW_SENSOR_HISTORY).handler(this::getSensorHistoryByDeviceView);
vertx.createHttpServer()
.requestHandler(router)
.listen(configManager.getDataApiPort(), configManager.getHost());
pool.query("SELECT 1").execute(ar -> {
if (ar.succeeded()) {
Constants.LOGGER.info("🟢 Connected to DB");
startPromise.complete();
} else {
Constants.LOGGER.error("🔴 Failed to connect to DB: " + ar.cause());
startPromise.fail(ar.cause());
}
});
}
private void getAllGroups(RoutingContext context) {
groupDAO.getAll()
.onSuccess(groups -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(groups));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void getGroupById(RoutingContext context) {
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
groupDAO.getById(groupId)
.onSuccess(group -> {
if (group != null) {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(group));
} else {
context.response().setStatusCode(404).end();
}
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void addGroup(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Group group = gson.fromJson(body.toString(), Group.class);
groupDAO.insert(group)
.onSuccess(result -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Group added successfully")));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void updateGroup(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Group group = gson.fromJson(body.toString(), Group.class);
groupDAO.update(group)
.onSuccess(result -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Group updated successfully")));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void getAllDevices(RoutingContext context) {
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
deviceDAO.getAllByGroupId(groupId)
.onSuccess(devices -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(devices));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void getDeviceById(RoutingContext context) {
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
String deviceId = context.request().getParam("deviceId");
deviceDAO.getByIdAndGroupId(deviceId, groupId)
.onSuccess(device -> {
if (device != null) {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(device));
} else {
context.response().setStatusCode(404).end();
}
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void addDevice(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Device device = gson.fromJson(body.toString(), Device.class);
deviceDAO.insert(device)
.onSuccess(result -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Device added successfully")));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void updateDevice(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Device device = gson.fromJson(body.toString(), Device.class);
deviceDAO.update(device)
.onSuccess(result -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Device updated successfully")));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void getAllSensors(RoutingContext context) {
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
String deviceId = context.request().getParam("deviceId");
deviceDAO.getByIdAndGroupId(deviceId, groupId).compose(device -> {
if (device == null) {
return Future.succeededFuture(List.of());
}
return sensorDAO.getAllByDeviceId(device.getDeviceId());
}).onSuccess(sensors -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(sensors));
}).onFailure(err -> {
context.response().setStatusCode(500).end("Error: " + err.getMessage());
});
}
private void getSensorById(RoutingContext context) {
Integer sensorId = Integer.parseInt(context.request().getParam("sensorId"));
String deviceId = context.request().getParam("deviceId");
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
deviceDAO.getByIdAndGroupId(deviceId, groupId).compose(device -> {
if (device == null) {
return Future.succeededFuture(null);
}
return sensorDAO.getByIdAndDeviceId(sensorId, device.getDeviceId());
}).onSuccess(sensor -> {
if (sensor == null) {
context.response().setStatusCode(404).end("Sensor no encontrado");
return;
}
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(sensor));
}).onFailure(err -> {
context.response().setStatusCode(500).end("Error: " + err.getMessage());
});
}
private void addSensor(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Sensor sensor = gson.fromJson(body.toString(), Sensor.class);
sensorDAO.insert(sensor)
.onSuccess(result -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Sensor added successfully")));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void updateSensor(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Sensor sensor = gson.fromJson(body.toString(), Sensor.class);
sensorDAO.update(sensor)
.onSuccess(result -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Sensor updated successfully")));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void getAllActuators(RoutingContext context) {
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
String deviceId = context.request().getParam("deviceId");
deviceDAO.getByIdAndGroupId(deviceId, groupId).compose(device -> {
if (device == null) {
return Future.succeededFuture(List.of());
}
return actuatorDAO.getAllByDeviceId(device.getDeviceId());
}).onSuccess(actuators -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(actuators));
}).onFailure(err -> {
context.response().setStatusCode(500).end("Error: " + err.getMessage());
});
}
private void getActuatorById(RoutingContext context) {
Integer groupId = Integer.parseInt(context.request().getParam("groupId"));
String deviceId = context.request().getParam("deviceId");
Integer actuatorId = Integer.parseInt(context.request().getParam("actuatorId"));
deviceDAO.getByIdAndGroupId(deviceId, groupId).compose(device -> {
if (device == null) {
return Future.succeededFuture(null);
}
return actuatorDAO.getByIdAndDeviceId(actuatorId, device.getDeviceId());
}).onSuccess(actuator -> {
if (actuator == null) {
context.response().setStatusCode(404).end("Actuator no encontrado");
return;
}
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(actuator));
}).onFailure(err -> {
context.response().setStatusCode(500).end("Error: " + err.getMessage());
});
}
private void addActuator(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Actuator actuator = gson.fromJson(body.toString(), Actuator.class);
actuatorDAO.insert(actuator)
.onSuccess(result -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Actuator added successfully")));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void updateActuator(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
Actuator actuator = gson.fromJson(body.toString(), Actuator.class);
actuatorDAO.update(actuator)
.onSuccess(result -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(SingleJsonResponse.of("Actuator updated successfully")));
})
.onFailure(err -> {
context.fail(500, err);
});
}
private void getLatestValuesView(RoutingContext context) {
String query = QueryBuilder
.select(ViewLatestValues.class)
.build();
dbManager.execute(query, ViewLatestValues.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getDevicePollutionMapView(RoutingContext context) {
String query = QueryBuilder
.select(ViewPollutionMap.class)
.build();
dbManager.execute(query, ViewPollutionMap.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getSensorValuesView(RoutingContext context) {
String query = QueryBuilder
.select(ViewSensorValue.class)
.build();
dbManager.execute(query, ViewSensorValue.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
private void getSensorHistoryByDeviceView(RoutingContext context) {
String query = QueryBuilder
.select(ViewSensorHistory.class)
.build();
dbManager.execute(query, ViewSensorHistory.class,
onSuccess -> {
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(onSuccess));
},
onFailure -> {
context.fail(500, onFailure);
});
}
}

View File

@@ -0,0 +1,160 @@
package net.miarma.contaminus.verticles;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;
import net.miarma.contaminus.common.ConfigManager;
import net.miarma.contaminus.common.Constants;
import net.miarma.contaminus.entities.ViewLatestValues;
import net.miarma.contaminus.entities.ViewPollutionMap;
import net.miarma.contaminus.entities.ViewSensorHistory;
import net.miarma.contaminus.entities.ViewSensorValue;
import net.miarma.contaminus.util.RestClientUtil;
public class LogicLayerAPIVerticle extends AbstractVerticle {
private ConfigManager configManager;
private final Gson gson = new GsonBuilder().serializeNulls().create();
private RestClientUtil restClient;
public LogicLayerAPIVerticle() {
this.configManager = ConfigManager.getInstance();
WebClientOptions options = new WebClientOptions()
.setUserAgent("ContaminUS");
this.restClient = new RestClientUtil(WebClient.create(Vertx.vertx(), options));
}
@Override
public void start(Promise<Void> startPromise) {
Constants.LOGGER.info("📡 Iniciando LogicApiVerticle...");
Router router = Router.router(vertx);
Set<HttpMethod> allowedMethods = new HashSet<>(
Arrays.asList(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.OPTIONS));
Set<String> allowedHeaders = new HashSet<>(Arrays.asList("Content-Type", "Authorization"));
router.route().handler(CorsHandler.create()
.allowCredentials(true)
.allowedHeaders(allowedHeaders)
.allowedMethods(allowedMethods));
router.route().handler(BodyHandler.create());
router.route(HttpMethod.GET, Constants.LATEST_VALUES).handler(this::getDeviceLatestValues);
router.route(HttpMethod.GET, Constants.POLLUTION_MAP).handler(this::getDevicePollutionMap);
router.route(HttpMethod.GET, Constants.HISTORY).handler(this::getDeviceHistory);
router.route(HttpMethod.GET, Constants.SENSOR_VALUES).handler(this::getSensorValues);
vertx.createHttpServer()
.requestHandler(router)
.listen(configManager.getLogicApiPort(), configManager.getHost());
startPromise.complete();
}
private void getDeviceLatestValues(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Promise<ViewLatestValues[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if (complete.succeeded()) {
List<ViewLatestValues> aux = Stream.of(complete.result())
.filter(elem -> deviceId.equals(elem.getDeviceId()))
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.VIEW_LATEST_VALUES, ViewLatestValues[].class, resultList);
}
private void getDevicePollutionMap(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Promise<ViewPollutionMap[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if (complete.succeeded()) {
List<ViewPollutionMap> aux = Arrays.asList(complete.result()).stream()
.filter(elem -> deviceId.equals(elem.getDeviceId()))
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.VIEW_POLLUTION_MAP, ViewPollutionMap[].class, resultList);
}
private void getDeviceHistory(RoutingContext context) {
String deviceId = context.request().getParam("deviceId");
Promise<ViewSensorHistory[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if (complete.succeeded()) {
List<ViewSensorHistory> aux = Arrays.asList(complete.result()).stream()
.filter(elem -> deviceId.equals(elem.getDeviceId()))
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.VIEW_SENSOR_HISTORY, ViewSensorHistory[].class, resultList);
}
private void getSensorValues(RoutingContext context) {
Integer sensorId = Integer.parseInt(context.request().getParam("sensorId"));
Promise<ViewSensorValue[]> resultList = Promise.promise();
resultList.future().onComplete(complete -> {
if (complete.succeeded()) {
List<ViewSensorValue> aux = Arrays.asList(complete.result()).stream()
.filter(val -> val.getSensorId() == sensorId)
.toList();
context.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(gson.toJson(aux));
} else {
context.fail(500, complete.cause());
}
});
this.restClient.getRequest(configManager.getDataApiPort(), "http://" + configManager.getHost(),
Constants.VIEW_SENSOR_VALUES, ViewSensorValue[].class, resultList);
}
}

View File

@@ -1,97 +1,96 @@
package net.miarma.contaminus.server; package net.miarma.contaminus.verticles;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import io.vertx.core.AbstractVerticle; import io.vertx.core.AbstractVerticle;
import io.vertx.core.DeploymentOptions; import io.vertx.core.DeploymentOptions;
import io.vertx.core.Launcher; import io.vertx.core.Launcher;
import io.vertx.core.Promise; import io.vertx.core.Promise;
import io.vertx.core.ThreadingModel; import io.vertx.core.ThreadingModel;
import net.miarma.contaminus.common.ConfigManager; import net.miarma.contaminus.common.ConfigManager;
import net.miarma.contaminus.common.Constants; import net.miarma.contaminus.common.Constants;
public class MainVerticle extends AbstractVerticle { public class MainVerticle extends AbstractVerticle {
private ConfigManager configManager; private ConfigManager configManager;
public static void main(String[] args) { public static void main(String[] args) {
Launcher.executeCommand("run", MainVerticle.class.getName()); Launcher.executeCommand("run", MainVerticle.class.getName());
} }
private void init() { private void init() {
this.configManager = ConfigManager.getInstance(); this.configManager = ConfigManager.getInstance();
initializeDirectories(); initializeDirectories();
copyDefaultConfig(); copyDefaultConfig();
} }
private void initializeDirectories() { private void initializeDirectories() {
File baseDir = new File(this.configManager.getBaseDir()); File baseDir = new File(this.configManager.getBaseDir());
if (!baseDir.exists()) { if (!baseDir.exists()) {
baseDir.mkdirs(); baseDir.mkdirs();
} }
} }
private void copyDefaultConfig() { private void copyDefaultConfig() {
File configFile = new File(configManager.getConfigFile().getAbsolutePath()); File configFile = new File(configManager.getConfigFile().getAbsolutePath());
if (!configFile.exists()) { if (!configFile.exists()) {
try (InputStream in = MainVerticle.class.getClassLoader().getResourceAsStream("default.properties")) { try (InputStream in = MainVerticle.class.getClassLoader().getResourceAsStream("default.properties")) {
if (in != null) { if (in != null) {
Files.copy(in, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING); Files.copy(in, configFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} else { } else {
Constants.LOGGER.error("🔴 Default config file not found in resources"); Constants.LOGGER.error("🔴 Default config file not found in resources");
} }
} catch (IOException e) { } catch (IOException e) {
Constants.LOGGER.error("🔴 Failed to copy default config file", e); Constants.LOGGER.error("🔴 Failed to copy default config file", e);
} }
} }
} }
@Override @Override
public void start(Promise<Void> startPromise) { public void start(Promise<Void> startPromise) {
try { try {
System.setProperty("java.util.logging.manager", "org.jboss.logmanager.LogManager"); init();
init(); deployVerticles(startPromise);
deployVerticles(startPromise); } catch (Exception e) {
} catch (Exception e) { Constants.LOGGER.error("🔴 Error starting the application: " + e);
Constants.LOGGER.error("🔴 Error starting the application: " + e); startPromise.fail(e);
startPromise.fail(e); }
} }
}
private void deployVerticles(Promise<Void> startPromise) {
private void deployVerticles(Promise<Void> startPromise) { final DeploymentOptions options = new DeploymentOptions();
final DeploymentOptions options = new DeploymentOptions(); options.setThreadingModel(ThreadingModel.WORKER);
options.setThreadingModel(ThreadingModel.WORKER);
vertx.deployVerticle(new DataLayerAPIVerticle(), options, result -> {
vertx.deployVerticle(new DataLayerAPIVerticle(), options, result -> { if (result.succeeded()) {
if (result.succeeded()) { Constants.LOGGER.info("🟢 DatabaseVerticle desplegado");
Constants.LOGGER.info("🟢 DatabaseVerticle desplegado"); Constants.LOGGER.info("\t🔗 API URL: " + configManager.getHost()
Constants.LOGGER.info("\t🔗 API URL: " + configManager.getHost() + ":" + configManager.getDataApiPort());
+ ":" + configManager.getDataApiPort()); } else {
} else { Constants.LOGGER.error("🔴 Error deploying DataLayerAPIVerticle: " + result.cause());
Constants.LOGGER.error("🔴 Error deploying DataLayerAPIVerticle: " + result.cause()); }
} });
});
vertx.deployVerticle(new LogicLayerAPIVerticle(), options, result -> {
vertx.deployVerticle(new LogicLayerAPIVerticle(), options, result -> { if (result.succeeded()) {
if (result.succeeded()) { Constants.LOGGER.info("🟢 LogicLayerAPIVerticle desplegado");
Constants.LOGGER.info("🟢 LogicLayerAPIVerticle desplegado"); Constants.LOGGER.info("\t🔗 API URL: " + configManager.getHost()
Constants.LOGGER.info("\t🔗 API URL: " + configManager.getHost() + ":" + configManager.getLogicApiPort());
+ ":" + configManager.getLogicApiPort()); } else {
} else { Constants.LOGGER.error("🔴 Error deploying LogicLayerAPIVerticle: " + result.cause());
Constants.LOGGER.error("🔴 Error deploying LogicLayerAPIVerticle: " + result.cause()); }
} });
});
startPromise.complete();
startPromise.complete(); }
}
@Override
@Override public void stop(Promise<Void> stopPromise) throws Exception {
public void stop(Promise<Void> stopPromise) throws Exception { getVertx().deploymentIDs()
getVertx().deploymentIDs() .forEach(v -> getVertx().undeploy(v));
.forEach(v -> getVertx().undeploy(v)); }
}
}
}

View File

@@ -1,18 +1,18 @@
package net.miarma.contaminus.server; package net.miarma.contaminus.verticles;
import io.vertx.core.AbstractVerticle; import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise; import io.vertx.core.Promise;
public class MqttVerticle extends AbstractVerticle { public class MqttVerticle extends AbstractVerticle {
@Override @Override
public void start(Promise<Void> startPromise) { public void start(Promise<Void> startPromise) {
} }
@Override @Override
public void stop(Promise<Void> startPromise) { public void stop(Promise<Void> startPromise) {
} }
} }

View File

@@ -1,14 +1,14 @@
# DB Configuration # DB Configuration
db.protocol=jdbc:mariadb db.protocol=jdbc:mariadb
db.host=localhost db.host=localhost
db.port=3306 db.port=3306
db.name=dad db.name=dad
db.user=root db.user=root
db.pwd=root db.password=root
dp.poolSize=5 dp.poolSize=5
# HTTP Server Configuration # HTTP Server Configuration
inet.host=localhost inet.host=localhost
webserver.port=8080 webserver.port=8080
data-api.port=8081 data-api.port=8081
logic-api.port=8082 logic-api.port=8082

View File

@@ -0,0 +1,20 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%cyan([%d{HH:mm:ss}]) %highlight(%-5level) %green(%logger{20}) - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
<logger name="io.netty" level="WARN"/>
<logger name="io.vertx" level="INFO"/>
<logger name="io.vertx.core.impl.launcher" level="INFO"/>
<logger name="io.vertx.core.logging" level="INFO"/>
</configuration>

View File

@@ -1,77 +1,77 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import CardContainer from './CardContainer'; import CardContainer from './CardContainer';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCloud, faClock, faTemperature0, faWater } from '@fortawesome/free-solid-svg-icons'; import { faCloud, faClock, faTemperature0, faWater } from '@fortawesome/free-solid-svg-icons';
import { DataProvider } from '@/context/DataContext'; import { DataProvider } from '@/context/DataContext';
import { useDataContext } from '@/hooks/useDataContext'; import { useDataContext } from '@/hooks/useDataContext';
import { useConfig } from '@/hooks/useConfig.js'; import { useConfig } from '@/hooks/useConfig.js';
import { DateParser } from '@/util/dateParser'; import { DateParser } from '@/util/dateParser';
const SummaryCards = ({ deviceId }) => { const SummaryCards = ({ deviceId }) => {
const { config, configLoading, configError } = useConfig(); const { config, configLoading, configError } = useConfig();
if (configLoading) return <p>Cargando configuración...</p>; if (configLoading) return <p>Cargando configuración...</p>;
if (configError) return <p>Error al cargar configuración: {configError}</p>; if (configError) return <p>Error al cargar configuración: {configError}</p>;
if (!config) return <p>Configuración no disponible.</p>; if (!config) return <p>Configuración no disponible.</p>;
const BASE = config.appConfig.endpoints.LOGIC_URL; const BASE = config.appConfig.endpoints.LOGIC_URL;
const ENDPOINT = config.appConfig.endpoints.GET_DEVICE_LATEST_VALUES; const ENDPOINT = config.appConfig.endpoints.GET_DEVICE_LATEST_VALUES;
const endp = ENDPOINT.replace('{0}', deviceId); const endp = ENDPOINT.replace('{0}', deviceId);
const reqConfig = { const reqConfig = {
baseUrl: `${BASE}${endp}`, baseUrl: `${BASE}${endp}`,
params: {} params: {}
} }
return ( return (
<DataProvider config={reqConfig}> <DataProvider config={reqConfig}>
<SummaryCardsContent /> <SummaryCardsContent />
</DataProvider> </DataProvider>
); );
} }
const SummaryCardsContent = () => { const SummaryCardsContent = () => {
const { data, dataLoading, dataError } = useDataContext(); const { data, dataLoading, dataError } = useDataContext();
if (dataLoading) return <p>Cargando datos...</p>; if (dataLoading) return <p>Cargando datos...</p>;
if (dataError) return <p>Error al cargar datos: {dataError}</p>; if (dataError) return <p>Error al cargar datos: {dataError}</p>;
if (!data) return <p>Datos no disponibles.</p>; if (!data) return <p>Datos no disponibles.</p>;
const CardsData = [ const CardsData = [
{ id: 1, title: "Temperatura", content: "N/A", status: "Esperando datos...", titleIcon: <FontAwesomeIcon icon={faTemperature0} /> }, { id: 1, title: "Temperatura", content: "N/A", status: "Esperando datos...", titleIcon: <FontAwesomeIcon icon={faTemperature0} /> },
{ id: 2, title: "Humedad", content: "N/A", status: "Esperando datos...", titleIcon: <FontAwesomeIcon icon={faWater} /> }, { id: 2, title: "Humedad", content: "N/A", status: "Esperando datos...", titleIcon: <FontAwesomeIcon icon={faWater} /> },
{ id: 3, title: "Nivel de CO", content: "N/A", status: "Esperando datos...", titleIcon: <FontAwesomeIcon icon={faCloud} /> }, { id: 3, title: "Nivel de CO", content: "N/A", status: "Esperando datos...", titleIcon: <FontAwesomeIcon icon={faCloud} /> },
{ id: 4, title: "Actualizado a las", content: "N/A", status: "Esperando datos...", titleIcon: <FontAwesomeIcon icon={faClock} /> } { id: 4, title: "Actualizado a las", content: "N/A", status: "Esperando datos...", titleIcon: <FontAwesomeIcon icon={faClock} /> }
]; ];
if (data) { if (data) {
let coData = data[1]; let coData = data[1];
let tempData = data[2]; let tempData = data[2];
let lastTime = DateParser.timestampToString(coData.airValuesTimestamp); let lastTime = DateParser.timestampToString(coData.timestamp);
let lastDate = new Date(coData.airValuesTimestamp); let lastDate = new Date(coData.timestamp);
CardsData[0].content = tempData.temperature + "°C"; CardsData[0].content = tempData.temperature + "°C";
CardsData[0].status = "Temperatura actual"; CardsData[0].status = "Temperatura actual";
CardsData[1].content = tempData.humidity + "%"; CardsData[1].content = tempData.humidity + "%";
CardsData[1].status = "Humedad actual"; CardsData[1].status = "Humedad actual";
CardsData[2].content = coData.carbonMonoxide + " ppm"; CardsData[2].content = coData.carbonMonoxide + " ppm";
CardsData[2].status = "Nivel de CO actual"; CardsData[2].status = "Nivel de CO actual";
CardsData[3].content = lastTime; CardsData[3].content = lastTime;
CardsData[3].status = "Día " + lastDate.toLocaleDateString(); CardsData[3].status = "Día " + lastDate.toLocaleDateString();
} }
return ( return (
<CardContainer cards={CardsData} /> <CardContainer cards={CardsData} />
); );
} }
SummaryCards.propTypes = { SummaryCards.propTypes = {
deviceId: PropTypes.number.isRequired deviceId: PropTypes.number.isRequired
}; };
export default SummaryCards; export default SummaryCards;

View File

@@ -2,6 +2,9 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <HTTPClient.h> #include <HTTPClient.h>
#include "BME280.hpp"
#include "MQ7v2.hpp"
#include "GPS.hpp"
String serializeSensorValue( String serializeSensorValue(
int sensorId, int sensorId,
@@ -12,15 +15,13 @@ String serializeSensorValue(
const BME280Data_t &bme, const BME280Data_t &bme,
const MQ7Data_t &mq7, const MQ7Data_t &mq7,
const GPSData_t &gps, const GPSData_t &gps,
long timestamp long timestamp);
);
String serializeActuatorStatus( String serializeActuatorStatus(
int actuatorId, int actuatorId,
const String &deviceId, const String &deviceId,
int status, int status,
long timestamp long timestamp);
);
void deserializeSensorValue(HTTPClient &http, int httpResponseCode); void deserializeSensorValue(HTTPClient &http, int httpResponseCode);
void deserializeActuatorStatus(HTTPClient &http, int httpResponseCode); void deserializeActuatorStatus(HTTPClient &http, int httpResponseCode);

View File

@@ -1,51 +1,51 @@
#include <Arduino.h> #include <Arduino.h>
#define SERVER_IP "https://contaminus.miarma.net/api/v1/" #define SERVER_IP "https://contaminus.miarma.net/api/v1/"
#define REST_PORT 443 #define REST_PORT 443
#define MQTT_PORT 1883 #define MQTT_PORT 1883
#define MQ7_ID 1 #define MQ7_ID 1
#define BME280_ID 2 #define BME280_ID 2
#define GPS_ID 3 #define GPS_ID 3
#define MAX7219_ID 1 #define MAX7219_ID 1
#define DEBUG #define DEBUG
#include "JsonTools.hpp" #include "JsonTools.hpp"
#include "RestClient.hpp" #include "RestClient.hpp"
#include "WifiConnection.hpp" #include "WifiConnection.hpp"
#include "MqttClient.hpp" #include "MqttClient.hpp"
#include "BME280.hpp" #include "BME280.hpp"
#include "GPS.hpp" #include "GPS.hpp"
#include "MAX7219.hpp" #include "MAX7219.hpp"
#include "MQ7v2.hpp" #include "MQ7v2.hpp"
struct TaskTimer struct TaskTimer
{ {
uint32_t lastRun = 0; uint32_t lastRun = 0;
uint32_t interval = 1000; uint32_t interval = 1000;
TaskTimer() = default; TaskTimer() = default;
TaskTimer(uint32_t last, uint32_t interval) TaskTimer(uint32_t last, uint32_t interval)
: lastRun(last), interval(interval) {} : lastRun(last), interval(interval) {}
}; };
struct SensorInfo struct SensorInfo
{ {
int id; int id;
String type; String type;
}; };
enum AirQualityStatus enum AirQualityStatus
{ {
GOOD, GOOD,
BAD BAD
}; };
void readMQ7(); void readMQ7();
void readBME280(); void readBME280();
void readGPS(); void readGPS();
void writeMatrix(const char* message); void writeMatrix(const char *message);
void printAllData(); void printAllData();
uint32_t getChipID(); uint32_t getChipID();

View File

@@ -1,159 +1,179 @@
#include "JsonTools.hpp" #include "JsonTools.hpp"
String serializeSensorValue( String serializeSensorValue(
int sensorId, int sensorId,
const String &deviceId, const String &deviceId,
const String &sensorType, const String &sensorType,
const String &unit, const String &unit,
int sensorStatus, int sensorStatus,
const BME280Data_t &bme, const BME280Data_t &bme,
const MQ7Data_t &mq7, const MQ7Data_t &mq7,
const GPSData_t &gps, const GPSData_t &gps,
long timestamp long timestamp)
) { {
DynamicJsonDocument doc(1024); DynamicJsonDocument doc(1024);
doc["sensorId"] = sensorId; doc["sensorId"] = sensorId;
doc["deviceId"] = deviceId; doc["deviceId"] = deviceId;
doc["sensorType"] = sensorType; doc["sensorType"] = sensorType;
doc["unit"] = unit; doc["unit"] = unit;
doc["sensorStatus"] = sensorStatus; doc["sensorStatus"] = sensorStatus;
doc["temperature"] = bme.temperature; doc["temperature"] = bme.temperature;
doc["humidity"] = bme.humidity; doc["humidity"] = bme.humidity;
doc["pressure"] = bme.pressure; doc["pressure"] = bme.pressure;
doc["carbonMonoxide"] = mq7.co; doc["carbonMonoxide"] = mq7.co;
doc["lat"] = gps.lat; doc["lat"] = gps.lat;
doc["lon"] = gps.lon; doc["lon"] = gps.lon;
doc["timestamp"] = timestamp; doc["timestamp"] = timestamp;
String output; String output;
serializeJson(doc, output); serializeJson(doc, output);
Serial.println(output); Serial.println(output);
return output; return output;
} }
String serializeActuatorStatus(const int actuatorId, const String &deviceId, const int status, const long timestamp) { String serializeActuatorStatus(const int actuatorId, const String &deviceId, const int status, const long timestamp)
DynamicJsonDocument doc(512); {
DynamicJsonDocument doc(512);
doc["actuatorId"] = actuatorId;
doc["deviceId"] = deviceId; doc["actuatorId"] = actuatorId;
doc["status"] = status; doc["deviceId"] = deviceId;
doc["timestamp"] = timestamp; doc["status"] = status;
doc["timestamp"] = timestamp;
String output;
serializeJson(doc, output); String output;
Serial.println(output); serializeJson(doc, output);
return output; Serial.println(output);
} return output;
}
String serializeDevice(const String &deviceId, int groupId, const String &deviceName) {
DynamicJsonDocument doc(512); String serializeDevice(const String &deviceId, int groupId, const String &deviceName)
{
doc["deviceId"] = deviceId; DynamicJsonDocument doc(512);
doc["groupId"] = groupId;
doc["deviceName"] = deviceName; doc["deviceId"] = deviceId;
doc["groupId"] = groupId;
String output; doc["deviceName"] = deviceName;
serializeJson(doc, output);
Serial.println(output); String output;
return output; serializeJson(doc, output);
} Serial.println(output);
return output;
void deserializeSensorValue(HTTPClient &http, int httpResponseCode) { }
if (httpResponseCode > 0) {
Serial.print("HTTP Response code: "); void deserializeSensorValue(HTTPClient &http, int httpResponseCode)
Serial.println(httpResponseCode); {
String responseJson = http.getString(); if (httpResponseCode > 0)
DynamicJsonDocument doc(ESP.getMaxAllocHeap()); {
DeserializationError error = deserializeJson(doc, responseJson); Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
if (error) { String responseJson = http.getString();
Serial.print(F("deserializeJson() failed: ")); DynamicJsonDocument doc(ESP.getMaxAllocHeap());
Serial.println(error.f_str()); DeserializationError error = deserializeJson(doc, responseJson);
return;
} if (error)
{
JsonArray array = doc.as<JsonArray>(); Serial.print(F("deserializeJson() failed: "));
for (JsonObject sensor : array) { Serial.println(error.f_str());
int sensorId = sensor["sensorId"]; return;
String deviceId = sensor["deviceId"]; }
String sensorType = sensor["sensorType"];
String unit = sensor["unit"]; JsonArray array = doc.as<JsonArray>();
int sensorStatus = sensor["sensorStatus"]; for (JsonObject sensor : array)
float temperature = sensor["temperature"]; {
float humidity = sensor["humidity"]; int sensorId = sensor["sensorId"];
float carbonMonoxide = sensor["carbonMonoxide"]; String deviceId = sensor["deviceId"];
float lat = sensor["lat"]; String sensorType = sensor["sensorType"];
float lon = sensor["lon"]; String unit = sensor["unit"];
long timestamp = sensor["timestamp"]; int sensorStatus = sensor["sensorStatus"];
float temperature = sensor["temperature"];
Serial.println("Sensor deserialized:"); float humidity = sensor["humidity"];
Serial.printf(" ID: %d\n Device: %s\n Type: %s\n Unit: %s\n Status: %d\n Temp: %.2f\n Hum: %.2f\n CO: %.2f\n Lat: %.6f\n Lon: %.6f\n Time: %ld\n\n", float carbonMonoxide = sensor["carbonMonoxide"];
sensorId, deviceId.c_str(), sensorType.c_str(), unit.c_str(), sensorStatus, float lat = sensor["lat"];
temperature, humidity, carbonMonoxide, lat, lon, timestamp); float lon = sensor["lon"];
} long timestamp = sensor["timestamp"];
} else {
Serial.print("Error code: "); Serial.println("Sensor deserialized:");
Serial.println(httpResponseCode); Serial.printf(" ID: %d\n Device: %s\n Type: %s\n Unit: %s\n Status: %d\n Temp: %.2f\n Hum: %.2f\n CO: %.2f\n Lat: %.6f\n Lon: %.6f\n Time: %ld\n\n",
} sensorId, deviceId.c_str(), sensorType.c_str(), unit.c_str(), sensorStatus,
} temperature, humidity, carbonMonoxide, lat, lon, timestamp);
}
void deserializeActuatorStatus(HTTPClient &http, int httpResponseCode) { }
if (httpResponseCode > 0) { else
Serial.print("HTTP Response code: "); {
Serial.println(httpResponseCode); Serial.print("Error code: ");
String responseJson = http.getString(); Serial.println(httpResponseCode);
DynamicJsonDocument doc(ESP.getMaxAllocHeap()); }
DeserializationError error = deserializeJson(doc, responseJson); }
if (error) { void deserializeActuatorStatus(HTTPClient &http, int httpResponseCode)
Serial.print(F("deserializeJson() failed: ")); {
Serial.println(error.f_str()); if (httpResponseCode > 0)
return; {
} Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
JsonArray array = doc.as<JsonArray>(); String responseJson = http.getString();
for (JsonObject actuator : array) { DynamicJsonDocument doc(ESP.getMaxAllocHeap());
int actuatorId = actuator["actuatorId"]; DeserializationError error = deserializeJson(doc, responseJson);
String deviceId = actuator["deviceId"];
int status = actuator["status"]; if (error)
long timestamp = actuator["timestamp"]; {
Serial.print(F("deserializeJson() failed: "));
Serial.println("Actuator deserialized:"); Serial.println(error.f_str());
Serial.printf(" ID: %d\n Device: %s\n Status: %d\n Time: %ld\n\n", return;
actuatorId, deviceId.c_str(), status, timestamp); }
}
} else { JsonArray array = doc.as<JsonArray>();
Serial.print("Error code: "); for (JsonObject actuator : array)
Serial.println(httpResponseCode); {
} int actuatorId = actuator["actuatorId"];
} String deviceId = actuator["deviceId"];
int status = actuator["status"];
void deserializeDevice(HTTPClient &http, int httpResponseCode) { long timestamp = actuator["timestamp"];
if (httpResponseCode > 0) {
Serial.print("HTTP Response code: "); Serial.println("Actuator deserialized:");
Serial.println(httpResponseCode); Serial.printf(" ID: %d\n Device: %s\n Status: %d\n Time: %ld\n\n",
String responseJson = http.getString(); actuatorId, deviceId.c_str(), status, timestamp);
DynamicJsonDocument doc(ESP.getMaxAllocHeap()); }
DeserializationError error = deserializeJson(doc, responseJson); }
else
if (error) { {
Serial.print(F("deserializeJson() failed: ")); Serial.print("Error code: ");
Serial.println(error.f_str()); Serial.println(httpResponseCode);
return; }
} }
JsonArray array = doc.as<JsonArray>(); void deserializeDevice(HTTPClient &http, int httpResponseCode)
for (JsonObject device : array) { {
String deviceId = device["deviceId"]; if (httpResponseCode > 0)
int groupId = device["groupId"]; {
String deviceName = device["deviceName"]; Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
Serial.println("Device deserialized:"); String responseJson = http.getString();
Serial.printf(" ID: %s\n Group: %d\n Name: %s\n\n", deviceId.c_str(), groupId, deviceName.c_str()); DynamicJsonDocument doc(ESP.getMaxAllocHeap());
} DeserializationError error = deserializeJson(doc, responseJson);
} else {
Serial.print("Error code: "); if (error)
Serial.println(httpResponseCode); {
} Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
JsonArray array = doc.as<JsonArray>();
for (JsonObject device : array)
{
String deviceId = device["deviceId"];
int groupId = device["groupId"];
String deviceName = device["deviceName"];
Serial.println("Device deserialized:");
Serial.printf(" ID: %s\n Group: %d\n Name: %s\n\n", deviceId.c_str(), groupId, deviceName.c_str());
}
}
else
{
Serial.print("Error code: ");
Serial.println(httpResponseCode);
}
} }

View File

@@ -1,28 +1,34 @@
#include "RestClient.hpp" #include "RestClient.hpp"
HTTPClient httpClient; // HTTP client object HTTPClient httpClient; // HTTP client object
void getRequest(const String url, String &response) void getRequest(const String url, String &response)
{ {
httpClient.begin(url); httpClient.begin(url);
int httpCode = httpClient.GET(); int httpCode = httpClient.GET();
if (httpCode > 0) { if (httpCode > 0)
response = httpClient.getString(); {
} else { response = httpClient.getString();
response = "Error: " + String(httpCode); }
} else
httpClient.end(); {
} response = "Error: " + String(httpCode);
}
void postRequest(const String url, String &payload, String &response) httpClient.end();
{ }
httpClient.begin(url);
httpClient.addHeader("Content-Type", "application/json"); void postRequest(const String url, String &payload, String &response)
int httpCode = httpClient.POST(payload); {
if (httpCode > 0) { httpClient.begin(url);
response = httpClient.getString(); httpClient.addHeader("Content-Type", "application/json");
} else { int httpCode = httpClient.POST(payload);
response = "Error: " + String(httpCode); if (httpCode > 0)
} {
httpClient.end(); response = httpClient.getString();
}
else
{
response = "Error: " + String(httpCode);
}
httpClient.end();
} }

View File

@@ -1,61 +1,62 @@
#include "MqttClient.hpp" #include "MqttClient.hpp"
// MQTT configuration // MQTT configuration
WiFiClient espClient; WiFiClient espClient;
PubSubClient client(espClient); PubSubClient client(espClient);
void OnMqttReceived(char *topic, byte *payload, unsigned int length) void OnMqttReceived(char *topic, byte *payload, unsigned int length)
{ {
Serial.print("Received on "); Serial.print("Received on ");
Serial.print(topic); Serial.print(topic);
Serial.print(": "); Serial.print(": ");
String content = ""; String content = "";
for (size_t i = 0; i < length; i++) { for (size_t i = 0; i < length; i++)
content.concat((char)payload[i]); {
} content.concat((char)payload[i]);
}
Serial.print(content);
Serial.println(); Serial.print(content);
} Serial.println();
}
void InitMqtt(const char * MQTTServerAddress, uint16_t MQTTServerPort)
{ void InitMqtt(const char *MQTTServerAddress, uint16_t MQTTServerPort)
client.setServer(MQTTServerAddress, MQTTServerPort); {
client.setCallback(OnMqttReceived); client.setServer(MQTTServerAddress, MQTTServerPort);
} client.setCallback(OnMqttReceived);
}
// conecta o reconecta al MQTT
// consigue conectar -> suscribe a topic y publica un mensaje // conecta o reconecta al MQTT
// no -> espera 5 segundos // consigue conectar -> suscribe a topic y publica un mensaje
void ConnectMqtt(const char * MQTTClientName) // no -> espera 5 segundos
{ void ConnectMqtt(const char *MQTTClientName)
Serial.print("Starting MQTT connection..."); {
if (client.connect(MQTTClientName)) Serial.print("Starting MQTT connection...");
{ if (client.connect(MQTTClientName))
client.subscribe("hello/world"); {
client.publish("hello/world", "connected"); client.subscribe("hello/world");
} client.publish("hello/world", "connected");
else }
{ else
Serial.print("Failed MQTT connection, rc="); {
Serial.print(client.state()); Serial.print("Failed MQTT connection, rc=");
Serial.println(" try again in 5 seconds"); Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
} delay(5000);
} }
}
// gestiona la comunicación MQTT
// comprueba que el cliente está conectado // gestiona la comunicación MQTT
// no -> intenta reconectar // comprueba que el cliente está conectado
// si -> llama al MQTT loop // no -> intenta reconectar
void HandleMqtt(const char * MQTTClientName) // si -> llama al MQTT loop
{ void HandleMqtt(const char *MQTTClientName)
if (!client.connected()) {
{ if (!client.connected())
ConnectMqtt(MQTTClientName); {
} ConnectMqtt(MQTTClientName);
client.loop(); }
} client.loop();
}

View File

@@ -1,83 +1,86 @@
#include <WifiConnection.hpp> #include <WifiConnection.hpp>
#define PIN_R 12 #define PIN_R 12
#define PIN_G 13 #define PIN_G 13
#define PIN_B 14 #define PIN_B 14
WiFiClient wifiClient; WiFiClient wifiClient;
void setColor(uint8_t r, uint8_t g, uint8_t b) { void setColor(uint8_t r, uint8_t g, uint8_t b)
ledcWrite(0, r); {
ledcWrite(1, g); ledcWrite(0, r);
ledcWrite(2, b); ledcWrite(1, g);
} ledcWrite(2, b);
}
void setupLED() {
ledcAttachPin(PIN_R, 0); void setupLED()
ledcAttachPin(PIN_G, 1); {
ledcAttachPin(PIN_B, 2); ledcSetup(0, 5000, 8);
ledcAttachPin(PIN_R, 0);
ledcSetup(0, 5000, 8);
ledcSetup(1, 5000, 8); ledcSetup(1, 5000, 8);
ledcSetup(2, 5000, 8); ledcAttachPin(PIN_G, 1);
}
ledcSetup(2, 5000, 8);
// hue cycle ledcAttachPin(PIN_B, 2);
void hueCycle(uint8_t pos) { }
uint8_t r = (uint8_t)(sin((pos + 0) * 0.024) * 127 + 128);
uint8_t g = (uint8_t)(sin((pos + 85) * 0.024) * 127 + 128); // hue cycle
uint8_t b = (uint8_t)(sin((pos + 170) * 0.024) * 127 + 128); void hueCycle(uint8_t pos)
setColor(r, g, b); {
} uint8_t r = (uint8_t)(sin((pos + 0) * 0.024) * 127 + 128);
uint8_t g = (uint8_t)(sin((pos + 85) * 0.024) * 127 + 128);
int setupWifi() uint8_t b = (uint8_t)(sin((pos + 170) * 0.024) * 127 + 128);
{ setColor(r, g, b);
setupLED(); }
WiFi.mode(WIFI_STA); int setupWifi()
WiFi.begin(SSID, PASSWORD); {
setupLED();
#ifdef DEBUG
Serial.print("Conectando a la red WiFi: "); WiFi.mode(WIFI_STA);
Serial.print(SSID); WiFi.begin(SSID, PASSWORD);
#endif
#ifdef DEBUG
int hue = 0; Serial.print("Conectando a la red WiFi: ");
uint32_t start = millis(); Serial.print(SSID);
const uint32_t timeout = 15000; #endif
while (WiFi.status() != WL_CONNECTED && millis() - start < timeout) int hue = 0;
{ uint32_t start = millis();
hueCycle(hue++); const uint32_t timeout = 15000;
#ifdef DEBUG while (WiFi.status() != WL_CONNECTED && millis() - start < timeout)
Serial.print("."); {
#endif hueCycle(hue++);
delay(30); #ifdef DEBUG
} Serial.print(".");
#endif
if (WiFi.status() == WL_CONNECTED)
{ delay(30);
setColor(0, 255, 0); }
#ifdef DEBUG if (WiFi.status() == WL_CONNECTED)
Serial.println("Conectado a la red WiFi"); {
Serial.print("Dirección IP: "); setColor(0, 255, 0);
Serial.println(WiFi.localIP());
#endif #ifdef DEBUG
Serial.println("Conectado a la red WiFi");
return 0; Serial.print("Dirección IP: ");
} Serial.println(WiFi.localIP());
else #endif
{
setColor(255, 0, 0); return 0;
}
#ifdef DEBUG else
Serial.println("No se pudo conectar a la red WiFi"); {
#endif setColor(255, 0, 0);
return 1; #ifdef DEBUG
} Serial.println("No se pudo conectar a la red WiFi");
} #endif
return 1;
}
}

View File

@@ -1,34 +1,34 @@
#include "BME280.hpp" #include "BME280.hpp"
BME280I2C bme; BME280I2C bme;
void BME280_Init() void BME280_Init()
{ {
Wire.setPins(21, 22); Wire.setPins(21, 22);
Wire.begin(); Wire.begin();
BME280I2C::Settings settings( BME280I2C::Settings settings(
BME280I2C::OSR::OSR_X1, BME280I2C::OSR::OSR_X1,
BME280I2C::OSR::OSR_X1, BME280I2C::OSR::OSR_X1,
BME280I2C::OSR::OSR_X1, BME280I2C::OSR::OSR_X1,
BME280I2C::Mode::Mode_Forced, // modo forzado BME280I2C::Mode::Mode_Forced, // modo forzado
BME280I2C::StandbyTime::StandbyTime_1000ms, BME280I2C::StandbyTime::StandbyTime_1000ms,
BME280I2C::Filter::Filter_16, BME280I2C::Filter::Filter_16,
BME280I2C::SpiEnable::SpiEnable_False, BME280I2C::SpiEnable::SpiEnable_False,
BME280I2C::I2CAddr::I2CAddr_0x76 // dirección I2C del BME280 BME280I2C::I2CAddr::I2CAddr_0x76 // dirección I2C del BME280
); );
bme.setSettings(settings); bme.setSettings(settings);
while (!bme.begin()); while (!bme.begin())
} ;
}
BME280Data_t BME280_Read()
{ BME280Data_t BME280_Read()
float p, t, h; {
BME280::TempUnit tUnit(BME280::TempUnit_Celsius); float p, t, h;
BME280::PresUnit pUnit(BME280::PresUnit_Pa); BME280::TempUnit tUnit(BME280::TempUnit_Celsius);
bme.read(p, t, h, tUnit, pUnit); BME280::PresUnit pUnit(BME280::PresUnit_Pa);
return {p, t, h}; bme.read(p, t, h, tUnit, pUnit);
} return {p, t, h};
}

View File

@@ -3,7 +3,7 @@
const uint32_t DEVICE_ID = getChipID(); const uint32_t DEVICE_ID = getChipID();
const char ALL_VEHICLES[] = "Todo tipo de vehiculos"; const char ALL_VEHICLES[] = "Todo tipo de vehiculos";
const char ELECTRIC_VEHICLES[] = "Solo vehiculos electricos/hibridos"; const char ELECTRIC_VEHICLES[] = "Solo vehiculos electricos/hibridos";
const char* currentMessage = nullptr; const char *currentMessage = nullptr;
TaskTimer matrixTimer{0, 25}; TaskTimer matrixTimer{0, 25};
TaskTimer globalTimer{0, 60000}; TaskTimer globalTimer{0, 60000};
@@ -29,7 +29,7 @@ void setup()
GPS_Init(); GPS_Init();
Serial.println("Sensor GPS inicializado"); Serial.println("Sensor GPS inicializado");
MQ7_Init(); MQ7_Init();
Serial.println("Sensor MQ7 inicializado"); Serial.println("Sensor MQ7 inicializado");
MAX7219_Init(); MAX7219_Init();
Serial.println("Display inicializado"); Serial.println("Display inicializado");
@@ -40,8 +40,10 @@ void loop()
{ {
uint32_t now = millis(); uint32_t now = millis();
if (now - matrixTimer.lastRun >= matrixTimer.interval) { if (now - matrixTimer.lastRun >= matrixTimer.interval)
if (MAX7219_Animate()) { {
if (MAX7219_Animate())
{
MAX7219_ResetAnimation(); MAX7219_ResetAnimation();
} }
matrixTimer.lastRun = now; matrixTimer.lastRun = now;
@@ -52,10 +54,10 @@ void loop()
readBME280(); readBME280();
readGPS(); readGPS();
readMQ7(); readMQ7();
#ifdef DEBUG #ifdef DEBUG
printAllData(); printAllData();
#endif #endif
globalTimer.lastRun = now; globalTimer.lastRun = now;
} }
@@ -69,11 +71,15 @@ void readMQ7()
AirQualityStatus newStatus = (mq7Data.co >= CO_THRESHOLD) ? BAD : GOOD; AirQualityStatus newStatus = (mq7Data.co >= CO_THRESHOLD) ? BAD : GOOD;
if (newStatus != currentAirStatus) { if (newStatus != currentAirStatus)
{
currentAirStatus = newStatus; currentAirStatus = newStatus;
if (currentAirStatus == BAD) { if (currentAirStatus == BAD)
{
writeMatrix(ELECTRIC_VEHICLES); writeMatrix(ELECTRIC_VEHICLES);
} else { }
else
{
writeMatrix(ALL_VEHICLES); writeMatrix(ALL_VEHICLES);
} }
} }
@@ -89,15 +95,16 @@ void readGPS()
gpsData = GPS_Read(); gpsData = GPS_Read();
} }
void writeMatrix(const char* message) void writeMatrix(const char *message)
{ {
if (currentMessage == message) return; if (currentMessage == message)
return;
currentMessage = message; currentMessage = message;
#ifdef DEBUG #ifdef DEBUG
Serial.println("Escribiendo en el display..."); Serial.println("Escribiendo en el display...");
#endif #endif
MAX7219_DisplayText(message, PA_LEFT, 50, 0); MAX7219_DisplayText(message, PA_LEFT, 50, 0);
} }
@@ -105,17 +112,28 @@ void printAllData()
{ {
Serial.println("---------------------"); Serial.println("---------------------");
Serial.print("ID: "); Serial.println(DEVICE_ID, HEX); Serial.print("ID: ");
Serial.println(DEVICE_ID, HEX);
Serial.print("Presión: "); Serial.print(bme280Data.pressure / 100); Serial.println(" hPa"); Serial.print("Presión: ");
Serial.print("Temperatura: "); Serial.print(bme280Data.temperature); Serial.println(" °C"); Serial.print(bme280Data.pressure / 100);
Serial.print("Humedad: "); Serial.print(bme280Data.humidity); Serial.println(" %"); Serial.println(" hPa");
Serial.print("Temperatura: ");
Serial.print(bme280Data.temperature);
Serial.println(" °C");
Serial.print("Humedad: ");
Serial.print(bme280Data.humidity);
Serial.println(" %");
Serial.print("Latitud: "); Serial.println(gpsData.lat); Serial.print("Latitud: ");
Serial.print("Longitud: "); Serial.println(gpsData.lon); Serial.println(gpsData.lat);
Serial.print("Longitud: ");
Serial.println(gpsData.lon);
Serial.print("CO: "); Serial.println(mq7Data.co); Serial.print("CO: ");
Serial.print("D0: "); Serial.println(mq7Data.threshold); Serial.println(mq7Data.co);
Serial.print("D0: ");
Serial.println(mq7Data.threshold);
} }
uint32_t getChipID() uint32_t getChipID()
@@ -125,8 +143,9 @@ uint32_t getChipID()
{ {
chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i; chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
} }
#ifdef DEBUG #ifdef DEBUG
Serial.print("Chip ID: "); Serial.println(chipId, HEX); Serial.print("Chip ID: ");
#endif Serial.println(chipId, HEX);
#endif
return chipId; return chipId;
} }