7 changed files with 233 additions and 6 deletions
@ -0,0 +1,221 @@
@@ -0,0 +1,221 @@
|
||||
package de.srsoftware.web4rail.tiles; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.concurrent.TimeoutException; |
||||
|
||||
import org.json.JSONObject; |
||||
|
||||
import de.srsoftware.tools.Tag; |
||||
import de.srsoftware.web4rail.Command; |
||||
import de.srsoftware.web4rail.Command.Reply; |
||||
import de.srsoftware.web4rail.Device; |
||||
import de.srsoftware.web4rail.Protocol; |
||||
import de.srsoftware.web4rail.tags.Fieldset; |
||||
import de.srsoftware.web4rail.tags.Input; |
||||
import de.srsoftware.web4rail.tags.Label; |
||||
import de.srsoftware.web4rail.tags.Radio; |
||||
|
||||
public class Relay extends Tile implements Device{ |
||||
public static final String STATE = "state"; |
||||
private static final String PORT_A = "port_a"; |
||||
private static final String PORT_B = "port_b"; |
||||
protected static final String STRAIGHT = "straight"; |
||||
|
||||
private Protocol protocol = Protocol.DCC128; |
||||
protected int address = 0; |
||||
protected int portA = 0, portB = 1; |
||||
protected int delay = 400; |
||||
protected boolean initialized = false; |
||||
protected boolean error = false; |
||||
private String stateLabelA = "A"; |
||||
private String stateLabelB = "B"; |
||||
protected boolean state = true; |
||||
|
||||
public static final boolean STATE_A = true,STATE_B=false; |
||||
private static final String LABEL_A = "label_a"; |
||||
private static final String LABEL_B = "label_b"; |
||||
|
||||
@Override |
||||
public Object click() throws IOException { |
||||
Object o = super.click(); |
||||
state(!state); |
||||
return o; |
||||
} |
||||
|
||||
protected String commandFor(boolean newState) { |
||||
return "SET {} GA "+address+" "+(newState?portA:portB)+" 1 "+delay; |
||||
} |
||||
|
||||
public void error(Reply reply) { |
||||
this.error = true; |
||||
try { |
||||
plan.stream(tag(null).toString()); |
||||
} catch (IOException e) { |
||||
LOG.error("Was not able to stream: ",e); |
||||
} |
||||
throw new RuntimeException(reply.message()); |
||||
} |
||||
|
||||
protected Reply init() { |
||||
if (!initialized) { |
||||
Command command = new Command("INIT {} GA "+address+" "+proto()) { |
||||
|
||||
@Override |
||||
public void onSuccess() { |
||||
super.onSuccess(); |
||||
initialized = true; |
||||
} |
||||
|
||||
@Override |
||||
public void onFailure(Reply r) { |
||||
super.onSuccess(); |
||||
initialized = false; |
||||
} |
||||
|
||||
}; |
||||
try { |
||||
return plan.queue(command).reply(); |
||||
} catch (TimeoutException e) { |
||||
LOG.warn(e.getMessage()); |
||||
} |
||||
} |
||||
return new Reply(200, "OK"); |
||||
} |
||||
|
||||
@Override |
||||
public JSONObject json() { |
||||
JSONObject json = super.json(); |
||||
if (portA != 0) json.put(PORT_A, portA); |
||||
if (portB != 1) json.put(PORT_B, portB); |
||||
if (address != 0) json.put(ADDRESS, address); |
||||
json.put(PROTOCOL, protocol); |
||||
json.put(LABEL_A, stateLabelA); |
||||
json.put(LABEL_B, stateLabelB); |
||||
return json; |
||||
} |
||||
|
||||
@Override |
||||
protected Tile load(JSONObject json) throws IOException { |
||||
if (json.has(ADDRESS)) address = json.getInt(ADDRESS); |
||||
if (json.has(PORT_A)) portA = json.getInt(PORT_A); |
||||
if (json.has(PORT_B)) portB = json.getInt(PORT_B); |
||||
if (json.has(LABEL_A)) stateLabelA = json.getString(LABEL_A); |
||||
if (json.has(LABEL_B)) stateLabelB = json.getString(LABEL_B); |
||||
if (json.has(PROTOCOL)) protocol = Protocol.valueOf(json.getString(PROTOCOL)); |
||||
return super.load(json); |
||||
} |
||||
|
||||
@Override |
||||
public Tag propForm(String id) { |
||||
Tag form = super.propForm(id); |
||||
Fieldset fieldset = new Fieldset(t("Decoder settings")); |
||||
Label protocol = new Label(t("Protocol:")); |
||||
for (Protocol proto : Protocol.values()) { |
||||
new Radio(PROTOCOL, proto.toString(), t(proto.toString()), proto == this.protocol).addTo(protocol); |
||||
} |
||||
protocol.addTo(fieldset); |
||||
new Input(ADDRESS, address).numeric().addTo(new Label(t("Address"))).addTo(fieldset).addTo(form); |
||||
fieldset = new Fieldset(t("Ports and Labels")); |
||||
new Input(PORT_A, portA).numeric().addTo(new Label(t("Port for state A"))).addTo(fieldset); |
||||
new Input(LABEL_A, stateLabelA).addTo(new Label(t("Label for state A"))).addTo(fieldset); |
||||
new Input(PORT_B, portB).numeric().addTo(new Label(t("Port for state B"))).addTo(fieldset); |
||||
new Input(LABEL_B, stateLabelB).addTo(new Label(t("Label for state B"))).addTo(fieldset); |
||||
fieldset.addTo(form); |
||||
return form; |
||||
} |
||||
|
||||
private char proto() { |
||||
switch (protocol) { |
||||
case DCC14: |
||||
case DCC27: |
||||
case DCC28: |
||||
case DCC128: |
||||
return 'N'; |
||||
case MOTO: |
||||
return 'M'; |
||||
case SELECTRIX: |
||||
return 'S'; |
||||
default: |
||||
return 'P'; |
||||
} |
||||
} |
||||
|
||||
public Relay setLabel(boolean state, String tx) { |
||||
if (state) { |
||||
stateLabelA = tx; |
||||
} else stateLabelB = tx; |
||||
return this; |
||||
} |
||||
|
||||
public boolean state() { |
||||
return state; |
||||
} |
||||
|
||||
public Reply state(boolean newState) throws IOException { |
||||
Reply reply = init(); |
||||
if (reply != null && !reply.succeeded()) return reply; |
||||
LOG.debug("Setting {} to {}",this,newState); |
||||
try { |
||||
String cmd = commandFor(newState); |
||||
return plan.queue(new Command(cmd) { |
||||
|
||||
@Override |
||||
public void onSuccess() { |
||||
super.onSuccess(); |
||||
try { |
||||
Relay.this.state = newState; |
||||
plan.place(Relay.this); |
||||
} catch (IOException e) {} |
||||
} |
||||
|
||||
@Override |
||||
protected void onFailure(Reply reply) { |
||||
super.onFailure(reply); |
||||
plan.stream(t("Unable to switch \"{}\": {}",Relay.this,reply.message())); |
||||
} |
||||
|
||||
}).reply(); |
||||
} catch (TimeoutException e) { |
||||
LOG.warn(e.getMessage()); |
||||
} |
||||
return new Reply(417,t("Timeout while trying to switch {}.",this)); |
||||
|
||||
|
||||
} |
||||
|
||||
public void success() { |
||||
this.error = false; |
||||
try { |
||||
plan.stream(tag(null).toString()); |
||||
} catch (IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Tag tag(Map<String, Object> replacements) throws IOException { |
||||
if (replacements == null) replacements = new HashMap<String, Object>(); |
||||
replacements.put("%text%",state ? stateLabelA : stateLabelB); |
||||
Tag tag = super.tag(replacements); |
||||
tag.clazz(tag.get("class")+(" "+state).toLowerCase()+(error?" error":"")); |
||||
return tag; |
||||
} |
||||
|
||||
@Override |
||||
public String title() { |
||||
return getClass().getSimpleName()+t("(Address: {}, Ports {} and {})",address,portA,portB); |
||||
} |
||||
|
||||
@Override |
||||
public Tile update(HashMap<String, String> params) throws IOException { |
||||
if (params.containsKey(PROTOCOL)) protocol = Protocol.valueOf(params.get(PROTOCOL)); |
||||
if (params.containsKey(ADDRESS)) address = Integer.parseInt(params.get(ADDRESS)); |
||||
if (params.containsKey(PORT_A)) portA = Integer.parseInt(params.get(PORT_A)); |
||||
if (params.containsKey(PORT_B)) portB = Integer.parseInt(params.get(PORT_B)); |
||||
if (params.containsKey(LABEL_A)) stateLabelA = params.get(LABEL_A); |
||||
if (params.containsKey(LABEL_B)) stateLabelB = params.get(LABEL_B); |
||||
return super.update(params); |
||||
} |
||||
} |
Loading…
Reference in new issue