Implemented reporting and storing of raw data

Former-commit-id: db8352f02b4a703698c69618a8af6036d78f5b1d
This commit is contained in:
Ziver Koc 2016-01-04 22:50:26 +01:00
parent 2c59ae5693
commit d117e344c2
25 changed files with 271 additions and 141 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
/hal.db*
/build/
/lib/Zutil.jar
/tellstick.conf

View file

@ -1,15 +1,16 @@
package se.koc.hal;
import se.koc.hal.intf.HalEvent;
import se.koc.hal.intf.HalEventController;
import se.koc.hal.intf.HalSensor;
import se.koc.hal.intf.HalSensorController;
import se.koc.hal.intf.*;
import se.koc.hal.plugin.tellstick.protocols.Oregon0x1A2D;
import se.koc.hal.struct.Event;
import se.koc.hal.struct.Sensor;
import zutil.db.DBConnection;
import zutil.log.LogUtil;
import zutil.plugin.PluginData;
import zutil.plugin.PluginManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -20,7 +21,7 @@ import java.util.logging.Logger;
/**
* This class manages all SensorController and EventController objects
*/
public class ControllerManager {
public class ControllerManager implements HalSensorReportListener, HalEventReportListener {
private static final Logger logger = LogUtil.getLogger();
private static ControllerManager instance;
@ -75,6 +76,38 @@ public class ControllerManager {
return detectedSensors;
}
@Override
public void reportReceived(HalSensor sensorData) {
try{
DBConnection db = HalContext.getDB();
Sensor sensor = null;
for (Sensor s : registeredSensors) {
if (sensorData.equals(s.getSensorData())) {
sensor = s;
sensor.setSensorData(sensorData); // Set the latest data
break;
}
}
if (sensor != null) {
PreparedStatement stmt =
db.getPreparedStatement("INSERT INTO sensor_data_raw (timestamp, event_id, data) VALUES(?, ?, ?)");
stmt.setLong(1, sensorData.getTimestamp());
stmt.setLong(2, sensor.getId());
stmt.setDouble(3, sensorData.getData());
db.exec(stmt);
logger.finest("Received report from sensor: "+ sensorData);
}
else { // unknown sensor
if(!detectedSensors.contains(sensorData)) {
logger.finest("Received report from unregistered sensor: "+ sensorData);
detectedSensors.add(sensorData);
}
}
}catch (SQLException e){
logger.log(Level.WARNING, "Unable to store sensor report", e);
}
}
//////////////////////////////// EVENTS ///////////////////////////////////
@ -105,6 +138,38 @@ public class ControllerManager {
return detectedEvents;
}
@Override
public void reportReceived(HalEvent eventData) {
try {
DBConnection db = HalContext.getDB();
Event event = null;
for (Event e : registeredEvents) {
if (eventData.equals(e.getEventData())) {
event = e;
event.setEventData(eventData); // Set the latest data
break;
}
}
if (event != null) {
PreparedStatement stmt =
db.getPreparedStatement("INSERT INTO event_data_raw (timestamp, event_id, data) VALUES(?, ?, ?)");
stmt.setLong(1, eventData.getTimestamp());
stmt.setLong(2, event.getId());
stmt.setDouble(3, eventData.getData());
db.exec(stmt);
logger.finest("Received report from event: "+ eventData);
}
else { // unknown sensor
if(!detectedEvents.contains(eventData)) {
logger.finest("Received report from unregistered event: "+ eventData);
detectedEvents.add(eventData);
}
}
}catch (SQLException e){
logger.log(Level.WARNING, "Unable to store event report", e);
}
}
/////////////////////////////// GENERAL ///////////////////////////////////
@ -117,6 +182,11 @@ public class ControllerManager {
logger.fine("Instantiating new controller: " + c.getName());
try {
controller = c.newInstance();
if(controller instanceof HalSensorController)
((HalSensorController) controller).setListener(this);
if(controller instanceof HalEventController)
((HalEventController) controller).setListener(this);
controllerMap.put(c, controller);
} catch (Exception e){
logger.log(Level.SEVERE, "Unable to instantiate controller: "+c.getName(), e);
@ -169,4 +239,5 @@ public class ControllerManager {
public static ControllerManager getInstance(){
return instance;
}
}

View file

@ -4,10 +4,6 @@ import se.koc.hal.bot.AliceBot;
import se.koc.hal.intf.HalBot;
import se.koc.hal.intf.HalSpeachToText;
import se.koc.hal.intf.HalTextToSpeach;
import se.koc.hal.plugin.tellstick.TellstickChangeListener;
import se.koc.hal.plugin.tellstick.TellstickProtocol;
import se.koc.hal.plugin.tellstick.TellstickSerialComm;
import se.koc.hal.plugin.tellstick.protocols.NexaSelfLearning;
import se.koc.hal.struct.SwitchEvent;
import se.koc.hal.stt.ManualSTTClient;
import se.koc.hal.tts.MaryRemoteTTSClient;

View file

@ -27,7 +27,7 @@ public class HalContext {
private static final String DEFAULT_DB_FILE = "hal-default.db";
// Variables
private static DBConnection db;
private static DBConnection db; // TODO: Should probably be a db pool as we have multiple threads accessing the DB
private static Properties defaultFileConf;
private static Properties fileConf;

View file

@ -7,6 +7,16 @@ import zutil.parser.DataNode;
*/
public interface HalEvent {
public Class<? extends HalEventController> getController();
long getTimestamp();
double getData();
Class<? extends HalEventController> getEventController();
/**
* This method needs to be implemented.
* NOTE: it should not compare data and timestamp, only static or unique data for the event type.
*/
boolean equals(Object obj);
}

View file

@ -1,7 +1,5 @@
package se.koc.hal.intf;
import se.koc.hal.struct.Event;
/**
* Created by Ziver on 2015-12-15.
*/
@ -30,11 +28,7 @@ public interface HalEventController {
/**
* Set a listener that will receive all reports from the the registered Events
*/
void setListener(EventReportListener listener);
interface EventReportListener{
void reportReceived(HalEvent s); //TODO: rename, use a better name
}
void setListener(HalEventReportListener listener);
/**

View file

@ -0,0 +1,7 @@
package se.koc.hal.intf;
public interface HalEventReportListener {
void reportReceived(HalEvent e);
}

View file

@ -12,10 +12,17 @@ public interface HalSensor {
}
long getTimestamp();
double getData();
AggregationMethod getAggregationMethod();
Class<? extends HalSensorController> getController();
Class<? extends HalSensorController> getSensorController();
/**
* This method needs to be implemented.
* NOTE: it should not compare data and timestamp, only static or unique data for the event type.
*/
boolean equals(Object obj);
}

View file

@ -1,7 +1,5 @@
package se.koc.hal.intf;
import se.koc.hal.struct.Sensor;
/**
* Created by Ziver on 2015-12-15.
*/
@ -26,11 +24,7 @@ public interface HalSensorController {
/**
* Set a listener that will receive all reports from the the registered Sensors
*/
void setListener(SensorReportListener listener);
interface SensorReportListener{
void reportReceived(HalSensor s);
}
void setListener(HalSensorReportListener listener);
/**

View file

@ -0,0 +1,7 @@
package se.koc.hal.intf;
public interface HalSensorReportListener {
void reportReceived(HalSensor s);
}

View file

@ -58,7 +58,7 @@ public class PCConfigureHttpPage extends HalHttpPage {
sensor = new Sensor();
sensor.setName(request.get("name"));
sensor.setType(request.get("type"));
sensor.setConfig(request.get("config"));
//sensor.setConfig(request.get("config"));
sensor.setUser(localUser);
sensor.setSynced(true);
sensor.save(db);
@ -67,7 +67,7 @@ public class PCConfigureHttpPage extends HalHttpPage {
if(sensor != null){
sensor.setName(request.get("name"));
sensor.setType(request.get("type"));
sensor.setConfig(request.get("config"));
//sensor.setConfig(request.get("config"));
sensor.save(db);
}
break;

View file

@ -1,31 +0,0 @@
/*
* Copyright (c) 2015 Ziver
*
* 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.koc.hal.plugin.tellstick;
/**
* Created by Ziver on 2015-05-08.
*/
public interface TellstickChangeListener {
public void stateChange(TellstickProtocol protocol);
}

View file

@ -22,14 +22,47 @@
package se.koc.hal.plugin.tellstick;
import se.koc.hal.intf.HalEventController;
import se.koc.hal.intf.HalSensorController;
/**
* Created by Ziver on 2015-02-18.
*/
public interface TellstickProtocol {
public abstract class TellstickProtocol {
public String encode();
public void decode(byte[] data);
private String protocol;
private String model;
private long timestamp = -1;
public String getProtocolName();
public String getModelName();
public TellstickProtocol(String protocol, String model){
this.protocol = protocol;
this.model = model;
}
public String getProtocolName(){
return protocol;
}
public String getModelName(){
return model;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public Class<? extends HalEventController> getEventController() {
return TellstickSerialComm.class;
}
public Class<? extends HalSensorController> getSensorController() {
return TellstickSerialComm.class;
}
public abstract String encode();
public abstract void decode(byte[] data);
}

View file

@ -23,14 +23,15 @@
package se.koc.hal.plugin.tellstick;
import com.fazecast.jSerialComm.SerialPort;
import se.koc.hal.intf.HalSensor;
import se.koc.hal.intf.HalSensorController;
import se.koc.hal.intf.*;
import zutil.io.file.FileUtil;
import zutil.log.InputStreamLogger;
import zutil.log.LogUtil;
import zutil.log.OutputStreamLogger;
import zutil.struct.TimedHashSet;
import java.io.*;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -40,7 +41,7 @@ import java.util.logging.Logger;
* This version of the TwoWaySerialComm example makes use of the
* SerialPortEventListener to avoid polling.
*/
public class TellstickSerialComm implements Runnable, HalSensorController {
public class TellstickSerialComm implements Runnable, HalSensorController, HalEventController {
private static final long TRANSMISSION_UNIQUENESS_TTL = 300; // milliseconds
private static final Logger logger = LogUtil.getLogger();
@ -50,13 +51,27 @@ public class TellstickSerialComm implements Runnable, HalSensorController {
private TimedHashSet set; // To check for retransmissions
private TellstickParser parser;
private TellstickChangeListener listener;
private HalSensorReportListener sensorListener;
private HalEventReportListener eventListener;
private int registeredObjects;
public TellstickSerialComm() throws Exception {
set = new TimedHashSet(TRANSMISSION_UNIQUENESS_TTL);
parser = new TellstickParser();
connect("COM6");
registeredObjects = 0;
// Read properties
Properties prop = new Properties();
prop.setProperty("com_port", "COM6"); // defaults
if(FileUtil.find("tellstick.conf") != null) {
Reader reader = new FileReader("tellstick.conf");
prop.load(reader);
reader.close();
}
connect(prop.getProperty("com_port"));
}
public void connect(String portName) throws Exception {
@ -100,10 +115,14 @@ public class TellstickSerialComm implements Runnable, HalSensorController {
else {
if(!set.contains(data)) {
TellstickProtocol protocol = parser.decode(data);
if(protocol.getTimestamp() < 0)
protocol.setTimestamp(System.currentTimeMillis());
set.add(data);
if (listener != null) {
listener.stateChange(protocol);
}
if (sensorListener != null && protocol instanceof HalSensor)
sensorListener.reportReceived((HalSensor)protocol);
else if (eventListener != null && protocol instanceof HalEvent)
eventListener.reportReceived((HalEvent)protocol);
}
}
}
@ -112,6 +131,12 @@ public class TellstickSerialComm implements Runnable, HalSensorController {
}
}
@Override
public void send(HalEvent event) {
if(event instanceof TellstickProtocol)
write((TellstickProtocol) event);
}
public synchronized void write(TellstickProtocol prot) {
write(prot.encode());
try {
@ -120,7 +145,6 @@ public class TellstickSerialComm implements Runnable, HalSensorController {
logger.log(Level.SEVERE, null, e);
}
}
public void write(String data) {
try {
for(int i=0; i<data.length();i++)
@ -132,23 +156,28 @@ public class TellstickSerialComm implements Runnable, HalSensorController {
}
}
public void setListener(TellstickChangeListener listener){
this.listener = listener;
}
@Override
public void register(HalSensor sensor) {}
public void register(HalEvent event) {++registeredObjects;}
@Override
public void deregister(HalSensor sensor) {}
public void register(HalSensor sensor) {++registeredObjects;}
@Override
public void deregister(HalSensor sensor) {--registeredObjects;}
@Override
public void deregister(HalEvent event) {--registeredObjects;}
@Override
public int size() {
return 0;
return registeredObjects;
}
@Override
public void setListener(SensorReportListener listener) {
public void setListener(HalEventReportListener listener) {
eventListener = listener;
}
@Override
public void setListener(HalSensorReportListener listener) {
sensorListener = listener;
}
}

View file

@ -2,7 +2,7 @@
"version": 1.0,
"name": "Tellstick",
"interfaces": [
{"se.koc.hal.struct.HalSensor": "se.koc.hal.plugin.tellstick.protocols.Oregon0x1A2D"},
{"se.koc.hal.struct.HalEvent": "se.koc.hal.plugin.tellstick.protocols.NexaSelfLearning"}
{"se.koc.hal.intf.HalSensor": "se.koc.hal.plugin.tellstick.protocols.Oregon0x1A2D"},
{"se.koc.hal.intf.HalEvent": "se.koc.hal.plugin.tellstick.protocols.NexaSelfLearning"}
]
}

View file

@ -22,13 +22,16 @@
package se.koc.hal.plugin.tellstick.protocols;
import se.koc.hal.intf.HalEventController;
import se.koc.hal.plugin.tellstick.TellstickProtocol;
import se.koc.hal.struct.DimmerEvent;
import se.koc.hal.struct.SwitchEvent;
import zutil.ui.Configurator;
/**
* Created by Ziver on 2015-02-18.
*/
public class NexaSelfLearning implements TellstickProtocol {
public class NexaSelfLearning extends TellstickProtocol implements SwitchEvent {
@Configurator.Configurable("House code")
private int house = 0;
@ -40,6 +43,11 @@ public class NexaSelfLearning implements TellstickProtocol {
private boolean enable = false;
public NexaSelfLearning() {
super("arctech", "selflearning");
}
public String encode(){
StringBuilder enc = new StringBuilder();
enc.append(new char[]{'T', 127, 255, 24, 1});
@ -132,24 +140,18 @@ public class NexaSelfLearning implements TellstickProtocol {
public void setUnit(int unit) {
this.unit = unit;
}
public boolean isEnabled() {
public boolean isOn() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
public void turnOn() {
enable = true;
}
public void turnOff() {
enable = false;
}
@Override
public String getProtocolName() {
return "arctech";
}
@Override
public String getModelName() {
return "selflearning";
}
public String toString(){
return "class:command;protocol:arctech;model:selflearning;" +
@ -165,4 +167,11 @@ public class NexaSelfLearning implements TellstickProtocol {
((NexaSelfLearning)obj).unit == unit;
return false;
}
@Override
public double getData() {
return (enable ? 1 : 0);
}
}

View file

@ -11,7 +11,7 @@ import zutil.ui.Configurator;
/**
* Created by Ziver on 2015-11-19.
*/
public class Oregon0x1A2D implements TellstickProtocol, PowerConsumptionSensor {
public class Oregon0x1A2D extends TellstickProtocol implements PowerConsumptionSensor {
@Configurator.Configurable("Address")
private int address = 0;
@ -19,6 +19,11 @@ public class Oregon0x1A2D implements TellstickProtocol, PowerConsumptionSensor {
private double temperature = 0;
private double humidity = 0;
public Oregon0x1A2D(){
super("oregon", "0x1A2D");
}
@Override
public String encode() {
return null;
@ -66,15 +71,6 @@ public class Oregon0x1A2D implements TellstickProtocol, PowerConsumptionSensor {
}
@Override
public String getProtocolName() {
return "oregon";
}
@Override
public String getModelName() {
return "0x1A2D";
}
public double getTemperature(){
return temperature;
@ -85,14 +81,14 @@ public class Oregon0x1A2D implements TellstickProtocol, PowerConsumptionSensor {
}
@Override
public double getData() {
return temperature;
}
@Override
public AggregationMethod getAggregationMethod() {
return AggregationMethod.SUM;
}
@Override
public Class<? extends HalSensorController> getController() {
return TellstickSerialComm.class;
}
}

View file

@ -28,4 +28,5 @@ import se.koc.hal.intf.HalEvent;
* Created by Ziver on 2015-05-07.
*/
public abstract class DimmerEvent implements HalEvent {
}

View file

@ -45,6 +45,9 @@ public class Event extends DBBean{
}
public void setEventData(HalEvent eventData){
this.eventData = eventData;
}
public HalEvent getEventData(){
if(eventData == null) {
try {
@ -80,6 +83,6 @@ public class Event extends DBBean{
public Class<? extends HalEventController> getController(){
return getEventData().getController();
return getEventData().getEventController();
}
}

View file

@ -79,6 +79,9 @@ public class Sensor extends DBBean{
}
public void setSensorData(HalSensor sensorData){
this.sensorData = sensorData;
}
public HalSensor getSensorData(){
if(sensorData == null) {
try {
@ -125,12 +128,6 @@ public class Sensor extends DBBean{
public void setType(String type) {
this.type = type;
}
public String getConfig() {
return config;
}
public void setConfig(String config) {
this.config = config;
}
public User getUser() {
return user;
@ -157,6 +154,6 @@ public class Sensor extends DBBean{
}
public Class<? extends HalSensorController> getController(){
return getSensorData().getController();
return getSensorData().getSensorController();
}
}

View file

@ -31,7 +31,8 @@ import se.koc.hal.plugin.tellstick.protocols.NexaSelfLearning;
*/
public interface SwitchEvent extends HalEvent {
public boolean isOn();
public void turnOn();
public void turnOff();
boolean isOn();
void turnOn();
void turnOff();
}

View file

@ -7,7 +7,7 @@ import se.koc.hal.intf.HalSensor;
*/
public interface TemperatureSensor extends HalSensor {
public double getTemperature();
double getTemperature();
public double getHumidity();
double getHumidity();
}

View file

@ -27,7 +27,7 @@ public class TelstickSerialCommNexaOnOffTest {
System.out.println("Up and Running");
while(true) {
Thread.sleep(2000);
nexa.setEnable(true);
nexa.turnOn();
nexa.setUnit(0);
comm.write(nexa);
Thread.sleep(2000);
@ -36,7 +36,7 @@ public class TelstickSerialCommNexaOnOffTest {
Thread.sleep(2000);
nexa.setEnable(false);
nexa.turnOff();
nexa.setUnit(0);
comm.write(nexa);
Thread.sleep(2000);

View file

@ -1,10 +1,14 @@
package se.koc.hal.plugin.tellstick;
import se.koc.hal.intf.HalSensor;
import se.koc.hal.intf.HalSensorController;
import se.koc.hal.intf.HalSensorReportListener;
import se.koc.hal.plugin.tellstick.protocols.Oregon0x1A2D;
import zutil.db.DBConnection;
import zutil.log.CompactLogFormatter;
import zutil.log.LogUtil;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -25,17 +29,18 @@ public class TelstickSerialCommTest {
logger.info("Setting up Tellstick listeners...");
TellstickSerialComm comm = new TellstickSerialComm();
comm.setListener(new TellstickChangeListener() {
comm.setListener(new HalSensorReportListener() {
@Override
public void stateChange(TellstickProtocol protocol) {
if(protocol instanceof Oregon0x1A2D){
logger.info("Power used: "+ ((Oregon0x1A2D)protocol).getTemperature() +" pulses");
public void reportReceived(HalSensor s) {
if(s instanceof Oregon0x1A2D){
logger.info("Power used: "+ ((Oregon0x1A2D)s).getTemperature() +" pulses");
try {
db.exec("INSERT INTO sensor_data_raw (timestamp, sensor_id, data) VALUES("+
System.currentTimeMillis() + "," +
"1," +
(int)((Oregon0x1A2D)protocol).getTemperature()
+")");
PreparedStatement stmt =
db.getPreparedStatement("INSERT INTO sensor_data_raw (timestamp, event_id, data) VALUES(?, ?, ?)");
stmt.setLong(1, s.getTimestamp());
stmt.setLong(2, 1);
stmt.setDouble(3, ((Oregon0x1A2D)s).getTemperature());
db.exec(stmt);
} catch (SQLException e) {
e.printStackTrace();
}

View file

@ -33,7 +33,7 @@ public class NexaSelfLearningTest {
NexaSelfLearning nexa = new NexaSelfLearning();
nexa.setHouse(11772006);
nexa.setUnit(3);
nexa.setEnable(true);
nexa.turnOn();
assertArrayEquals(
new char[]{
@ -53,7 +53,7 @@ public class NexaSelfLearningTest {
assertEquals("House Code", 11772006, nexa.getHouse());
assertEquals("Unit Code", 1, nexa.getUnit());
assertTrue("Enabled", nexa.isEnabled());
assertTrue("Enabled", nexa.isOn());
}
@org.junit.Test
public void decode_OFF() throws Exception {
@ -62,6 +62,6 @@ public class NexaSelfLearningTest {
assertEquals("House Code", 11772006, nexa.getHouse());
assertEquals("Unit Code", 1, nexa.getUnit());
assertFalse("Enabled", nexa.isEnabled());
assertFalse("Enabled", nexa.isOn());
}
}