Skip to content
Snippets Groups Projects
SubscribeCallback.java 15.52 KiB
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 può 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 più
			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());
	}
	
	
	// to/gruppo2/luci/antifurto/luceAntifurto
}