package code; import java.io.IOException; import java.util.Date; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.json.JSONException; import org.json.JSONObject; public class SubscribeCallback implements MqttCallback { private Antifurto client; private Publisher publisher; private Esecutore esec; private Automa automa; private int contatore = 0; // quando pubblico un messaggio per accendere la luce che indica che l'antifurto // e' on, incremento questa variabile. // Quando ricevo la conferma dal gpio, decremento il contatore. Questo contatore // non puo' scendere sotto a 0. // Ho introdotto questa variabile perche' sia il microservizio dell'antifurto // sia il microservizio degli scenari // inviano il comando allo stesso OUT per dire che l'antifurto e' acceso private String newSuonoConf = null; // quando arriva il comando per modificare la luce (OUT) che indica che // l'allarme sta suonando, questa variabile conterra' il nuovo nome // dell'OUT; altrimenti newSuonoConf = null private String newNomeOutputAntifurtoConf = null; // quando arriva il comando per modificare la luce (OUT) che indica che // l'antifurto e' acceso, questa variabile conterra' il nuovo nome // dell'OUT; altrimenti newNomeOutputAntifurto = null public SubscribeCallback(Antifurto client, Publisher publisher, Esecutore esec, Automa automa) { this.client = client; this.publisher = publisher; this.esec = esec; this.automa = automa; } @Override public void connectionLost(Throwable arg0) { boolean retry = true; final Date d = new Date(); Date d2 = new Date(); long time = Math.abs(d2.getTime() - d.getTime()); while (retry && (time < 600000)) { try { client.startClient(esec, publisher); retry = false; } catch (MqttException | JSONException e) { d2 = new Date(); time = Math.abs(d2.getTime() - d.getTime()); } } if (time >= 600000) { System.out.println("Tentativo di riconnessione fallito"); System.exit(1); } } @Override public void deliveryComplete(IMqttDeliveryToken arg0) { // Nessuna operazione } @Override public void messageArrived(String topic, MqttMessage message) throws JSONException, IOException { if (topic.equals("to/all")) { System.out.println("MESSAGGIO MQTT = " + message.toString()); if (message.toString().equals("{request:description}")) sendMyState("from/" + Antifurto.getMqttTree() + "/antifurto/description"); if (message.toString().equals("{request:status}")) sendMyStateToAll("from/" + Antifurto.getMqttTree() + "/antifurto"); return; } JSONObject msgJson = new JSONObject(message.toString()); if (topic.equals("conf/" + Antifurto.getMqttTree() + "/antifurto/sensore")) { if (msgJson.has("in") && msgJson.has("delta")) handleConfSensoreMovimento(msgJson); return; } if (topic.equals("conf/" + Antifurto.getMqttTree() + "/antifurto")) { handleNewConfig(msgJson); return; } if (topic.equals("to/" + Antifurto.getMqttTree() + "/antifurto/luceAntifurto")) { if (msgJson.has("request")) sendOutAntifurto(); return; } if (topic.equals("conf/" + Antifurto.getMqttTree() + "/antifurto/soglia")) { if (msgJson.has("soglia")) handleSetSoglia(msgJson); return; } if (topic.equals("rpc/" + Antifurto.getMqttTree() + "/antifurto")) { if (message.toString().equals("{\"request\":\"description\"}")) sendMyState("from/" + Antifurto.getMqttTree() + "/antifurto"); return; } if (topic.equals("from/" + Antifurto.getMqttTree() + "/gpio/" + client.getNomeOutputSuono())) { int newStatus = -1; if (msgJson.has("status")) newStatus = msgJson.getInt("status"); else { if (msgJson.has("event")) { if(newSuonoConf != null) { // sto facendo la configurazione. Si vuole modificare il nome dell'OUT che indica se l'allarme sta suonando try { newConfigNomeOutputSuono(newSuonoConf); sendResponseConf(); } catch (MqttException e) { sendErrorConf(e); } } else newStatus = msgJson.getInt("event"); } } handleStateMsgFromOutputSuono(newStatus); return; } if (topic.equals("from/" + Antifurto.getMqttTree() + "/gpio/" + client.getNomeOutputAntifurto())) { if (msgJson.has("event")) { if(newNomeOutputAntifurtoConf != null) { // sto facendo la configurazione. Si vuole modificare il nome dell'OUT che indica che l'antifurto e' acceso/spento try { newConfigNomeOutputAntifurto(newNomeOutputAntifurtoConf); sendResponseConf(); } catch (MqttException e) { sendErrorConf(e); } } else handleLuceAntifurto(); } if (msgJson.has("status")) setConsistentStatus(msgJson); return; } int event = msgJson.getInt("event"); if (event == 1) { // e' stato premuto l'interruttore / il sensore di movimento ha rilevato // qualcuno if (topic.equals("from/" + Antifurto.getMqttTree() + "/gpio/" + client.getNomeInterruttoreAntifurto())) { handleStateMsgFromInterruttore(); return; } // il topic sara' from/gruppo2/luci/gpio/IN2 dove IN2 e' un sensore di movimento if (topic.startsWith("from/" + Antifurto.getMqttTree() + "/gpio/IN")) { String[] t = topic.split("/"); handleMovimento(t[4]); } } } private synchronized void handleStateMsgFromInterruttore() { if (automa.getStatoInterruttore().equals("on")) // voglio spegnere l'antifurto, quindi invio un messaggio per spegnere la luce che indica che l'antifurto e' acceso publisher.aggiungiComando("to/" + Antifurto.getMqttTree() + "/gpio/" + client.getNomeOutputAntifurto(), "{cmd:0}"); // else // voglio accendere l'antifurto, quindi invio un messaggio per accendere la luce che indica che l'antifurto e' acceso publisher.aggiungiComando("to/" + Antifurto.getMqttTree() + "/gpio/" + client.getNomeOutputAntifurto(), "{cmd:1}"); contatore++; } private synchronized void handleLuceAntifurto() throws JSONException { contatore--; if (contatore < 0) { contatore = 0; return; } try { JSONObject js = new JSONObject(); automa.changeStatoInterruttore(); if (automa.getStatoInterruttore().equals("off")) { publisher.aggiungiComando("to/" + Antifurto.getMqttTree() + "/gpio/" + client.getNomeOutputSuono(), "{cmd:0}"); esec.reset(); js.put("event", esec.getValore()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/valore", js.toString()); } js.put("event", automa.getStatoInterrutoreTrueFalse()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/antifurto", js.toString()); } catch (IOException e) { JSONObject jsError = new JSONObject(); jsError.put("error", e.getMessage()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/antifurto", jsError.toString()); } } private synchronized void handleStateMsgFromOutputSuono(int newStatus) throws JSONException, IOException { if (newStatus != -1) { String statusOnOff = automa.converter(newStatus); // lo stato e' della forma "on" oppure "off" if (!statusOnOff.equals(automa.getStatoSuono())) { automa.aggiornaStatoSuono(statusOnOff); JSONObject js = new JSONObject(); js.put("event", automa.getStatoSuonoTrueFalse()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/allarme", js.toString()); js.put("event", esec.getValore()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/valore", js.toString()); } } } private void handleMovimento(String nomeSensore) { if (automa.getStatoInterruttore().equals("on")) esec.aggiungiVal(automa.getDelta(nomeSensore)); } private void handleConfSensoreMovimento(JSONObject toAdd) throws JSONException { // aggiorno il file che contiene l'associazione sensore-movimento, delta try { JSONObject sensori = new JSONObject(Helper.leggiFile(Automa.FILE_DELTA_SENSORI)); String nomeSensore = toAdd.getString("in").toUpperCase(); int delta = toAdd.getInt("delta"); sensori.put(nomeSensore, delta); Helper.scriviFile(sensori, Automa.FILE_DELTA_SENSORI); // aggiorno il file zona: ho un sensore di movimento in piu' JSONObject zona = new JSONObject(Helper.leggiFile(Antifurto.CONF_ZONA)); zona.getJSONArray("sensoriMovimento").put(nomeSensore); Helper.scriviFile(zona, Antifurto.CONF_ZONA); Antifurto.addSensore(nomeSensore); automa.addDeltaSensori(nomeSensore, delta); client.addTopicToSubscribe("from/" + Antifurto.getMqttTree() + "/gpio/" + nomeSensore); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/sensore", toAdd.toString()); // invio questo messaggio per confermare alla web app che il sensore di movimento e' stato aggiunto } catch (IOException | MqttException e) { JSONObject jsError = new JSONObject(); jsError.put("error", e.getMessage()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/sensore", jsError.toString()); } } private void handleSetSoglia(JSONObject jsSoglia) throws JSONException { try { Esecutore.setSoglia(jsSoglia.getInt("soglia")); JSONObject jsToSend = new JSONObject(); jsToSend.put("soglia", Esecutore.getSoglia()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/soglia", jsToSend.toString()); } catch (IOException e) { JSONObject jsError = new JSONObject(); jsError.put("error", e.getMessage()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/soglia", jsError.toString()); } } private void sendMyState(String topic) throws JSONException { JSONObject json = new JSONObject(); json.put("stato", automa.getStatoAutoma()); json.put("interruttore", client.getNomeInterruttoreAntifurto()); json.put("sensori-movimento", Antifurto.getSensori()); json.put("output-suono", client.getNomeOutputSuono()); json.put("output-antifurto", client.getNomeOutputAntifurto()); json.put("soglia", Esecutore.getSoglia()); json.put("allarme", automa.getStatoSuonoTrueFalse()); json.put("valore-attuale", esec.getValore()); json.put("antifurto", automa.getStatoInterrutoreTrueFalse()); publisher.aggiungiComando(topic, json.toString()); } private void setConsistentStatus(JSONObject msgJson) throws JSONException, IOException { int statoOutGpio = msgJson.getInt("status"); JSONObject js = new JSONObject(); if (statoOutGpio == 0 && automa.getStatoInterruttore().equals("on")) { // devo andare nello stato 0 dell'automa automa.setStatoAutoma(0); automa.aggiornaInterruttoreESuono(); esec.reset(); js.put("event", automa.getStatoInterrutoreTrueFalse()); } if (statoOutGpio == 1 && automa.getStatoInterruttore().equals("off")) { // devo andare nello stato 1 dell'automa automa.setStatoAutoma(1); automa.aggiornaInterruttoreESuono(); js.put("event", automa.getStatoInterrutoreTrueFalse()); } if(js.has("event")) { // aggiorno il file di persistenza JSONObject statoJson = new JSONObject(Helper.leggiFile(Automa.FILE_STATO)); statoJson.put("stato", automa.getStatoAutoma()); statoJson.put("valore", esec.getValore()); Helper.scriviFile(statoJson, Automa.FILE_STATO); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto/antifurto", js.toString()); } } public void sendOutAntifurto() throws JSONException { JSONObject js = new JSONObject(); js.put("attiva-scenari", client.getNomeOutputAntifurto()); publisher.aggiungiComando("to/" + Antifurto.getMqttTree() + "/scenari/luceAntifurto", js.toString()); } private void sendMyStateToAll(String topic) throws JSONException { JSONObject js = new JSONObject(); js.put("status", automa.getStatoAutoma()); publisher.aggiungiComando(topic, js.toString()); } private void handleNewConfig(JSONObject msgJson) throws JSONException { try { if(msgJson.has("interruttore")) { client.unsubscribeTopic("from/"+Antifurto.getMqttTree()+"/gpio/" + client.getNomeInterruttoreAntifurto()); String interruttore = msgJson.getString("interruttore"); client.setNomeInterruttoreAntifurto(interruttore); client.addTopicToSubscribe("from/"+Antifurto.getMqttTree()+"/gpio/" + interruttore); } if(msgJson.has("outputSuono")) { if(automa.getStatoAutoma()==2) { // l'allarme sta suonando publisher.aggiungiComando("to/"+Antifurto.getMqttTree()+"/gpio/"+client.getNomeOutputSuono(), "{cmd:0}"); newSuonoConf = msgJson.getString("outputSuono"); } else { newConfigNomeOutputSuono(msgJson.getString("outputSuono")); } } if(msgJson.has("nomeOutputAntifurto")) { if(automa.getStatoAutoma()==1 || automa.getStatoAutoma()==2) { // l'antifurto e' acceso publisher.aggiungiComando("to/"+Antifurto.getMqttTree()+"/gpio/"+client.getNomeOutputAntifurto(), "{cmd:0}"); newNomeOutputAntifurtoConf = msgJson.getString("nomeOutputAntifurto"); } else { newConfigNomeOutputAntifurto(msgJson.getString("nomeOutputAntifurto")); } } sendResponseConf(); } catch (MqttException | IOException e) { sendErrorConf(e); } } private void newConfigNomeOutputAntifurto(String nomeOutputAntifurto) throws MqttException, JSONException { client.unsubscribeTopic("from/"+Antifurto.getMqttTree()+"/gpio/" + client.getNomeOutputAntifurto()); client.setNomeOutputAntifurto(nomeOutputAntifurto); client.addTopicToSubscribe("from/"+Antifurto.getMqttTree()+"/gpio/" + nomeOutputAntifurto); newNomeOutputAntifurtoConf = null; String message = null; if(automa.getStatoAutoma() == 1 || automa.getStatoAutoma()==2) message = "{cmd:1}"; else message = "{cmd:0}"; publisher.aggiungiComando("to/"+Antifurto.getMqttTree()+"/gpio/"+client.getNomeOutputAntifurto(), message); } private void newConfigNomeOutputSuono(String outputSuono) throws MqttException, JSONException { client.unsubscribeTopic("from/"+Antifurto.getMqttTree()+"/gpio/" + client.getNomeOutputSuono()); client.setNomeOutputSuono(outputSuono); client.addTopicToSubscribe("from/"+Antifurto.getMqttTree()+"/gpio/" + outputSuono); newSuonoConf = null; String message = null; if(automa.getStatoAutoma()==2) message = "{cmd:1}"; else message = "{cmd:0}"; publisher.aggiungiComando("to/"+Antifurto.getMqttTree()+"/gpio/"+client.getNomeOutputSuono(), message); } // pubblica la risposta (per la webApp) solo se newNomeOutputAntifurtoConf = null e newSuonoConf = null private void sendResponseConf() throws JSONException, IOException { if(newNomeOutputAntifurtoConf==null && newSuonoConf==null) { JSONObject jsResponse = new JSONObject(); jsResponse.put("interruttore", client.getNomeInterruttoreAntifurto()); jsResponse.put("outputSuono", client.getNomeOutputSuono()); jsResponse.put("nomeOutputAntifurto",client.getNomeOutputAntifurto()); JSONObject jsFile = new JSONObject(Helper.leggiFile(Antifurto.CONF_ZONA)); jsResponse.put("sensoriMovimento", jsFile.get("sensoriMovimento")); Helper.scriviFile(jsResponse, Antifurto.CONF_ZONA); jsResponse.remove("sensoriMovimento"); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto" , jsResponse.toString()); } } // pubblica l'errore (per la webApp) private void sendErrorConf(Exception e) throws JSONException { JSONObject jsError = new JSONObject(); jsError.put("error", e.getMessage()); publisher.aggiungiComando("from/" + Antifurto.getMqttTree() + "/antifurto", jsError.toString()); } }