/** * * Copyright (c) 2009-2016 Freedomotic team http://freedomotic.com * * This file is part of Freedomotic * * This Program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2, or (at your option) any later version. * * This Program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * Freedomotic; see the file COPYING. If not, see * <http://www.gnu.org/licenses/>. */ package com.freedomotic.plugins.devices.openwebnet; import com.freedomotic.api.EventTemplate; import com.freedomotic.api.Protocol; import com.freedomotic.app.Freedomotic; import com.freedomotic.events.ProtocolRead; import com.freedomotic.exceptions.UnableToExecuteException; import com.freedomotic.reactions.Command; import java.io.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Mauro Cicolella */ public class OpenWebNet extends Protocol { public static final Logger LOG = LoggerFactory.getLogger(OpenWebNet.class.getName()); private final String host = configuration.getProperty("host"); private final Integer port = Integer.parseInt(configuration.getProperty("port")); private String address = null; private String frame = null; private ProtocolRead event = null; private OWNFrame pluginGui = null; public clientjava.connections.ConnectionsManager ownHandler = clientjava.connections.ConnectionsManager.getInstance(); /* * * OWN Diagnostic Frames * */ final static String LIGHTNING_DIAGNOSTIC_FRAME = "*#1*0##"; final static String AUTOMATIONS_DIAGNOSTIC_FRAME = "*#2*0##"; final static String ALARM_DIAGNOSTIC_FRAME = "*#5##"; final static String POWER_MANAGEMENT_DIAGNOSTIC_FRAME = "*#3##"; /* * * OWN Control Messages * */ final static String MSG_OPEN_ACK = "*#*1##"; final static String MSG_OPEN_NACK = "*#*0##"; /** * */ public OpenWebNet() { super("OpenWebNet", "/openwebnet/openwebnet-manifest.xml"); setPollingWait(-1); } protected void onShowGui() { bindGuiToPlugin(pluginGui); } @Override public void onStart() { pluginGui = new OWNFrame(this); ownHandler.init(host, port, this); ownHandler.startMonitoring(); //System.out.println("PROVA FRAME "); //this.buildEventFromFrame("*#4*1*12*0205*3##"); // this.buildEventFromFrame("*#4*1*0*0205*3##"); } @Override protected void onRun() { // syncronize the software with the system status initSystem(); } @Override public void onCommand(Command c) throws IOException, UnableToExecuteException { String frameToSend = OWNUtilities.createFrame(c); LOG.info("Trying to send frame ''{}'' to OWN gateway", frameToSend); ownHandler.inviaComandoOpen(frameToSend); } /** * * @return the logger istance */ public Logger getLogger() { return LOG; } @Override protected boolean canExecute(Command c) { throw new UnsupportedOperationException("Not supported yet."); } @Override protected void onEvent(EventTemplate event) { throw new UnsupportedOperationException("Not supported yet."); } @Override public void onStop() { ownHandler.stopMonitoring(); this.setDescription("Plugin stopped"); } // sends diagnostic frames to syncronize the software with the real system private void initSystem() { LOG.info("Sending '{}' frame to initialize LIGHTNING", LIGHTNING_DIAGNOSTIC_FRAME); OWNFrame.writeAreaLog(OWNUtilities.getDateTime() + " Act:" + "Sending " + LIGHTNING_DIAGNOSTIC_FRAME + " (initialize LIGHTNING)"); ownHandler.inviaComandoOpen(LIGHTNING_DIAGNOSTIC_FRAME); //LOG.log(Level.INFO, "Sending ''{0}'' frame to initialize AUTOMATIONS", AUTOMATIONS_DIAGNOSTIC_FRAME); //OWNFrame.writeAreaLog(OWNUtilities.getDateTime() + " Act:" + "Sending " + AUTOMATIONS_DIAGNOSTIC_FRAME + " (initialize AUTOMATIONS)"); //ownHandler.inviaComandoOpen(AUTOMATIONS_DIAGNOSTIC_FRAME); //LOG.log(Level.INFO, "Sending ''{0}'' frame to initialize ALARM", ALARM_DIAGNOSTIC_FRAME); //OWNFrame.writeAreaLog(OWNUtilities.getDateTime() + " Act:" + "Sending " + ALARM_DIAGNOSTIC_FRAME + " (initialize ALARM)"); //ownHandler.inviaComandoOpen(ALARM_DIAGNOSTIC_FRAME); //LOG.log(Level.INFO, "Sending ''{0}'' frame to initialize POWER MANAGEMENT", POWER_MANAGEMENT_DIAGNOSTIC_FRAME); //OWNFrame.writeAreaLog(OWNUtilities.getDateTime() + " Act:" + "Sending " + POWER_MANAGEMENT_DIAGNOSTIC_FRAME + " (initialize POWER MANAGEMENT)"); //ownHandler.inviaComandoOpen(POWER_MANAGEMENT_DIAGNOSTIC_FRAME); } /** * Builds a Freedomotic event from the received frame. * * @param frame the frame to build an event from */ public void buildEventFromFrame(String frame) { String who = null; String what = null; String where = null; String dimension = null; String objectClass = null; String objectName = null; String messageType = null; String messageDescription = null; String[] frameParts = null; if (frame.isEmpty() || !frame.endsWith("##")) { LOG.error("Malformed frame " + frame); OWNFrame.writeAreaLog(OWNUtilities.getDateTime() + " Mon: Malformed frame " + frame); return; } if (frame.equals(OpenWebNet.MSG_OPEN_ACK)) { messageType = "ack"; return; } if (frame.equals(OpenWebNet.MSG_OPEN_NACK)) { messageType = "nack"; return; } if (frame.substring(0, 2).equalsIgnoreCase("*#")) { // remove *# and ## frame = frame.substring(2, frame.length() - 2); frameParts = frame.split("\\*"); // * is reserved so it must be escaped who = frameParts[0]; where = frameParts[1]; dimension = frameParts[2]; objectClass = null; objectName = who + "*" + where; event = new ProtocolRead(this, "openwebnet", who + "*" + where); // LIGHTING if (who.equalsIgnoreCase("1")) { if (who.equalsIgnoreCase("1")) { if (frameParts[2].equalsIgnoreCase("1")) { String level = frameParts[3]; String speed = frameParts[4]; messageDescription = "Luminous intensity change"; if (level != null) { event.getPayload().addStatement("level", level); } if (speed != null) { event.getPayload().addStatement("speed", speed); } } if (frameParts[2].equalsIgnoreCase("2")) { String hour = frameParts[3]; String min = frameParts[4]; String sec = frameParts[5]; messageDescription = "Luminous intensity change"; if (hour != null) { event.getPayload().addStatement("hour", hour); } if (min != null) { event.getPayload().addStatement("min", min); } if (sec != null) { event.getPayload().addStatement("sec", sec); } } } // POWER MANAGEMENT - WHO=3 if (who.equalsIgnoreCase("3")) { //objectClass = "Powermeter"; //objectName = who + "*" + where; String voltage = null; String current = null; String power = null; String energy = null; if (frameParts[3].equalsIgnoreCase("0")) { voltage = frameParts[3]; current = frameParts[4]; power = frameParts[5]; energy = frameParts[6]; messageDescription = "Load control status"; if (voltage != null) { event.getPayload().addStatement("voltage", voltage); } if (current != null) { event.getPayload().addStatement("current", current); } if (power != null) { event.getPayload().addStatement("power", power); } if (energy != null) { event.getPayload().addStatement("energy", energy); } } if (frameParts[3].equalsIgnoreCase("1")) { voltage = frameParts[3]; if (voltage != null) { event.getPayload().addStatement("voltage", voltage); } messageDescription = "Voltage status"; } if (frameParts[3].equalsIgnoreCase("2")) { current = frameParts[3]; if (current != null) { event.getPayload().addStatement("current", current); } messageDescription = "Current status"; } if (frameParts[3].equalsIgnoreCase("3")) { power = frameParts[3]; if (power != null) { event.getPayload().addStatement("power", power); } messageDescription = "Power status"; } if (frameParts[3].equalsIgnoreCase("4")) { energy = frameParts[3]; if (energy != null) { event.getPayload().addStatement("energy", energy); } messageDescription = "Energy status"; } } // TERMOREGULATION if (who.equalsIgnoreCase("4")) { String temperature = null; String setpoint = null; switch (Integer.parseInt(dimension)) { // temperature read value case 0: objectClass = "Thermostat"; temperature = frameParts[3].substring(1, frameParts[3].length()); messageDescription = "Temperature read value"; event.getPayload().addStatement("openwebnet.temperature", temperature); event.getPayload().addStatement("openwebnet.dimension", dimension); event.getPayload().addStatement("object.class", objectClass); break; // setpoint read value case 12: objectClass = "Thermostat"; setpoint = frameParts[3].substring(1, frameParts[3].length()); messageDescription = "Setpoint read value"; event.getPayload().addStatement("openwebnet.setpoint", setpoint); event.getPayload().addStatement("openwebnet.dimension", dimension); event.getPayload().addStatement("object.class", objectClass); break; } } // close TERMOREGULATION // GATEWAY CONTROL if (who.equalsIgnoreCase("13")) { String hour = null; String minute = null; String second = null; String timeZone = null; String dayWeek = null; String day = null; String month = null; String year = null; String version = null; String release = null; String build = null; if (frameParts[2].equalsIgnoreCase("0")) { hour = frameParts[3]; minute = frameParts[4]; second = frameParts[5]; timeZone = frameParts[6]; // aggiungere funzione conversione messageType = "gatewayControl"; messageDescription = "Time request"; if (hour != null) { event.getPayload().addStatement("hour", hour); } if (minute != null) { event.getPayload().addStatement("minute", minute); } if (second != null) { event.getPayload().addStatement("second", second); } if (timeZone != null) { event.getPayload().addStatement("timeZone", timeZone); } } if (frameParts[2].equalsIgnoreCase("1")) { dayWeek = OWNUtilities.dayName(frameParts[3]); day = frameParts[4]; month = frameParts[5]; year = frameParts[6]; messageType = "gatewayControl"; messageDescription = "Date request"; if (dayWeek != null) { event.getPayload().addStatement("dayWeek", dayWeek); } if (day != null) { event.getPayload().addStatement("day", day); } if (month != null) { event.getPayload().addStatement("month", month); } if (year != null) { event.getPayload().addStatement("year", year); } } if (frameParts[2].equalsIgnoreCase("10")) { String ip1 = frameParts[3]; String ip2 = frameParts[4]; String ip3 = frameParts[5]; String ip4 = frameParts[6]; messageType = "gatewayControl"; messageDescription = "IP request"; event.getPayload().addStatement("ip-address", ip1 + "." + ip2 + "." + ip3 + "." + ip4); } if (frameParts[2].equalsIgnoreCase("11")) { String netmask1 = frameParts[3]; String netmask2 = frameParts[4]; String netmask3 = frameParts[5]; String netmask4 = frameParts[6]; messageType = "gatewayControl"; messageDescription = "Netmask request"; event.getPayload().addStatement("netmask", netmask1 + "." + netmask2 + "." + netmask3 + "." + netmask4); } if (frameParts[2].equalsIgnoreCase("12")) { String mac1 = frameParts[3]; String mac2 = frameParts[4]; String mac3 = frameParts[5]; String mac4 = frameParts[6]; String mac5 = frameParts[7]; String mac6 = frameParts[8]; messageType = "gatewayControl"; messageDescription = "MAC request"; event.getPayload().addStatement("mac-address", mac1 + ":" + mac2 + ":" + mac3 + ":" + mac4 + ":" + mac5 + ":" + mac6); } if (frameParts[2].equalsIgnoreCase("15")) { String model = OWNUtilities.gatewayModel(frameParts[3]); messageType = "gatewayControl"; messageDescription = "Model request"; event.getPayload().addStatement("model", model); } if (frameParts[2].equalsIgnoreCase("16")) { version = frameParts[3]; release = frameParts[4]; build = frameParts[5]; messageType = "gatewayControl"; messageDescription = "Firmware version request"; event.getPayload().addStatement("firmware - version", version + "." + release + "." + build); } if (frameParts[2].equalsIgnoreCase("17")) { String days = frameParts[3]; String hours = frameParts[4]; String minutes = frameParts[5]; String seconds = frameParts[6]; messageType = "gatewayControl"; messageDescription = "Uptime request"; event.getPayload().addStatement("uptime", days + "D:" + hours + "H:" + minutes + "m:" + seconds + "s"); } if (frameParts[2].equalsIgnoreCase("22")) { hour = frameParts[3]; minute = frameParts[4]; second = frameParts[5]; timeZone = frameParts[6]; String weekDay = OWNUtilities.dayName(frameParts[7]); day = frameParts[8]; month = frameParts[9]; year = frameParts[10]; messageType = "gatewayControl"; messageDescription = "Date&Time request"; event.getPayload().addStatement("date", weekDay + " " + day + "/" + month + "/" + year); event.getPayload().addStatement("time", hour + ":" + minute + ":" + second); } if (frameParts[2].equalsIgnoreCase("23")) { version = frameParts[3]; release = frameParts[4]; build = frameParts[5]; messageType = "gatewayControl"; messageDescription = "Kernel version request"; event.getPayload().addStatement("kernel - version", version + "." + release + "." + build); } if (frameParts[2].equalsIgnoreCase("24")) { version = frameParts[3]; release = frameParts[4]; build = frameParts[5]; messageType = "gatewayControl"; messageDescription = "Distribution version request"; event.getPayload().addStatement("distribution - version", version + "." + release + "." + build); } } if (who != null) { event.getPayload().addStatement("openwebnet.who", who); } if (where != null) { event.getPayload().addStatement("openwebnet.where", where); } if (messageDescription != null) { event.getPayload().addStatement("openwebnet.messageDescription", messageDescription); } if (messageType != null) { event.getPayload().addStatement("openwebnet.messageType", messageType); } if (objectName != null) { event.getPayload().addStatement("object.name", objectName); event.getPayload().addStatement("autodiscovery.allow-clones", "false"); } OWNFrame.writeAreaLog(OWNUtilities.getDateTime() + " Rx: " + frame + " " + "(" + messageDescription + ")"); LOG.info("Frame received from OWN gateway: '{}'", frame); // notify event notifyEvent(event); LOG.debug("EVENTO NOTIFICATO: " + event.getPayload().getStatements()); return; } if (!(frame.substring(0, 2).equalsIgnoreCase("*#"))) { // remove delimiter chars * and ## frame = frame.substring(1, frame.length() - 2); frameParts = frame.split("\\*"); // * is reserved so it must be escaped who = frameParts[0]; what = frameParts[1]; where = frameParts[2]; event = new ProtocolRead(this, "openwebnet", who + "*" + where); objectName = who + "*" + where; switch (Integer.parseInt(who)) { //LIGHTING - WHO=1 case 1: messageType = "Lighting"; objectClass = "Light"; if ((where.length() > 1) && (!where.substring(1, 1).equalsIgnoreCase("#"))) { event.getPayload().addStatement("object.class", objectClass); } switch (Integer.parseInt(what)) { // Light OFF - WHAT=0 case 0: messageDescription = "Light OFF"; break; // Light ON - WHAT=1 case 1: messageDescription = "Light ON"; break; default: if (Integer.parseInt(what) >= 2 && Integer.parseInt(what) <= 10) { messageDescription = "Light Dimmer"; } break; } break; // close LIGHTING switch // AUTOMATION - WHO=2 case 2: messageType = "Automation"; switch (Integer.parseInt(what)) { case 0: // Automation STOP - WHAT=0 messageDescription = "Automation STOP"; break; case 1: // Automation UP - WHAT=1 messageDescription = "Automation UP"; break; case 2: // Automation DOWN - WHAT=2 messageDescription = "Automation DOWN"; break; } break; // close AUTOMATION switch // POWER MANAGEMENT - WHO=3 case 3: objectClass = "Powermeter"; messageType = "Power management"; switch (Integer.parseInt(what)) { case 0: messageDescription = "Load disable"; break; case 1: messageDescription = "Load enable"; break; case 2: messageDescription = "Load forced"; break; case 3: messageDescription = "Stop load forced"; break; } break; // close POWER MANAGEMENT switch // TERMOREGULATION - WHO=4 case 4: messageType = "termoregulation"; switch (Integer.parseInt(what)) { case 0: messageDescription = "Conditioning"; break; case 1: messageDescription = "Heating"; break; case 20: messageDescription = "Remote Control disabled"; break; case 21: messageDescription = "Remote Control enabled"; break; case 22: messageDescription = "At least one Probe OFF"; break; case 23: messageDescription = "At least one Probe in protection"; break; case 24: messageDescription = "At least one Probe in manual"; break; case 30: messageDescription = "Failure discovered"; break; case 31: messageDescription = "Central Unit battery KO"; break; case 103: messageDescription = "OFF Heating"; break; case 110: messageDescription = "Manual Heating"; break; case 111: messageDescription = "Automatic Heating"; break; case 202: messageDescription = "AntiFreeze"; break; case 203: messageDescription = "OFF Conditioning"; break; case 210: messageDescription = "Manual Conditioning"; break; case 211: messageDescription = "Automatic Conditioning"; break; case 302: messageDescription = "Thermal Protection"; break; case 303: messageDescription = "Generic OFF"; break; case 311: messageDescription = "Automatic Generic"; break; } break; // close TERMOREGULATION switch // BURGLAR ALARM - WHO=5 case 5: messageType = "alarm"; switch (Integer.parseInt(what)) { case 0: messageDescription = "System on maintenance"; break; case 4: messageDescription = "Battery fault"; break; case 5: messageDescription = "Battery OK"; break; case 6: messageDescription = "No Network"; break; case 7: messageDescription = "Network OK"; break; case 8: messageDescription = "System engaged"; break; case 9: messageDescription = "System disengaged"; break; case 10: messageDescription = "Battery KO"; break; case 11: // prelevare la sottostringa di where #N { messageDescription = "Zone " + where + " engaged"; } break; case 12: // prelevare la sottostringa di where #N { messageDescription = "Aux " + where + " in Technical alarm ON"; } break; case 13: // prelevare la sottostringa di where #N { messageDescription = "Aux " + where + " in Technical alarm RESET"; } break; case 15: // prelevare la sottostringa di where #N { messageDescription = "Zone " + where + " in Intrusion alarm"; } break; case 16: // prelevare la sottostringa di where #N { messageDescription = "Zone " + where + " in Tampering alarm"; } break; case 17: // prelevare la sottostringa di where #N { messageDescription = "Zone " + where + " in Anti-panic alarm"; } break; case 18: // prelevare la sottostringa di where #N { messageDescription = "Zone " + where + " divided"; } break; case 31: // prelevare la sottostringa di where #N { messageDescription = "Silent alarm from aux " + where; } break; } break; // close BURGLAR ALARM switch // SOUND SYSTEM case 16: messageType = "Sound System"; switch (Integer.parseInt(what)) { case 0: messageDescription = "ON Baseband"; break; case 3: messageDescription = "ON Stereo channel"; break; case 10: messageDescription = "OFF Baseband"; break; case 13: messageDescription = "OFF Stereo channel"; break; case 30: messageDescription = "Sleep on baseband"; break; case 33: messageDescription = "Sleep on stereo channel"; break; } break; // close SOUND SYSTEM switch } // close switch(who) if (who != null) { event.getPayload().addStatement("openwebnet.who", who); } if (what != null) { event.getPayload().addStatement("openwebnet.what", what); } if (where != null) { event.getPayload().addStatement("openwebnet.where", where); } if (messageType != null) { event.getPayload().addStatement("openwebnet.messageType", messageType); } if (messageDescription != null) { event.getPayload().addStatement("openwebnet.messageDescription", messageDescription); } if (objectName != null) { event.getPayload().addStatement("object.name", objectName); event.getPayload().addStatement("autodiscovery.allow-clones", "false"); } OWNFrame.writeAreaLog(OWNUtilities.getDateTime() + " Rx: " + frame + " " + "(" + messageDescription + ")"); LOG.info("Frame received from OWN gateway: '{}'", frame); // notify event notifyEvent(event); LOG.debug("EVENTO NOTIFICATO: " + event.getPayload().getStatements()); } return; } }