org.harctoolbox.harchardware.misc.EzControlT10 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of HarcHardware Show documentation
Show all versions of HarcHardware Show documentation
Helper functions for accessing hardware etc.
/*
Copyright (C) 2009-2012 Bengt Martensson.
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 3 of the License, 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
this program. If not, see http://www.gnu.org/licenses/.
*/
package org.harctoolbox.harchardware.misc;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.Locale;
import org.harctoolbox.harchardware.HarcHardwareException;
import org.harctoolbox.harchardware.IHarcHardware;
import org.harctoolbox.harchardware.comm.IWeb;
import org.harctoolbox.ircore.XmlUtils;
import org.harctoolbox.irp.IrpUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public final class EzControlT10 implements IHarcHardware, IWeb {
public final static String defaultEzcontrolIP = "192.168.1.42";
private final static int ezcontrolPortno = 7042;
private final static int ezcontrolQueryPortno = 7044;
private final static int bufferSize = 352;
public static final int t10NumberPresets = 32;
private final static String[] daynames = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
public static final int t10NumberTimers = 26;
private static int fs20Time(double secs) {
int quartersecs = (int) (4*secs);
int qMin = (int) Math.round(java.lang.Math.log(quartersecs/15.0)/java.lang.Math.log(2))+1;
if (qMin < 0)
qMin = 0;
int mult = (((qMin & 1) == 1) ? 2 : 1)
* (((qMin & 2) == 2) ? 4 : 1)
* (((qMin & 4) == 4) ? 16 : 1)
* (((qMin & 8) == 8) ? 256 : 1);
int m = quartersecs/mult;
int res = (qMin << 4) + m;
return res;
}
private static int encodeCommand(EZSystem system, Command cmd) {
return system == EZSystem.FS20 ? fs20EncodeCommand(cmd) : simpleEncodeCommand(cmd);
}
private static int fs20EncodeCommand(Command cmd) {
return cmd == Command.power_on ? 255
: cmd == Command.power_off ? 0
: cmd == Command.power_toggle ? 18
: cmd == Command.dim_up ? 19
: cmd == Command.dim_down ? 20
: cmd == Command.dim_max_time ? 48
: cmd == Command.dim_off_time ? 32
: cmd == Command.set_time ? 54
: -1;
}
private static int simpleEncodeCommand(Command cmd) {
return cmd == Command.power_on ? 1
: cmd == Command.power_off ? 0
: -1;
}
public static String getTimers(String hostname) {
return (new EzControlT10(hostname)).getTimers();
}
public static String getTimer(String hostname, int n) {
return (new EzControlT10(hostname)).getTimer(n);
}
public static String getTimer(String hostname, String name) {
return (new EzControlT10(hostname)).getTimer(name);
}
public static String getStatus(String hostname) {
return (new EzControlT10(hostname)).getStatus();
}
private static void usage() {
System.err.println("Usage:\n" + "ezcontrol [] get_status []\n"
+ "or\n" + "ezcontrol [] get_timer []\n"
+ "or\n" + "ezcontrol [] \n"
+ "or\n" + "ezcontrol [] \n"
+ "or\n" + "ezcontrol [] []\n"
+ "or\n" + "ezcontrol [] xml\n"
+ "\nwhere options=-h ,-d ,-# ,-v, -u\n"
+ "and command=power_on,power_off,power_toggle,get_status,...");
doExit(IrpUtils.EXIT_USAGE_ERROR);
}
private static void doExit(int exitcode) {
System.exit(exitcode);
}
@SuppressWarnings("ValueOfIncrementOrDecrementUsed")
public static void main(String args[]) {
boolean verbose = false;
String ezcontrolHost = defaultEzcontrolIP;
//int debug = 0;
int arg_i = 0;
int count = 1;
boolean presetMode = false;
boolean doGetStatus = false;
boolean doGetTimers = false;
boolean doXml = false;
Command cmd = Command.invalid;
//String commandName = null;
String timerName = null;
EZSystem system = null;
String housecode = null;
int deviceNumber = -1;
int numArg = -1;
int percentValue = -1;
int value = -1;
int arg = -1;
boolean udp = false;
try {
while (arg_i < args.length && (args[arg_i].length() > 0) && args[arg_i].charAt(0) == '-') {
switch (args[arg_i]) {
case "-v":
verbose = true;
arg_i++;
break;
case "-u":
arg_i++;
udp = true;
break;
case "-h":
arg_i++;
ezcontrolHost = args[arg_i++];
break;
case "-d":
arg_i++;
//debug = Integer.parseInt(args[arg_i++]);
break;
case "-#":
arg_i++;
count = Integer.parseInt(args[arg_i++]);
break;
default:
usage();
break;
}
}
if (args[arg_i].equals("getStatus")) {
doGetStatus = true;
if (args.length - arg_i > 1) {
numArg = Integer.parseInt(args[arg_i + 1]);
}
} else if (args[arg_i].equals("getTimer")) {
doGetTimers = true;
if (args.length - arg_i > 1) {
timerName = args[arg_i + 1];
}
} else if (args[arg_i].equals("xml")) {
doXml = true;
} else if (args.length - arg_i == 2) {// Preset command
presetMode = true;
numArg = Integer.parseInt(args[arg_i]);
try {
cmd = Command.valueOf(args[arg_i + 1]);
} catch (IllegalArgumentException e) { // FIXME
cmd = Command.set_power;
percentValue = Integer.parseInt(args[arg_i + 1]);
}
} else {
system = EZSystem.parse(args[arg_i]);
housecode = args[arg_i + 1];
String devString = args[arg_i + 2];
deviceNumber = devString.charAt(0) > '9'
? devString.toUpperCase(Locale.US).charAt(0) - 'A'
: Integer.parseInt(devString);
cmd = Command.valueOf(args[arg_i + 3].toLowerCase(Locale.US));
value = encodeCommand(system, cmd);
arg = args.length > arg_i + 4 ? Integer.parseInt(args[arg_i + 4]) : -1;
if (cmd.hasTimeArgument())
arg = fs20Time(arg);
}
} catch (ArrayIndexOutOfBoundsException | NumberFormatException ex) {
usage();
}
if (numArg != -1 && (numArg < 1 || numArg > t10NumberPresets)) {
System.err.println("Numerical argument not valid.");
System.exit(45);
}
if (deviceNumber != -1 && value == -1) {
System.err.println("Only commands power_on and power_off allowed.");
System.exit(46);
}
EzControlT10 ez = new EzControlT10(ezcontrolHost, verbose, udp ? Interface.udp : Interface.http);
try {
if (doGetStatus) {
if (numArg > 0) {
System.out.println(ez.getPresetString(numArg));
System.out.println(ez.getPresetName(numArg));
} else {
System.out.println(ez.getStatus());
}
} else if (doGetTimers) {
if (timerName != null) {
System.out.println(ez.getTimer(timerName));
} else {
System.out.println(ez.getTimers());
}
} else if (doXml) {
ez.generateXml();
} else if (presetMode) {
if (cmd == Command.set_power)
ez.sendPreset(numArg, percentValue);
else
ez.sendPreset(numArg, cmd);
} else {
ez.sendManual(system, housecode, deviceNumber, value, arg, count);
}
} catch (HarcHardwareException ex) {
System.err.println(ex.getMessage());
}
}
public static boolean isPresetCommand(String cmd) {
try {
return Command.valueOf(cmd).isPresetCommand();
} catch (IllegalArgumentException ex) {
return false;
}
}
// UDP control presently not implemented for manual selection.
private String ezcontrolIP;
private int soTimeout = 1000;
private boolean verbose = true;
private int debug = 0;
private Interface interfaze = Interface.http;
private Status[] state = null; // Note: element 0 unused,
//starts with 0, T10 starts with 1
private Timer[] timers = null;
public EzControlT10(String hostname, boolean verbose, Interface interfaze) {
ezcontrolIP = (hostname != null && ! hostname.isEmpty()) ? hostname : defaultEzcontrolIP;
this.verbose = verbose;
this.interfaze = interfaze;
}
public EzControlT10(String hostname, boolean verbose) {
this(hostname, verbose, Interface.http);
}
public EzControlT10(String hostname) {
this(hostname, false, Interface.http);
}
@Override
public void close() {
}
@Override
public URI getUri(String user, String password) {
try {
return new URI("http", ezcontrolIP, null, null);
} catch (URISyntaxException ex) {
return null;
}
}
@Override
public void open() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void setDebug(int debug) {
this.debug = debug;
}
@Override
public void setTimeout(int timeout) {
this.soTimeout = timeout;
}
/**
* Dummy implementation.
* @return The String "unknown".
*/
@Override
public String getVersion() {
return "unknown";
}
/**
* Dummy implementation, always returns true
* @return true
*/
@Override
public boolean isValid() {
return true;
}
@Override
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
public void setInterface(Interface interfaze) {
this.interfaze = interfaze;
}
public boolean sendManual(EZSystem system, String house, int device,
int value, int arg, int n) throws HarcHardwareException {
try {
getUrl(urlManual(system, house, device, value, arg, n));
return true;
} catch (MalformedURLException ex) {
throw new HarcHardwareException(ex);
} catch (IOException ex) {
throw new HarcHardwareException(ex);
}
}
public boolean sendManual(EZSystem system, String house, int device,
Command cmd, int power, int arg, int n) throws HarcHardwareException {
return cmd == Command.set_power ? sendManual(system, house, device, power*16/100, -1, n)
: cmd == Command.dim_max_time ? sendManual(system, house, device, 48, fs20Time(arg), n)
: cmd == Command.dim_off_time ? sendManual(system, house, device, 32, fs20Time(arg), n)
: cmd == Command.dim_value_time ? sendManual(system, house, device, 32+power*16/100, fs20Time(arg), n)
: sendManual(system, house, device, encodeCommand(system, cmd), arg, n);
}
public boolean sendManual(EZSystem system, String house, int device,
Command cmd, int arg, int n) throws HarcHardwareException {
return sendManual(system, house, device, encodeCommand(system, cmd), arg, n);
}
// throws IllegalArgumentException
public String urlManual(String systemName, String house, int device,
int value, int arg, int n) {
return urlManual(EZSystem.parse(systemName), house, device, value, arg, n);
}
public String urlManual(EZSystem system, String house, int device,
int value, int arg, int n) {
String url = null;
switch (system) {
case FS20:
url = fs20Url(house, device, value, arg, n);
break;
case RS200:
url = rs200Url(house, device, value, n);
break;
case AB400:
url = ab400Url(house, device, value, n);
break;
case IT:
url = intertechnoUrl(house.charAt(0), device, value, n);
break;
case MARMI:
url = x10Url(house.charAt(0), device, value, n);
break;
default:
System.err.println("Sorry, system " + system + " is not yet implemented.");
break;
}
return url;
}
// Callable as special command
public String powerToggle(String preset) throws HarcHardwareException {
return sendPreset(Integer.parseInt(preset), Command.power_toggle) ? "" : null;
}
public boolean sendPreset(int switchNumber, Command cmd) throws HarcHardwareException {
Command actualCommand = cmd != Command.power_toggle ? cmd
: (getStatus(switchNumber) == 0 ? Command.power_on : Command.power_off);
try {
return interfaze == Interface.udp ? udpSendPreset(switchNumber, actualCommand) : getUrl(urlPreset(switchNumber, actualCommand));
} catch (MalformedURLException ex) {
throw new HarcHardwareException(ex);
} catch (IOException ex) {
throw new HarcHardwareException(ex);
}
}
public boolean sendPreset(int switchNumber, Command cmd, int count) throws HarcHardwareException {
boolean result = true;
for (int i = 0; i < count; i++) {
boolean stat = sendPreset(switchNumber, cmd);
result &= stat;
}
return result;
}
public boolean sendPreset(int switchNumber, int value) throws IllegalArgumentException, HarcHardwareException {
try {
// Not possible with udp.
return getUrl(urlPreset(switchNumber, value));
} catch (MalformedURLException ex) {
throw new HarcHardwareException(ex);
} catch (IOException ex) {
throw new HarcHardwareException(ex);
}
}
public boolean sendPreset(int switchNumber, int value, int count) throws HarcHardwareException {
boolean result = true;
for (int i = 0; i < count; i++) {
boolean stat = sendPreset(switchNumber, value);
result &= stat;
}
return result;
}
private boolean udpSendPreset(int switchNumber, Command cmd) {
if (verbose)
System.err.println("Sending command `" + cmd + "' to preprogrammed " + switchNumber + " to T10 `" + ezcontrolIP + "' over UDP.");
InetAddress addr;
try {
addr = InetAddress.getByName(ezcontrolIP);
} catch (UnknownHostException ex) {
System.err.println("Unknown host: " + ezcontrolIP);
return false;
}
byte[] buf = new byte[8];
buf[2] = 1;
buf[3] = (byte) 171;
buf[4] = (byte) (switchNumber - 1);
buf[5] = 0;
buf[6] = (byte) (cmd == Command.power_off ? 0 : 255);
buf[7] = 0;
int sum = checksum(buf);
buf[0] = (byte) (sum & 0xff);
buf[1] = (byte) (sum >> 8);
DatagramPacket dp = new DatagramPacket(buf, buf.length, addr, ezcontrolPortno);
return udpSendCheck(dp);
}
private boolean udpSendCheck(DatagramPacket dp) {
boolean success = false;
try (DatagramSocket sock = new DatagramSocket()) {
sock.setSoTimeout(soTimeout);
sock.send(dp);
byte[] error = new byte[6];
DatagramPacket errorPacket = new DatagramPacket(error, error.length);
sock.receive(errorPacket);
int sum = checksum(error);
if (!(((sum & 0xff) == error[0]) && ((sum >> 8) == error[1]) && (error[4] == 0) && (error[5] == 0))) {
System.err.println("Erroneous response from T10");
} else
success = true;
} catch (IOException e) {
if (e.getClass() == SocketTimeoutException.class)
System.err.println("UDP socket timeout from " + ezcontrolIP);
else
System.err.println(e.getMessage());
}
return success;
}
private int checksum(byte[] buf) {
int sum = 0;
for (int i = 2; i < buf.length; i += 2)
sum += ubyte(buf[i]) + 256 * ubyte(buf[i + 1]);
return sum;
}
private int ubyte(byte b) {
return b < 0 ? b + 256 : b;
}
private boolean udpExtractState(byte[] buf) {
return buf != null ? (buf[66] != 0) : false;
}
private String udpExtractName(byte[] buf) {
try {
return buf != null ? (new String(buf, 6, 32, "US-ASCII")).replaceAll("\u0000", "") : null;
} catch (UnsupportedEncodingException ex) {
assert false;
return null;
}
}
private byte[] udpStatusInquiry(int n) {
if (verbose)
System.err.println("Inquiring state from T10 `" + ezcontrolIP + "' on preset " + n + " using UDP.");
byte[] buf = new byte[bufferSize];
buf[0] = 0x11;
buf[1] = 0x67;
buf[2] = 2;
buf[3] = 0;
buf[4] = (byte) (n - 1);
buf[5] = 0;
buf[bufferSize - 4] = (byte) 0xff;
buf[bufferSize - 3] = (byte) 0xff;
InetAddress addr;
try {
addr = InetAddress.getByName(ezcontrolIP);
} catch (UnknownHostException ex) {
System.err.println("Unknown host: " + ezcontrolIP);
return null;
}
DatagramPacket dp = new DatagramPacket(buf, buf.length, addr, ezcontrolQueryPortno);
try (DatagramSocket sock = new DatagramSocket()) {
sock.setSoTimeout(soTimeout);
sock.send(dp);
sock.receive(dp);
} catch (IOException e) {
if (e.getClass() == SocketTimeoutException.class)
System.err.println("UDP socket timeout from " + ezcontrolIP);
else
System.err.println(e.getMessage());
buf = null;
}
return buf;
}
private String fs20Url(String houseRaw, int device, int value, int arg, int n) {
try {
String house = houseRaw.replaceAll("\\s+", "");
int hc1 = Integer.parseInt(house.substring(0, 4));
int hc2 = Integer.parseInt(house.substring(4));
return urlManual(EZSystem.FS20, hc1, hc2, device, value, arg, n);
} catch (NumberFormatException ex) {
throw new RuntimeException("String \"" + houseRaw + "\" is not a valid housenumber for FS20.");
}
}
private String ab400Url(String house, int device, int value, int n) {
try {
int hc1 = Integer.parseInt(house);
return urlManual(EZSystem.AB400, hc1, 0, device + 1, value, -1, n);
} catch (NumberFormatException ex) {
throw new RuntimeException("String \"" + house + "\" is not a valid housenumber for AB400.");
}
}
private String intertechnoUrl(char house, int device, int value, int n) {
return intertechnoUrl(Character.toUpperCase(house) - 'A' + 1,
(device - 1) / 4 + 1,
(device - 1) % 4 + 1,
value, n);
}
private String intertechnoUrl(int hc1, int hc2, int addr, int value, int n) {
return urlManual(EZSystem.IT, hc1, hc2, addr, value, -1, n);
}
private String x10Url(char house, int device, int value, int n) {
return x10Url(Character.toUpperCase(house) - 'A' + 1, device, value, n);
}
private String x10Url(int hc1, int addr, int value, int n) {
return urlManual(EZSystem.MARMI, hc1, 0, addr, value, -1, n);
}
private String rs200Url(String house, int device, int value, int n) {
return urlManual(EZSystem.RS200, Integer.parseInt(house), 0, device, value, -1, n);
}
private String urlManual(EZSystem system, int hc1, int hc2, int device, int value, int arg, int n) {
return "http://" + ezcontrolIP + "/send?system=" + system.systemNumber()
+ "&hc1=" + hc1
+ (hc2 != 0 ? "&hc2=" + hc2 : "")
+ "&addr=" + device + "&value=" + value
+ (arg >= 0 ? "&arg=" + arg : "")
+ (n > 1 ? "&n=" + n : "");
}
public String urlPreset(int switchNumber, Command cmd) {
if (cmd != Command.power_on && cmd != Command.power_off) {
throw new IllegalArgumentException("Command " + cmd + " not allowed here.");
}
return urlPreset(switchNumber, cmd == Command.power_on ? "on" : "off");
}
public String urlPreset(int switchNumber, int value) throws IllegalArgumentException {
if (value < 0 || value > 100)
throw new IllegalArgumentException("value out of range");
return urlPreset(switchNumber, Integer.toString(value));
}
private String urlPreset(int switchNumber, String val) {
return "http://" + ezcontrolIP + "/preset?switch=" + switchNumber + "&value=" + val;
}
private boolean getUrl(String url) throws MalformedURLException, IOException {
if (verbose)
System.err.println("Getting URL " + url);
(new URL(url)).openStream();
return true;
}
public String getStatus() {
setupStatus();
StringBuilder result = new StringBuilder(32);
for (int i = 0; i < t10NumberPresets; i++) {
if (state[i] != null) {
result.append(i).append(".\t").append(state[i].toString()).append("\n");
}
}
return result.toString();
}
public int getStatus(int n) {
if (interfaze == Interface.udp)
return udpExtractState(udpStatusInquiry(n)) ? 1 : 0;
else {
setupStatus();
return state[n].state;
}
}
public String getPresetStatus(int n) {
if (interfaze == Interface.udp)
return udpExtractState(udpStatusInquiry(n)) ? "on" : "off";
else {
setupStatus();
return state[n] != null ? state[n].stateStr() : "n/a";
}
}
public String getPresetName(int n) {
if (interfaze == Interface.udp) {
byte[] buf = udpStatusInquiry(n);
return udpExtractName(buf);
} else {
setupStatus();
return state[n] != null ? state[n].name : "**not assigned**";
}
}
public String getPresetString(int n) {
if (interfaze == Interface.udp) {
byte[] buf = udpStatusInquiry(n);
return buf != null ? (udpExtractName(buf) + (udpExtractState(buf) ? ": on" : ": off")) : "**error**";
} else {
setupStatus();
return state[n] != null ? state[n].toString() : "Preset " + n + " not assigned.";
}
}
private boolean setupStatus() {
if (state != null) {
return true;
}
String url = "http://" + ezcontrolIP + "/";
if (verbose) {
System.err.println("Getting URL " + url);
}
StringBuilder data = new StringBuilder(32);
BufferedReader r = null;
boolean success = true;
try {
InputStream is = (new URL(url)).openStream();
r = new BufferedReader(new InputStreamReader(is, Charset.forName("US-ASCII")));
String str;
do {
str = r.readLine();
data.append(str);
} while (str != null);
} catch (java.net.MalformedURLException e) {
System.err.println(e.getMessage());
success = false;
} catch (java.io.IOException e) {
System.err.println("IOException: " + e.getMessage());
success = false;
} finally {
try {
if (r != null)
r.close();
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
if (!success)
return false;
String[] snork = data.toString().split("");
state = new Status[t10NumberPresets + 1];
for (int i = 1; i < snork.length; i++) {
int p1 = snork[i].indexOf('>');
int p2 = snork[i].indexOf('<', p1);
int n = Integer.parseInt(snork[i].substring(p1 + 1, p2));
p1 = snork[i].indexOf('>', p2 + 5);
p2 = snork[i].indexOf('<', p1);
String name = snork[i].substring(p1 + 1, p2);
int stat =
snork[i].matches(".*background:lime.*") ? Status.on
: snork[i].matches(".*background:red.*") ? Status.off
: Status.unknown;
//System.out.println("" + n + ": " + name + stat);
state[n] = new Status(name, stat);
}
return true;
}
private int extractValue(String str) {
int res = -1;
if (str.matches(".*value.*")) {
int p1 = str.indexOf("value");
int p2 = str.indexOf('"', p1 + 7);
res = Integer.parseInt(str.substring(p1 + 7, p2));
}
return res;
}
@SuppressWarnings({"empty-statement", "ValueOfIncrementOrDecrementUsed"})
private boolean setupTimers() {
if (timers != null) {
return true;
}
String url = "http://" + ezcontrolIP + "/timer.html";
if (verbose) {
System.err.println("Getting URL " + url);
}
StringBuilder data = new StringBuilder(32);
BufferedReader r = null;
try {
InputStream is = (new URL(url)).openStream();
r = new BufferedReader(new InputStreamReader(is, Charset.forName("US-ASCII")));
String str;
do {
str = r.readLine();
data.append(str);
} while (str != null);
} catch (java.net.MalformedURLException e) {
System.err.println(e.getMessage());
return false;
} catch (java.io.IOException e) {
System.err.println("IOException: " + e.getMessage());
return false;
} finally {
try {
if (r != null)
r.close();
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
String[] snork = data.toString().split("");
//int n = (int) snork[i].charAt(p1 + 4) - (int) 'A';
String[] inputs = snork[i].split(">");
boolean[] presets = new boolean[t10NumberPresets + 1];
boolean[] days = new boolean[7];
int indx = 0;
do
;
while (!inputs[indx++].matches("Switches.*"));
for (int j = 1; j <= t10NumberPresets;) {
if (inputs[indx].matches(".*= 0 && n < t10NumberTimers) {
result = getTimer((name.charAt(0) - 'A') % 32);
} else {
System.err.println("Erroneous timer name \"" + name + "\".");
}
return result;
}
public Document xmlConfig() {
Document doc = XmlUtils.newDocument();
Element root = doc.createElement("ezcontrol_t10");
root.setAttribute("hostname", ezcontrolIP);
doc.appendChild(root);
Element presets = doc.createElement("presets");
root.appendChild(presets);
setupStatus();
for (int i = 1; i <= t10NumberPresets; i++) {
if (state[i] != null) {
Element p = doc.createElement("preset");
p.setAttribute("id", "preset_" + i);
p.setAttribute("number", "" + i);
p.setAttribute("state", state[i].stateStr());
p.setTextContent(state[i].name);
presets.appendChild(p);
}
}
Element presetConfiguration = doc.createElement("preset_configuration");
root.appendChild(presetConfiguration);
Element timersEle = doc.createElement("timers");
root.appendChild(timersEle);
setupTimers();
for (int i = 0; i < t10NumberTimers; i++) {
if (timers[i] != null) {
Element t = doc.createElement("timer");
t.setAttribute("name", "" + (char) (i + 'A'));
t.setAttribute("enabled", timers[i].enabled ? "yes" : "no");
if (timers[i].onTime.hour != -1) {
Element on = doc.createElement("on");
on.setAttribute("hour", "" + timers[i].onTime.hour);
on.setAttribute("minute", "" + timers[i].onTime.minute);
t.appendChild(on);
}
if (timers[i].offTime.hour != -1) {
Element off = doc.createElement("off");
off.setAttribute("hour", "" + timers[i].offTime.hour);
off.setAttribute("minute", "" + timers[i].offTime.minute);
t.appendChild(off);
}
boolean atLeastOneDay = false;
for (int j = 0; j < 7; j++) {
atLeastOneDay = atLeastOneDay || timers[i].days[j];
}
if (atLeastOneDay) {
Element days = doc.createElement("days");
for (int j = 0; j < 7; j++) {
if (timers[i].days[j]) {
Element day = doc.createElement("day");
day.setAttribute("weekday", "" + (j + 1));
day.setAttribute("name", daynames[j]);
days.appendChild(day);
}
}
t.appendChild(days);
}
boolean atLeastOnePreset = false;
for (int j = 1; j <= t10NumberPresets; j++) {
atLeastOnePreset = atLeastOnePreset || timers[i].presets[j];
}
if (atLeastOnePreset) {
Element presetrefs = doc.createElement("presetrefs");
for (int j = 1; j <= t10NumberPresets; j++) {
if (timers[i].presets[j]) {
Element presetref = doc.createElement("presetref");
presetref.setAttribute("preset", "preset_" + j);
presetref.setTextContent(state[j].name);
presetrefs.appendChild(presetref);
}
}
t.appendChild(presetrefs);
}
timersEle.appendChild(t);
}
}
Element network = doc.createElement("network");
root.appendChild(network);
return doc;
}
private void generateXml() {
XmlUtils.printDOM(System.out, xmlConfig(), null, null);
}
public void generateXml(File file) throws FileNotFoundException {
XmlUtils.printDOM(file, xmlConfig(), null, null, null);
}
public void getConfiguration(File file) {
try {
XmlUtils.printDOM(file, xmlConfig(), null, null, null);
} catch (FileNotFoundException e) {
System.err.println(e.getMessage());
}
}
private static class Status {
public final static int on = 1;
public final static int off = 0;
public final static int unknown = -1;
public String name;
public int state;
Status(String n, int s) {
name = n;
state = s;
}
public String stateStr() {
return state == on ? "on" : state == off ? "off" : "?";
}
@Override
public String toString() {
return name + ": " + stateStr();
}
}
/** Interfaces that can be used to command an T10 */
public enum Interface {
udp,
http
}
public enum EZSystem {
/** The FS-10 system, now obsolete. */
FS10, // 1
/** The FS-20 system from ELV or Conrad. */
FS20, // 2
/** The RS200 system, once sold by Conrad. */
RS200,
/** ELRO AB400 */
AB400,
/** ELRO AB601 */
AB601,
/** Intertechno, and similar (Düwi, One 4 all, etc) "with codewheel" */
IT, // Intertechno, 6
/** REV Ritter */
REV,
/** Brennenstuhl und Quigg */
BS_QU,
/** The X10 system, for example by Marmitek. */
MARMI, // X10, 9
/** InScenio OASE FM-Master */
OA_FM,
/** Kopp first control, only first generation */
KO_FC,
/** Europe Supplies Ltd. */
RS862;
public static EZSystem parse(String systemName) {
return systemName.toLowerCase(Locale.US).equals("intertechno") ? IT
: systemName.toLowerCase(Locale.US).equals("conrad") ? RS200
: systemName.toLowerCase(Locale.US).equals("x10") ? MARMI
: valueOf(systemName.replace('-', '_').toUpperCase(Locale.US));
}
/**
* Returns the system number as used in the official documentation.
* @return
*/
public int systemNumber() {
return ordinal() + 1;
}
public boolean hasHouseLetter() {
//int sysno = systemNumber(system);
return this == AB601 || this == IT || this == MARMI;
}
public boolean hasDeviceLetter() {
//int sysno = systemNumber(system);
return this == AB400;
}
}
/**
* An enum consisting of the commands this class understands.
*/
public enum Command {
power_on,
power_off,
power_toggle,
dim_up,
dim_down,
dim_max_time,
dim_off_time,
set_time,
/** Takes two arguments, the goal power, and the time to be taken. */
dim_value_time,
/** Takes an argument, power in percents. */
set_power,
get_status,
/** Marker for invalid command. */
invalid;
/**
* Returns true iff the command can be used as a present command.
* @return
*/
public boolean isPresetCommand() {
return this == get_status || this == set_power // Requires FW 2.26
|| this == power_toggle || this == power_on
|| this == power_off;
}
/**
* Returns true iff the command uses a time argument.
* @return
*/
public boolean hasTimeArgument() {
return this == dim_max_time || this == dim_off_time || this == set_time;
}
}
private class Timer {
boolean[] presets;
boolean[] days;
boolean enabled;
Clock onTime;
Clock offTime;
Timer(boolean[] presets, boolean[] days, boolean enabled, int onH, int onM, int offH, int offM) {
this.presets = presets;
this.days = days;
this.enabled = enabled;
onTime = new Clock(onH, onM);
offTime = new Clock(offH, offM);
}
@Override
public String toString() {
StringBuilder result = new StringBuilder(onTime.toString() + "-" + offTime.toString() + " ");
boolean virgin = true;
for (int i = 0; i < 7; i++) {
if (days[i]) {
if (((i == 0) || !days[i - 1]) || ((i == 6) || !days[i + 1])) {
result.append(virgin ? "" : (days[i - 1] ? "-" : ",")).append(daynames[i]);
}
virgin = false;
}
}
for (int i = result.length(); i < 30; i++) {
result.append(" ");
}
result.append(" ");
virgin = true;
for (int i = 1; i < t10NumberPresets; i++) {
if (presets[i]) {
result.append(virgin ? "" : ", ").append(state[i].name);
virgin = false;
}
}
for (int i = result.length(); i < 65; i++) {
result.append(" ");
}
return result.append(" ").append(enabled ? "(enabled)" : "(disabled)").toString();
}
private class Clock {
int hour;
int minute;
Clock(int h, int m) {
hour = h;
minute = m;
}
@Override
public String toString() {
return "" + (hour >= 0
? (hour < 10 ? "0" : "") + (hour + ":" + (minute < 10 ? "0" : "") + minute)
: " ");
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy