Moved PC to a plugin directory
This commit is contained in:
parent
fccc6a3609
commit
47afc78ee4
12 changed files with 226 additions and 90 deletions
27
plugins/hal-powerchallenge/build.xml
Normal file
27
plugins/hal-powerchallenge/build.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project name="Hal-Power;Challenge Plugin" >
|
||||
|
||||
<!-- ________________________ PROPERTIES AND SETTINGS ________________________ -->
|
||||
|
||||
<!--plugin specific properties-->
|
||||
<property name="releaseJar" value="hal-powerchallenge.jar" />
|
||||
|
||||
<!--common properties-->
|
||||
<property name="root" value="." />
|
||||
<property name="srcDir" value="${root}/src" />
|
||||
<property name="testDir" value="${root}/test" />
|
||||
<property name="libDir" value="${root}/lib" />
|
||||
<property name="resourceDir" value="${root}/resource" />
|
||||
|
||||
<property name="buildRoot" value="${root}/build" />
|
||||
<property name="compileDir" value="${buildRoot}/production" />
|
||||
<property name="compileTestDir" value="${buildRoot}/test" />
|
||||
<property name="releaseDir" value="${buildRoot}/release" />
|
||||
<property name="reportsDir" value="../../${buildRoot}/reports" /> <!-- Use Hal reports folder -->
|
||||
|
||||
<!-- ________________________ TARGETS ________________________ -->
|
||||
|
||||
<import file="../../build_plugin.xml"/>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Ziver Koc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.powerchallenge.daemon;
|
||||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.plugin.powerchallenge.daemon.PCDataSynchronizationDaemon.PeerDataRspDTO;
|
||||
import se.hal.plugin.powerchallenge.daemon.PCDataSynchronizationDaemon.SensorDTO;
|
||||
import se.hal.plugin.powerchallenge.daemon.PCDataSynchronizationDaemon.SensorDataDTO;
|
||||
import se.hal.plugin.powerchallenge.daemon.PCDataSynchronizationDaemon.SensorDataListDTO;
|
||||
import se.hal.intf.HalDaemon;
|
||||
import se.hal.page.HalAlertManager;
|
||||
import se.hal.page.HalAlertManager.AlertTTL;
|
||||
import se.hal.page.HalAlertManager.HalAlert;
|
||||
import se.hal.struct.Sensor;
|
||||
import se.hal.struct.User;
|
||||
import zutil.db.DBConnection;
|
||||
import zutil.log.LogUtil;
|
||||
import zutil.parser.json.JSONParser;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PCDataSynchronizationClient implements HalDaemon {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
private static final long SYNC_INTERVAL = 5 * 60 * 1000; // 5 min
|
||||
|
||||
|
||||
@Override
|
||||
public void initiate(ScheduledExecutorService executor){
|
||||
executor.scheduleAtFixedRate(this, 10000, SYNC_INTERVAL, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
DBConnection db = HalContext.getDB();
|
||||
List<User> users = User.getExternalUsers(db);
|
||||
for(User user : users){
|
||||
if(user.getHostname() == null){
|
||||
logger.fine("Hostname not defined for user: "+ user.getUsername());
|
||||
continue;
|
||||
}
|
||||
logger.fine("Synchronizing user: "+ user.getUsername() +" ("+user.getHostname()+":"+user.getPort()+")");
|
||||
try (Socket s = new Socket(user.getHostname(), user.getPort());){
|
||||
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
|
||||
ObjectInputStream in = new ObjectInputStream(s.getInputStream());
|
||||
|
||||
// Check server protocol version
|
||||
int version = in.readInt();
|
||||
if(version != PCDataSynchronizationDaemon.PROTOCOL_VERSION){
|
||||
logger.warning("Protocol version do not match, skipping user. " +
|
||||
"(local v"+PCDataSynchronizationDaemon.PROTOCOL_VERSION+" != remote v"+version+")");
|
||||
out.writeObject(null); // Tell server we are disconnecting
|
||||
out.flush();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Request peer data
|
||||
out.writeObject(new PeerDataReqDTO());
|
||||
PeerDataRspDTO peerData = (PeerDataRspDTO) in.readObject();
|
||||
user.setUsername(peerData.username);
|
||||
user.setEmail(peerData.email);
|
||||
user.setAddress(peerData.address);
|
||||
user.save(db);
|
||||
|
||||
for(SensorDTO sensorDTO : peerData.sensors){
|
||||
try { // We might not have the sensor plugin installed
|
||||
Sensor sensor = Sensor.getExternalSensor(db, user, sensorDTO.sensorId);
|
||||
if(sensor == null) { // new sensor
|
||||
sensor = new Sensor();
|
||||
logger.fine("Created new external sensor with external_id: "+ sensorDTO.sensorId);
|
||||
}
|
||||
else
|
||||
logger.fine("Updating external sensor with id: "+ sensor.getId() +" and external_id: "+ sensor.getExternalId());
|
||||
sensor.setExternalId(sensorDTO.sensorId);
|
||||
sensor.setName(sensorDTO.name);
|
||||
sensor.setType(sensorDTO.type);
|
||||
sensor.setUser(user);
|
||||
|
||||
sensor.getDeviceConfigurator().setValues(JSONParser.read(sensorDTO.config)).applyConfiguration();
|
||||
sensor.save(db);
|
||||
} catch (Exception e){
|
||||
logger.warning("Unable to register external sensor: " +
|
||||
"name="+sensorDTO.name+", type="+ sensorDTO.type);
|
||||
}
|
||||
}
|
||||
|
||||
// Request sensor data
|
||||
List<Sensor> sensors = Sensor.getSensors(db, user);
|
||||
for(Sensor sensor : sensors){
|
||||
if(sensor.isSynced()) {
|
||||
SensorDataReqDTO req = new SensorDataReqDTO();
|
||||
req.sensorId = sensor.getExternalId();
|
||||
req.offsetSequenceId = Sensor.getHighestSequenceId(sensor.getId());
|
||||
req.aggregationVersion = sensor.getAggregationVersion();
|
||||
out.writeObject(req);
|
||||
|
||||
SensorDataListDTO dataList = (SensorDataListDTO) in.readObject();
|
||||
if(dataList.aggregationVersion != sensor.getAggregationVersion()){
|
||||
logger.fine("The peer has modified its aggregated data, clearing aggregate data. oldAggregationVersion:"+sensor.getAggregationVersion()+" , newAggregationVersion:"+dataList.aggregationVersion);
|
||||
|
||||
//clear old aggregated data for sensor
|
||||
sensor.clearAggregatedData(db);
|
||||
|
||||
//save new aggregationVersion
|
||||
sensor.setAggregationVersion(dataList.aggregationVersion);
|
||||
sensor.save(db);
|
||||
}
|
||||
for (SensorDataDTO data : dataList) {
|
||||
PreparedStatement stmt = db.getPreparedStatement("INSERT INTO sensor_data_aggr(sensor_id, sequence_id, timestamp_start, timestamp_end, data, confidence) VALUES(?, ?, ?, ?, ?, ?)");
|
||||
stmt.setLong(1, sensor.getId());
|
||||
stmt.setLong(2, data.sequenceId);
|
||||
stmt.setLong(3, data.timestampStart);
|
||||
stmt.setLong(4, data.timestampEnd);
|
||||
stmt.setInt(5, data.data);
|
||||
stmt.setFloat(6, data.confidence);
|
||||
DBConnection.exec(stmt);
|
||||
}
|
||||
logger.fine("Stored " + dataList.size() + " entries for sensor " + sensor.getId() + " with offset "+ req.offsetSequenceId +" from " + user.getUsername());
|
||||
}
|
||||
else
|
||||
logger.fine("Sensor not marked for syncing, skipping sensor id: " + sensor.getId());
|
||||
}
|
||||
out.writeObject(null); // Tell server we are disconnecting
|
||||
|
||||
} catch (NoRouteToHostException|UnknownHostException|ConnectException e) {
|
||||
logger.warning("Unable to connect to "+ user.getHostname()+":"+user.getPort() +", "+ e.getMessage());
|
||||
HalAlertManager.getInstance().addAlert(new HalAlert(HalAlertManager.AlertLevel.WARNING,
|
||||
"Unable to connect to user with host: "+user.getHostname(), AlertTTL.DISMISSED));
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.log(Level.SEVERE, "Thread has crashed", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////// DTO ///////////////////////
|
||||
|
||||
/**
|
||||
* Request Peer information and isAvailable sensors
|
||||
*/
|
||||
protected static class PeerDataReqDTO implements Serializable{}
|
||||
|
||||
/**
|
||||
* Request aggregate data for a specific sensor and offset
|
||||
*/
|
||||
protected static class SensorDataReqDTO implements Serializable{
|
||||
private static final long serialVersionUID = -9066734025245139989L;
|
||||
|
||||
public long sensorId;
|
||||
public long offsetSequenceId; // highest known sequence id
|
||||
public long aggregationVersion = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Ziver Koc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.powerchallenge.daemon;
|
||||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.plugin.powerchallenge.daemon.PCDataSynchronizationClient.PeerDataReqDTO;
|
||||
import se.hal.plugin.powerchallenge.daemon.PCDataSynchronizationClient.SensorDataReqDTO;
|
||||
import se.hal.intf.HalDaemon;
|
||||
import se.hal.struct.Sensor;
|
||||
import se.hal.struct.User;
|
||||
import zutil.db.DBConnection;
|
||||
import zutil.db.SQLResultHandler;
|
||||
import zutil.log.LogUtil;
|
||||
import zutil.net.threaded.ThreadedTCPNetworkServer;
|
||||
import zutil.net.threaded.ThreadedTCPNetworkServerThread;
|
||||
import zutil.parser.json.JSONWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.Socket;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PCDataSynchronizationDaemon extends ThreadedTCPNetworkServer implements HalDaemon {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
public static final int PROTOCOL_VERSION = 5; // Increment for protocol changes
|
||||
|
||||
|
||||
public PCDataSynchronizationDaemon() {
|
||||
super(HalContext.getIntegerProperty("sync_port"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initiate(ScheduledExecutorService executor){
|
||||
this.start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected ThreadedTCPNetworkServerThread getThreadInstance(Socket s) {
|
||||
try {
|
||||
return new DataSynchronizationDaemonThread(s);
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, "Unable to create DataSynchronizationDaemonThread", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private class DataSynchronizationDaemonThread implements ThreadedTCPNetworkServerThread{
|
||||
private Socket s;
|
||||
private ObjectOutputStream out;
|
||||
private ObjectInputStream in;
|
||||
|
||||
|
||||
public DataSynchronizationDaemonThread(Socket s) throws IOException{
|
||||
this.s = s;
|
||||
this.out = new ObjectOutputStream(s.getOutputStream());
|
||||
this.in = new ObjectInputStream(s.getInputStream());
|
||||
}
|
||||
|
||||
|
||||
public void run(){
|
||||
logger.fine("User connected: "+ s.getInetAddress().getHostName());
|
||||
DBConnection db = HalContext.getDB();
|
||||
|
||||
try {
|
||||
Object obj = null;
|
||||
out.writeInt(PROTOCOL_VERSION); // send our protocol version to client
|
||||
out.flush();
|
||||
while((obj = in.readObject()) != null){
|
||||
if(obj instanceof PeerDataReqDTO){
|
||||
logger.fine("Client requesting peer data");
|
||||
PeerDataRspDTO rsp = new PeerDataRspDTO();
|
||||
User localUser = User.getLocalUser(db);
|
||||
rsp.username = localUser.getUsername();
|
||||
rsp.email = localUser.getEmail();
|
||||
rsp.address = localUser.getAddress();
|
||||
|
||||
rsp.sensors = new ArrayList<>();
|
||||
for(Sensor sensor : Sensor.getLocalSensors(db)){
|
||||
if(sensor.isSynced()) {
|
||||
SensorDTO dto = new SensorDTO();
|
||||
dto.sensorId = sensor.getId();
|
||||
dto.name = sensor.getName();
|
||||
dto.type = sensor.getType();
|
||||
dto.config = JSONWriter.toString(sensor.getDeviceConfigurator().getValuesAsNode());
|
||||
rsp.sensors.add(dto);
|
||||
}
|
||||
}
|
||||
out.writeObject(rsp);
|
||||
}
|
||||
if(obj instanceof SensorDataReqDTO){
|
||||
SensorDataReqDTO req = (SensorDataReqDTO) obj;
|
||||
Sensor sensor = Sensor.getSensor(db, req.sensorId);
|
||||
if(sensor.isSynced()) {
|
||||
PreparedStatement stmt = db.getPreparedStatement("SELECT * FROM sensor_data_aggr WHERE sensor_id == ? AND sequence_id > ?");
|
||||
stmt.setLong(1, sensor.getId());
|
||||
logger.fine("Client requesting sensor data: sensorId: " + req.sensorId + ", offset: " + req.offsetSequenceId + ", " + req.aggregationVersion);
|
||||
if(req.aggregationVersion != sensor.getAggregationVersion()){
|
||||
logger.fine("The requested aggregation version does not match the local version: " + sensor.getAggregationVersion() + ". Will re-send all aggregated data.");
|
||||
stmt.setLong(2, 0); //0 since we want to re-send all data to the peer
|
||||
}else{
|
||||
stmt.setLong(2, req.offsetSequenceId);
|
||||
}
|
||||
|
||||
SensorDataListDTO rsp = DBConnection.exec(stmt, new SQLResultHandler<SensorDataListDTO>() {
|
||||
@Override
|
||||
public SensorDataListDTO handleQueryResult(Statement stmt, ResultSet result) throws SQLException {
|
||||
SensorDataListDTO list = new SensorDataListDTO();
|
||||
while (result.next()) {
|
||||
SensorDataDTO data = new SensorDataDTO();
|
||||
data.sequenceId = result.getLong("sequence_id");
|
||||
data.timestampStart = result.getLong("timestamp_start");
|
||||
data.timestampEnd = result.getLong("timestamp_end");
|
||||
data.data = result.getInt("data");
|
||||
data.confidence = result.getFloat("confidence");
|
||||
list.add(data);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
});
|
||||
rsp.aggregationVersion = sensor.getAggregationVersion();
|
||||
logger.fine("Sending " + rsp.size() + " sensor data items to client");
|
||||
out.writeObject(rsp);
|
||||
}
|
||||
else{
|
||||
logger.warning("Client requesting non synced sensor data: sensorId: " + req.sensorId + ", offset: " + req.offsetSequenceId);
|
||||
SensorDataListDTO rsp = new SensorDataListDTO();
|
||||
out.writeObject(rsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
s.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, null, e);
|
||||
}
|
||||
logger.fine("User disconnected: "+ s.getInetAddress().getHostName());
|
||||
}
|
||||
}
|
||||
|
||||
/////////////// DTO ///////////////////////
|
||||
protected static class PeerDataRspDTO implements Serializable{
|
||||
public String username;
|
||||
public String email;
|
||||
public String address;
|
||||
|
||||
public ArrayList<SensorDTO> sensors;
|
||||
}
|
||||
protected static class SensorDTO implements Serializable{
|
||||
public long sensorId;
|
||||
public String name;
|
||||
public String type;
|
||||
public String config;
|
||||
}
|
||||
|
||||
|
||||
protected static class SensorDataListDTO extends ArrayList<SensorDataDTO> implements Serializable{
|
||||
private static final long serialVersionUID = -5701618637734020691L;
|
||||
|
||||
public long aggregationVersion = 0;
|
||||
}
|
||||
protected static class SensorDataDTO implements Serializable{
|
||||
private static final long serialVersionUID = 8494331502087736809L;
|
||||
|
||||
public long sequenceId;
|
||||
public long timestampStart;
|
||||
public long timestampEnd;
|
||||
public int data;
|
||||
public float confidence;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Ziver Koc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.powerchallenge.page;
|
||||
|
||||
import se.hal.intf.HalWebPage;
|
||||
import zutil.io.file.FileUtil;
|
||||
import zutil.parser.Templator;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PCHeatMapWebPage extends HalWebPage {
|
||||
private static final String TEMPLATE = "resource/web/pc_heatmap.tmpl";
|
||||
|
||||
|
||||
public PCHeatMapWebPage() {
|
||||
super("pc_heatmap");
|
||||
super.getRootNav().createSubNav("Sensors").createSubNav(this.getId(), "Heatmap").setWeight(60);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Templator httpRespond(
|
||||
Map<String, Object> session,
|
||||
Map<String, String> cookie,
|
||||
Map<String, String> request)
|
||||
throws Exception{
|
||||
|
||||
Templator tmpl = new Templator(FileUtil.find(TEMPLATE));
|
||||
return tmpl;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Ziver Koc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.powerchallenge.page;
|
||||
|
||||
import se.hal.HalContext;
|
||||
import se.hal.intf.HalWebPage;
|
||||
import se.hal.struct.Sensor;
|
||||
import se.hal.struct.User;
|
||||
import zutil.db.DBConnection;
|
||||
import zutil.io.file.FileUtil;
|
||||
import zutil.parser.Templator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class PCOverviewWebPage extends HalWebPage {
|
||||
private static final String TEMPLATE = "resource/web/pc_overview.tmpl";
|
||||
|
||||
public PCOverviewWebPage() {
|
||||
super("pc_overview");
|
||||
super.getRootNav().createSubNav("Sensors").createSubNav(this.getId(), "Power;Challenge").setWeight(50);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Templator httpRespond (
|
||||
Map<String, Object> session,
|
||||
Map<String, String> cookie,
|
||||
Map<String, String> request)
|
||||
throws Exception {
|
||||
|
||||
DBConnection db = HalContext.getDB();
|
||||
List<Sensor> sensors = Sensor.getSensors(db);
|
||||
|
||||
Templator tmpl = new Templator(FileUtil.find(TEMPLATE));
|
||||
tmpl.set("users", User.getUsers(db));
|
||||
tmpl.set("sensors", sensors);
|
||||
|
||||
return tmpl;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": 1.0,
|
||||
"name": "Hal-Power;Challenge",
|
||||
"interfaces": [
|
||||
{"se.hal.intf.HalHttpPage": "se.hal.plugin.powerchallenge.page.PCOverviewHttpPage"},
|
||||
{"se.hal.intf.HalHttpPage": "se.hal.plugin.powerchallenge.page.PCHeatMapHttpPage"},
|
||||
|
||||
{"se.hal.intf.HalDaemon": "se.hal.plugin.powerchallenge.daemon.PCDataSynchronizationClient"},
|
||||
{"se.hal.intf.HalDaemon": "se.hal.plugin.powerchallenge.daemon.PCDataSynchronizationDaemon"}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue