Some robustness fixes and:

- Fixed Nexa send command
- Added UPS plugin for power consumption
- Added Autostartable Controller interface
This commit is contained in:
Ziver Koc 2016-05-25 14:27:11 +02:00
parent 5f0800897c
commit 7109abeea2
17 changed files with 219 additions and 32 deletions

View file

@ -2,4 +2,6 @@ http_port=8080
sync_port=6666
# Plugin configurations
tellstick.com_port=COM5
#tellstick.com_port=COM5
#nutups.host=
#nutups.port=

View file

@ -28,7 +28,7 @@ public class ControllerManager implements HalSensorReportListener,
private static ControllerManager instance;
/** All available sensor plugins **/
/** All isAvailable sensor plugins **/
private List<Class<?>> availableSensors = new ArrayList<>();
/** List of all registered sensors **/
private List<Sensor> registeredSensors = new ArrayList<>();
@ -38,7 +38,7 @@ public class ControllerManager implements HalSensorReportListener,
private List<Sensor> limboSensors = new LinkedList<>();
/** All available event plugins **/
/** All isAvailable event plugins **/
private List<Class<?>> availableEvents = new ArrayList<>();
/** List of all registered events **/
private List<Event> registeredEvents = new ArrayList<>();
@ -61,7 +61,7 @@ public class ControllerManager implements HalSensorReportListener,
return;
}
if(!availableSensors.contains(sensor.getDeviceData().getClass())) {
logger.warning("Sensor data plugin not available: "+ sensor.getDeviceData().getClass());
logger.warning("Sensor data plugin not isAvailable: "+ sensor.getDeviceData().getClass());
return;
}
@ -146,7 +146,7 @@ public class ControllerManager implements HalSensorReportListener,
return;
}
if(!availableEvents.contains(event.getDeviceData().getClass())) {
logger.warning("Sensor data plugin not available: "+ event.getDeviceData().getClass());
logger.warning("Sensor data plugin not isAvailable: "+ event.getDeviceData().getClass());
return;
}
@ -234,6 +234,11 @@ public class ControllerManager implements HalSensorReportListener,
}
/////////////////////////////// GENERAL ///////////////////////////////////
public void initializeScannableControllers(){
}
@Override
public void preConfigurationAction(Configurator configurator, Object obj) {
if(obj instanceof HalSensorData) {
@ -276,9 +281,15 @@ public class ControllerManager implements HalSensorReportListener,
controller = controllerMap.get(c);
else {
// Instantiate controller
logger.info("Instantiating new controller: " + c.getName());
try {
controller = c.newInstance();
if (controller instanceof HalAutoScannableController &&
! ((HalAutoScannableController)controller).isAvailable()) {
logger.warning("Controller not available: "+c.getName());
return null;
}
logger.info("Instantiating new controller: " + c.getName());
if(controller instanceof HalSensorController) {
((HalSensorController) controller).setListener(this);
((HalSensorController) controller).initialize();
@ -292,13 +303,16 @@ public class ControllerManager implements HalSensorReportListener,
controllerMap.put(c, controller);
} catch (Exception e){
logger.log(Level.SEVERE, "Unable to instantiate controller: "+c.getName(), e);
controller = null;
return null;
}
}
return (T)controller;
}
private void removeControllerIfEmpty(Object controller){
if (controller instanceof HalAutoScannableController)
return; // Don't do anything if controller is scannable
int size = Integer.MAX_VALUE;
if(controller instanceof HalSensorController)
size = ((HalSensorController) controller).size();
@ -335,6 +349,11 @@ public class ControllerManager implements HalSensorReportListener,
while (pluginIt.hasNext()){
manager.availableEvents.add(pluginIt.next());
}
pluginIt = plugin.getClassIterator(HalAutoScannableController.class);
while (pluginIt.hasNext()){
manager.getControllerInstance(pluginIt.next()); // Instantiate controller
}
}
instance = manager;
}

View file

@ -53,6 +53,11 @@ public class HalContext {
}
else logger.info("No hal.conf file found");
if (FileUtil.find(DEFAULT_DB_FILE) == null){
logger.severe("Unable to find default DB: "+DEFAULT_DB_FILE);
System.exit(1);
}
// Init DB
File dbFile = FileUtil.find(DB_FILE);
db = new DBConnection(DBConnection.DBMS.SQLite, DB_FILE);

View file

@ -31,14 +31,6 @@ public class HalServer {
public static void main(String[] args) throws Exception {
// init logging
LogUtil.readConfiguration("logging.properties");
/*CompactLogFormatter formatter = new CompactLogFormatter();
LogUtil.setLevel("se.hal", Level.FINEST);
LogUtil.setFormatter("se.hal", formatter);
LogUtil.setLevel("zutil.db.bean", Level.INFO);
LogUtil.setLevel("zutil.net.http.pages", Level.INFO);
LogUtil.setLevel("zutil", Level.FINEST);
LogUtil.setFormatter("zutil", formatter);
LogUtil.setGlobalFormatter(formatter);*/
// init Managers
HalContext.initialize();

View file

@ -140,7 +140,7 @@ public class PCDataSynchronizationClient implements HalDaemon {
/////////////// DTO ///////////////////////
/**
* Request Peer information and available sensors
* Request Peer information and isAvailable sensors
*/
protected static class PeerDataReqDTO implements Serializable{}

View file

@ -0,0 +1,13 @@
package se.hal.intf;
/**
* Created by ezivkoc on 2016-05-25.
*/
public interface HalAutoScannableController {
/**
* Indicates if the controller has all the configuration
* data and resources to be able to initialize
*/
public boolean isAvailable();
}

View file

@ -5,6 +5,11 @@ package se.hal.intf;
*/
public interface HalEventController {
/**
* The framework might create dummy objects so any type of
* resource initialization should be handled in this method
* and not in the constructor.
*/
void initialize() throws Exception;
/**

View file

@ -5,6 +5,11 @@ package se.hal.intf;
*/
public interface HalSensorController {
/**
* The framework might create dummy objects so any type of
* resource initialization should be handled in this method
* and not in the constructor.
*/
void initialize() throws Exception;
/**

View file

@ -0,0 +1,79 @@
package se.hal.plugin.nutups;
import se.hal.HalContext;
import se.hal.intf.HalAutoScannableController;
import se.hal.intf.HalSensorController;
import se.hal.intf.HalSensorData;
import se.hal.intf.HalSensorReportListener;
import zutil.osal.app.linux.NutUPSClient;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created by Ziver on 2016-05-25.
*/
public class NutUpsController implements HalSensorController, HalAutoScannableController, Runnable{
private static final int SYNC_INTERVAL = 60 * 1000;
private NutUPSClient client;
private ScheduledExecutorService executor;
private HalSensorReportListener listener;
@Override
public boolean isAvailable() {
return HalContext.getStringProperty("nutups.host") != null;
}
@Override
public void initialize() throws Exception {
if (client == null) {
int port = NutUPSClient.DEFAULT_PORT;
if (HalContext.getStringProperty("nutups.port") != null)
port = Integer.parseInt(HalContext.getStringProperty("nutups.port"));
client = new NutUPSClient(HalContext.getStringProperty("nutups.host"), port);
executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(this, 5000, SYNC_INTERVAL, TimeUnit.MILLISECONDS);
}
}
@Override
public void setListener(HalSensorReportListener listener) {
this.listener = listener;
}
@Override
public void run() {
if(client != null && listener != null){
for (NutUPSClient.UPSDevice ups : client.getUPSList()){
listener.reportReceived(new NutUpsDevice(ups));
}
}
}
@Override
public void close() {
client = null;
executor.shutdownNow();
}
@Override
public void register(HalSensorData sensor) {
}
@Override
public void deregister(HalSensorData sensor) {
}
@Override
public int size() {
return 0;
}
}

View file

@ -0,0 +1,56 @@
package se.hal.plugin.nutups;
import se.hal.intf.HalSensorController;
import se.hal.intf.HalSensorData;
import se.hal.struct.PowerConsumptionSensorData;
import zutil.osal.app.linux.NutUPSClient;
import zutil.ui.Configurator;
/**
* Created by Ziver on 2016-05-25.
*/
public class NutUpsDevice implements PowerConsumptionSensorData{
@Configurator.Configurable("UPS id")
private String deviceId;
private long timestamp;
private int consumption;
public NutUpsDevice(){}
protected NutUpsDevice(NutUPSClient.UPSDevice ups){
this.deviceId = ups.getId();
this.timestamp = System.currentTimeMillis();
this.consumption = ups.getPowerUsage();
}
@Override
public long getTimestamp() {
return timestamp;
}
@Override
public double getData() {
return consumption;
}
@Override
public boolean equals(Object obj){
if (obj instanceof NutUpsDevice)
return deviceId != null && deviceId.equals(((NutUpsDevice)obj).deviceId);
return false;
}
@Override
public AggregationMethod getAggregationMethod() {
return AggregationMethod.SUM;
}
@Override
public Class<? extends HalSensorController> getSensorController() {
return NutUpsController.class;
}
}

View file

@ -0,0 +1,8 @@
{
"version": 1.0,
"name": "NutUps",
"interfaces": [
{"se.hal.intf.HalAutoScannableController": "se.hal.plugin.nutups.NutUpsController"},
{"se.hal.intf.HalSensorData": "se.hal.plugin.nutups.NutUpsDevice"}
]
}

View file

@ -41,7 +41,8 @@ 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, HalEventController {
public class TellstickSerialComm implements Runnable,
HalSensorController, HalEventController, HalAutoScannableController {
private static final long TRANSMISSION_UNIQUENESS_TTL = 1000; // milliseconds
private static final Logger logger = LogUtil.getLogger();
@ -64,6 +65,10 @@ public class TellstickSerialComm implements Runnable, HalSensorController, HalEv
registeredDevices = new ArrayList<>();
}
@Override
public boolean isAvailable() {
return HalContext.getStringProperty("tellstick.com_port") != null;
}
@Override
public void initialize() throws Exception {
// Read properties
@ -71,10 +76,10 @@ public class TellstickSerialComm implements Runnable, HalSensorController, HalEv
if (port == null)
port = "COM1"; // defaults
connect(port);
initialize(port);
}
public void connect(String portName) throws Exception {
public void initialize(String portName) throws Exception {
logger.info("Connecting to com port... ("+ portName +")");
serial = SerialPort.getCommPort(portName);
serial.setBaudRate(9600);
@ -85,9 +90,6 @@ public class TellstickSerialComm implements Runnable, HalSensorController, HalEv
in = serial.getInputStream();
out = serial.getOutputStream();
//in = new InputStreamLogger(serial.getInputStream());
//out = new OutputStreamLogger(serial.getOutputStream());
Executors.newSingleThreadExecutor().execute(this);
}
@ -241,4 +243,5 @@ public class TellstickSerialComm implements Runnable, HalSensorController, HalEv
public void setListener(HalSensorReportListener listener) {
sensorListener = listener;
}
}

View file

@ -2,6 +2,8 @@
"version": 1.0,
"name": "Tellstick",
"interfaces": [
{"se.hal.intf.HalAutoScannableController": "se.hal.plugin.tellstick.TellstickSerialComm"},
{"se.hal.intf.HalSensorData": "se.hal.plugin.tellstick.protocols.Oregon0x1A2D"},
{"se.hal.intf.HalEventData": "se.hal.plugin.tellstick.protocols.NexaSelfLearning"}
]

View file

@ -68,7 +68,7 @@ public class NexaSelfLearning extends TellstickProtocol
enc.append(new char[]{'T', 127, 255, 24, 0});
enc.append((char)0); // length
enc.append((char)0b1111_1001); // preamble
enc.append((char)0b0000_1001); // preamble
int length = 4;
byte[] data = BinaryStructOutputStream.serialize(this);
for (byte b : data){
@ -80,6 +80,8 @@ public class NexaSelfLearning extends TellstickProtocol
length += 4;
}
}
enc.append((char)0b0000_0000); // postemble
length += 2;
enc.setCharAt(5, (char)length); // Set calculated length
enc.append("+");

View file

@ -12,7 +12,7 @@ public class TelstickSerialCommNexaOnOffTest {
System.out.println("Connecting to db...");
TellstickSerialComm comm = new TellstickSerialComm();
// http://developer.telldus.com/doxygen/TellStick.html
comm.connect("COM5");
comm.initialize("COM8");
//comm.connect("/dev/ttyUSB1");
Thread.sleep(1000);

View file

@ -48,7 +48,7 @@ public class TelstickSerialCommTest {
}
}
});
comm.connect("COM5");
comm.initialize("COM5");
//comm.connect("/dev/ttyUSB1");
logger.info("Up and Running");

View file

@ -41,18 +41,15 @@ public class NexaSelfLearningTest {
byte[] expected = Converter.toBytes(new char[]{
84, // T
127, 255, 24, 0, // timings
132, // length
134, // length
0xF9, // preamble
168, 168, 138, 168, 138, 138, 168, 168, 138, 138,
138, 168, 138, 168, 168, 168, 168, 168, 168, 138,
138, 168, 168, 138, 138, 168, 168, 138, 168, 168,
168, 168,
0x00, // postemble
/*154, 138, 136, 170, 136, 168, 170, 138, 136, 168,
168, 170, 136, 170, 138, 138, 138, 138, 138, 136,
168, 170, 138, 136, 168, 170, 138, 136, 170, 138,
136, 168, 170,*/
43}); // +
byte[] actual = nexa.encode().getBytes(StandardCharsets.ISO_8859_1);
@ -69,9 +66,8 @@ public class NexaSelfLearningTest {
assertEquals("House Code", 11772006, nexa.getHouse());
assertEquals("Unit Code", 0, nexa.getUnit());
assertTrue("Enabled", nexa.isOn());
}
@org.junit.Test
public void decode_OFF() throws Exception {
NexaSelfLearning nexa = decode("0x2CE81980");