diff --git a/hal.conf.example b/hal.conf.example index 0a3e4d77..cab36709 100755 --- a/hal.conf.example +++ b/hal.conf.example @@ -2,4 +2,6 @@ http_port=8080 sync_port=6666 # Plugin configurations -tellstick.com_port=COM5 \ No newline at end of file +#tellstick.com_port=COM5 +#nutups.host= +#nutups.port= \ No newline at end of file diff --git a/src/se/hal/ControllerManager.java b/src/se/hal/ControllerManager.java index ce26f5f1..69f1d187 100755 --- a/src/se/hal/ControllerManager.java +++ b/src/se/hal/ControllerManager.java @@ -28,7 +28,7 @@ public class ControllerManager implements HalSensorReportListener, private static ControllerManager instance; - /** All available sensor plugins **/ + /** All isAvailable sensor plugins **/ private List> availableSensors = new ArrayList<>(); /** List of all registered sensors **/ private List registeredSensors = new ArrayList<>(); @@ -38,7 +38,7 @@ public class ControllerManager implements HalSensorReportListener, private List limboSensors = new LinkedList<>(); - /** All available event plugins **/ + /** All isAvailable event plugins **/ private List> availableEvents = new ArrayList<>(); /** List of all registered events **/ private List 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; } diff --git a/src/se/hal/HalContext.java b/src/se/hal/HalContext.java index 29ff8ce3..ad615320 100755 --- a/src/se/hal/HalContext.java +++ b/src/se/hal/HalContext.java @@ -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); diff --git a/src/se/hal/HalServer.java b/src/se/hal/HalServer.java index ffe90649..b16fe5c6 100755 --- a/src/se/hal/HalServer.java +++ b/src/se/hal/HalServer.java @@ -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(); diff --git a/src/se/hal/deamon/PCDataSynchronizationClient.java b/src/se/hal/deamon/PCDataSynchronizationClient.java index 64d3a25e..dc47d4c4 100755 --- a/src/se/hal/deamon/PCDataSynchronizationClient.java +++ b/src/se/hal/deamon/PCDataSynchronizationClient.java @@ -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{} diff --git a/src/se/hal/intf/HalAutoScannableController.java b/src/se/hal/intf/HalAutoScannableController.java new file mode 100755 index 00000000..1beae885 --- /dev/null +++ b/src/se/hal/intf/HalAutoScannableController.java @@ -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(); +} diff --git a/src/se/hal/intf/HalEventController.java b/src/se/hal/intf/HalEventController.java index 1625fa6f..95efa5d7 100755 --- a/src/se/hal/intf/HalEventController.java +++ b/src/se/hal/intf/HalEventController.java @@ -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; /** diff --git a/src/se/hal/intf/HalSensorController.java b/src/se/hal/intf/HalSensorController.java index 09328cc5..054058ea 100755 --- a/src/se/hal/intf/HalSensorController.java +++ b/src/se/hal/intf/HalSensorController.java @@ -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; /** diff --git a/src/se/hal/plugin/nutups/NutUpsController.java b/src/se/hal/plugin/nutups/NutUpsController.java new file mode 100755 index 00000000..000149f7 --- /dev/null +++ b/src/se/hal/plugin/nutups/NutUpsController.java @@ -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; + } + +} diff --git a/src/se/hal/plugin/nutups/NutUpsDevice.java b/src/se/hal/plugin/nutups/NutUpsDevice.java new file mode 100755 index 00000000..fe471588 --- /dev/null +++ b/src/se/hal/plugin/nutups/NutUpsDevice.java @@ -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 getSensorController() { + return NutUpsController.class; + } +} diff --git a/src/se/hal/plugin/nutups/plugin.json b/src/se/hal/plugin/nutups/plugin.json new file mode 100755 index 00000000..7b24fde6 --- /dev/null +++ b/src/se/hal/plugin/nutups/plugin.json @@ -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"} + ] +} \ No newline at end of file diff --git a/src/se/hal/plugin/tellstick/TellstickSerialComm.java b/src/se/hal/plugin/tellstick/TellstickSerialComm.java index 84a04cba..616d3549 100755 --- a/src/se/hal/plugin/tellstick/TellstickSerialComm.java +++ b/src/se/hal/plugin/tellstick/TellstickSerialComm.java @@ -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; } + } \ No newline at end of file diff --git a/src/se/hal/plugin/tellstick/plugin.json b/src/se/hal/plugin/tellstick/plugin.json index 610caa4d..65ef031c 100755 --- a/src/se/hal/plugin/tellstick/plugin.json +++ b/src/se/hal/plugin/tellstick/plugin.json @@ -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"} ] diff --git a/src/se/hal/plugin/tellstick/protocols/NexaSelfLearning.java b/src/se/hal/plugin/tellstick/protocols/NexaSelfLearning.java index e8583ba0..612363bf 100755 --- a/src/se/hal/plugin/tellstick/protocols/NexaSelfLearning.java +++ b/src/se/hal/plugin/tellstick/protocols/NexaSelfLearning.java @@ -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("+"); diff --git a/test/se/hal/plugin/tellstick/TelstickSerialCommNexaOnOffTest.java b/test/se/hal/plugin/tellstick/TelstickSerialCommNexaOnOffTest.java index bff68ecb..c16167bc 100755 --- a/test/se/hal/plugin/tellstick/TelstickSerialCommNexaOnOffTest.java +++ b/test/se/hal/plugin/tellstick/TelstickSerialCommNexaOnOffTest.java @@ -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); diff --git a/test/se/hal/plugin/tellstick/TelstickSerialCommTest.java b/test/se/hal/plugin/tellstick/TelstickSerialCommTest.java index c3b57e7b..011aae07 100755 --- a/test/se/hal/plugin/tellstick/TelstickSerialCommTest.java +++ b/test/se/hal/plugin/tellstick/TelstickSerialCommTest.java @@ -48,7 +48,7 @@ public class TelstickSerialCommTest { } } }); - comm.connect("COM5"); + comm.initialize("COM5"); //comm.connect("/dev/ttyUSB1"); logger.info("Up and Running"); diff --git a/test/se/hal/plugin/tellstick/protocols/NexaSelfLearningTest.java b/test/se/hal/plugin/tellstick/protocols/NexaSelfLearningTest.java index 844d2c5a..7e436d77 100755 --- a/test/se/hal/plugin/tellstick/protocols/NexaSelfLearningTest.java +++ b/test/se/hal/plugin/tellstick/protocols/NexaSelfLearningTest.java @@ -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");