Added Junit test for Tellstick Controller and reverted equals(Hal...) as it was causing unforeseen issues.

This commit is contained in:
Ziver Koc 2016-08-15 17:36:46 +02:00
parent 2c1ccb8b57
commit 21ab281ec6
10 changed files with 155 additions and 86 deletions

View file

@ -15,6 +15,6 @@ public interface HalEventData {
* This method needs to be implemented. * This method needs to be implemented.
* NOTE: it should not compare data and timestamp, only static or unique data for the event type. * NOTE: it should not compare data and timestamp, only static or unique data for the event type.
*/ */
boolean equals(HalEventData obj); boolean equals(Object obj);
} }

View file

@ -35,5 +35,5 @@ public interface HalSensorData {
* NOTE: it should only static or unique data for the sensor type. * NOTE: it should only static or unique data for the sensor type.
* This method is used to associate reported data with registered sensors * This method is used to associate reported data with registered sensors
*/ */
boolean equals(HalSensorData obj); boolean equals(Object obj);
} }

View file

@ -42,7 +42,7 @@ public class NutUpsDevice implements PowerConsumptionSensorData{
} }
@Override @Override
public boolean equals(HalSensorData obj){ public boolean equals(Object obj){
if (obj instanceof NutUpsDevice) if (obj instanceof NutUpsDevice)
return deviceId != null && deviceId.equals(((NutUpsDevice)obj).deviceId); return deviceId != null && deviceId.equals(((NutUpsDevice)obj).deviceId);
return false; return false;

View file

@ -49,7 +49,7 @@ public class RPiPowerConsumptionSensor implements PowerConsumptionSensorData {
} }
@Override @Override
public boolean equals(HalSensorData obj){ public boolean equals(Object obj){
if(!(obj instanceof RPiPowerConsumptionSensor)) if(!(obj instanceof RPiPowerConsumptionSensor))
return false; return false;
return ((RPiPowerConsumptionSensor)obj).gpioPin == gpioPin; return ((RPiPowerConsumptionSensor)obj).gpioPin == gpioPin;

View file

@ -48,7 +48,7 @@ public class RPiTemperatureSensor implements TemperatureSensorData {
} }
@Override @Override
public boolean equals(HalSensorData obj){ public boolean equals(Object obj){
if(obj instanceof RPiTemperatureSensor) if(obj instanceof RPiTemperatureSensor)
return obj == this; return obj == this;
return false; return false;

View file

@ -33,6 +33,8 @@ import java.util.logging.Logger;
/** /**
* Created by Ziver on 2015-02-18. * Created by Ziver on 2015-02-18.
*
* Protocol Specification: http://developer.telldus.com/doxygen/TellStick.html
*/ */
public class TellstickParser { public class TellstickParser {
private static final Logger logger = LogUtil.getLogger(); private static final Logger logger = LogUtil.getLogger();
@ -43,6 +45,9 @@ public class TellstickParser {
registerProtocol(Oregon0x1A2D.class); registerProtocol(Oregon0x1A2D.class);
} }
private int firmwareVersion = -1;
public TellstickProtocol decode(String data) { public TellstickProtocol decode(String data) {
if (data.startsWith("+W")) { if (data.startsWith("+W")) {
@ -72,6 +77,12 @@ public class TellstickParser {
} }
} else if (data.startsWith("+S") || data.startsWith("+T")) { } else if (data.startsWith("+S") || data.startsWith("+T")) {
// This is confirmation of send commands // This is confirmation of send commands
synchronized (this) {
this.notifyAll();
}
} else if (data.startsWith("+V")) {
if (data.length() > 2)
firmwareVersion = Integer.parseInt(data.substring(2));
}else { }else {
logger.severe("Unknown prefix: " + data); logger.severe("Unknown prefix: " + data);
} }
@ -79,12 +90,24 @@ public class TellstickParser {
return null; return null;
} }
public void waitSendConformation(){
try {
this.wait();
} catch (InterruptedException e) {
logger.log(Level.SEVERE, null, e);
}
}
public int getFirmwareVersion() {
return firmwareVersion;
}
public static void registerProtocol(Class<? extends TellstickProtocol> protClass) { public static void registerProtocol(Class<? extends TellstickProtocol> protClass) {
try { try {
if (protocolMap == null) if (protocolMap == null)
protocolMap = new HashMap<String, Class<? extends TellstickProtocol>>(); protocolMap = new HashMap<>();
TellstickProtocol tmp = protClass.newInstance(); TellstickProtocol tmp = protClass.newInstance();
protocolMap.put( protocolMap.put(
tmp.getProtocolName() + "-" + tmp.getModelName(), tmp.getProtocolName() + "-" + tmp.getModelName(),

View file

@ -53,7 +53,7 @@ public class TellstickSerialComm implements Runnable,
private OutputStream out; private OutputStream out;
private TimedHashSet set; // To check for duplicate transmissions private TimedHashSet set; // To check for duplicate transmissions
private TellstickParser parser; protected TellstickParser parser;
private HalSensorReportListener sensorListener; private HalSensorReportListener sensorListener;
private HalEventReportListener eventListener; private HalEventReportListener eventListener;
@ -115,43 +115,8 @@ public class TellstickSerialComm implements Runnable,
public void run() { public void run() {
try { try {
String data; String data;
while (in != null && (data = readLine()) != null) { while (in != null && (data = readLine()) != null) {
if ((data.startsWith("+S") || data.startsWith("+T"))) { handleLine(data);
synchronized (this) {
this.notifyAll();
}
}
else {
TellstickProtocol protocol = parser.decode(data);
if(protocol != null) {
if (protocol.getTimestamp() < 0)
protocol.setTimestamp(System.currentTimeMillis());
boolean registered = registeredDevices.contains(protocol);
if(registered && !set.contains(data) || // check for duplicates transmissions of registered devices
!registered && set.contains(data)) { // required duplicate transmissions before reporting unregistered devices
//Check for registered device that are in the same group
if(protocol instanceof TellstickGroupProtocol) {
TellstickGroupProtocol groupProtocol = (TellstickGroupProtocol) protocol;
for (int i=0; i<registeredDevices.size(); ++i) { // Don't use foreach for concurrency reasons
TellstickProtocol childProtocol = registeredDevices.get(i);
if (childProtocol instanceof TellstickGroupProtocol &&
groupProtocol.equalsGroup(childProtocol) &&
!protocol.equals(childProtocol)) {
((TellstickGroupProtocol) childProtocol).copyGroupData(groupProtocol);
childProtocol.setTimestamp(protocol.getTimestamp());
reportEvent(childProtocol);
}
}
}
// Report source event
reportEvent(protocol);
}
set.add(data);
}
}
} }
} catch (IOException e) { } catch (IOException e) {
logger.log(Level.SEVERE, null, e); logger.log(Level.SEVERE, null, e);
@ -165,7 +130,7 @@ public class TellstickSerialComm implements Runnable,
} }
/** /**
* There seems to be an issue with read(...) methods only read() is working * There seems to be an issue with read(...) methods, only read() is working
*/ */
private String readLine() throws IOException { private String readLine() throws IOException {
StringBuilder str = new StringBuilder(50); StringBuilder str = new StringBuilder(50);
@ -183,6 +148,36 @@ public class TellstickSerialComm implements Runnable,
} }
return str.toString(); return str.toString();
} }
protected void handleLine(String data){
TellstickProtocol protocol = parser.decode(data);
if(protocol != null) {
if (protocol.getTimestamp() < 0)
protocol.setTimestamp(System.currentTimeMillis());
boolean registered = registeredDevices.contains(protocol);
if(registered && !set.contains(data) || // check for duplicates transmissions of registered devices
!registered && set.contains(data)) { // required duplicate transmissions before reporting unregistered devices
//Check for registered device that are in the same group
if(protocol instanceof TellstickGroupProtocol) {
TellstickGroupProtocol groupProtocol = (TellstickGroupProtocol) protocol;
for (int i=0; i<registeredDevices.size(); ++i) { // Don't use foreach for concurrency reasons
TellstickProtocol childProtocol = registeredDevices.get(i);
if (childProtocol instanceof TellstickGroupProtocol &&
groupProtocol.equalsGroup(childProtocol) &&
!protocol.equals(childProtocol)) {
((TellstickGroupProtocol) childProtocol).copyGroupData(groupProtocol);
childProtocol.setTimestamp(protocol.getTimestamp());
reportEvent(childProtocol);
}
}
}
// Report source event
reportEvent(protocol);
}
set.add(data);
}
}
@Override @Override
@ -192,14 +187,10 @@ public class TellstickSerialComm implements Runnable,
} }
public synchronized void write(TellstickProtocol prot) { public synchronized void write(TellstickProtocol prot) {
write(prot.encode()); write(prot.encode());
try { parser.waitSendConformation();
this.wait(); prot.setTimestamp(System.currentTimeMillis());
prot.setTimestamp(System.currentTimeMillis());
} catch (InterruptedException e) {
logger.log(Level.SEVERE, null, e);
}
} }
public void write(String data) { private void write(String data) {
try { try {
for(int i=0; i<data.length();i++) for(int i=0; i<data.length();i++)
out.write(0xFF & data.charAt(i)); out.write(0xFF & data.charAt(i));

View file

@ -148,7 +148,7 @@ public class NexaSelfLearning extends TellstickProtocol
} }
@Override @Override
public boolean equals(HalEventData obj){ public boolean equals(Object obj){
if(obj instanceof NexaSelfLearning) if(obj instanceof NexaSelfLearning)
return ((NexaSelfLearning) obj).house == house && return ((NexaSelfLearning) obj).house == house &&
((NexaSelfLearning) obj).group == group && ((NexaSelfLearning) obj).group == group &&

View file

@ -69,7 +69,7 @@ public class Oregon0x1A2D extends TellstickProtocol implements PowerConsumptionS
} }
@Override @Override
public boolean equals(HalSensorData obj){ public boolean equals(Object obj){
if(! (obj instanceof Oregon0x1A2D)) if(! (obj instanceof Oregon0x1A2D))
return false; return false;
return ((Oregon0x1A2D)obj).address == this.address; return ((Oregon0x1A2D)obj).address == this.address;

View file

@ -1,59 +1,114 @@
package se.hal.plugin.tellstick; package se.hal.plugin.tellstick;
import org.junit.Before;
import org.junit.Test;
import se.hal.HalContext; import se.hal.HalContext;
import se.hal.intf.HalEventData;
import se.hal.intf.HalEventReportListener;
import se.hal.intf.HalSensorData; import se.hal.intf.HalSensorData;
import se.hal.intf.HalSensorReportListener; import se.hal.intf.HalSensorReportListener;
import se.hal.plugin.tellstick.protocols.Oregon0x1A2D; import se.hal.plugin.tellstick.protocols.Oregon0x1A2D;
import zutil.converter.Converter;
import zutil.db.DBConnection; import zutil.db.DBConnection;
import zutil.log.CompactLogFormatter; import zutil.log.CompactLogFormatter;
import zutil.log.LogUtil; import zutil.log.LogUtil;
import zutil.struct.MutableInt;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
/** /**
* Created by Ziver on 2015-11-19. * Created by Ziver on 2015-11-19.
*/ */
public class TelstickSerialCommTest { public class TelstickSerialCommTest {
private static final Logger logger = LogUtil.getLogger();
public static void main(String[] args) { @Before
try { public void init(){
LogUtil.setGlobalFormatter(new CompactLogFormatter()); TellstickParser.registerProtocol(TestEvent.class);
LogUtil.setGlobalLevel(Level.FINEST); }
logger.info("Initializing HalContext...");
HalContext.initialize();
final DBConnection db = HalContext.getDB();
logger.info("Setting up Tellstick listeners..."); //############# Non crashing TC
TellstickSerialComm comm = new TellstickSerialComm();
comm.setListener(new HalSensorReportListener() {
@Override
public void reportReceived(HalSensorData s) {
if(s instanceof Oregon0x1A2D){
logger.info("Power used: "+ ((Oregon0x1A2D)s).getTemperature() +" pulses");
try {
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();
}
}
}
});
comm.initialize("COM5");
//comm.connect("/dev/ttyUSB1");
logger.info("Up and Running"); @Test
} catch (Exception e) { public void startup(){
e.printStackTrace(); TellstickSerialComm tellstick = new TellstickSerialComm();
tellstick.handleLine("+V2");
}
@Test
public void unregisteredListener(){
TellstickSerialComm tellstick = new TellstickSerialComm();
tellstick.handleLine("+Wclass:sensor;protocol:test-prot;model:test-model;data:1234;");
}
//############ Normal TCs
@Test
public void unregisteredEvent(){
// Setup
TellstickSerialComm tellstick = new TellstickSerialComm();
final ArrayList<HalEventData> list = new ArrayList<>();
tellstick.setListener(new HalEventReportListener() {
@Override
public void reportReceived(HalEventData e) {
list.add(e);
}
});
// Execution
tellstick.handleLine("+Wclass:sensor;protocol:test-prot;model:test-model;data:2345;");
assertEquals("Events first transmission", 0, list.size());
tellstick.handleLine("+Wclass:sensor;protocol:test-prot;model:test-model;data:2345;");
assertEquals("Events Second transmission", 1, list.size());
}
@Test
public void event(){
// Setup
TellstickSerialComm tellstick = new TellstickSerialComm();
final ArrayList<HalEventData> list = new ArrayList<>();
tellstick.setListener(new HalEventReportListener() {
@Override
public void reportReceived(HalEventData e) {
list.add(e);
}
});
// Execution
TestEvent event = new TestEvent();
event.testData = 0xAAAA;
tellstick.register(event);
tellstick.handleLine("+Wclass:sensor;protocol:test-prot;model:test-model;data:AAAA;");
// Verification
assertEquals("Nr of received events", 1, list.size());
assertEquals("Data", event.testData, ((TestEvent)list.get(0)).testData);
}
private static class TestEvent extends TellstickProtocol implements HalEventData{
public int testData;
public TestEvent(){
super("test-prot", "test-model");
} }
@Override
public void decode(byte[] data) {
testData = Converter.toInt(data);
}
@Override
public String encode() {return null;}
@Override
public double getData() {return 0;}
@Override
public boolean equals(Object obj) {return testData == ((TestEvent)obj).testData;}
} }
} }