Skip to content
Snippets Groups Projects
SubscribeCallback.java 14.1 KiB
Newer Older
package utility;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
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;

import scenari.Automa;
import scenari.Scenari;

public class SubscribeCallback implements MqttCallback{
	private Scenari scenari;
	private Esecutore esec;
	private Automa automa;
Alfredo Chissotti's avatar
Alfredo Chissotti committed

	public SubscribeCallback(Scenari scenari, Esecutore esec, Automa automa) {
		this.scenari = scenari;
		this.esec = esec;
		this.automa = automa;
	}

	@Override
	public void connectionLost(Throwable arg0) {
		Helper.print("connessione persa\t"+arg0);
		final Date d = new Date();
		Date d2 = new Date();
		long time = Math.abs(d2.getTime()-d.getTime());
		while (time<600000) {
			try {
				Helper.print("retrying...");
				Scenari.main(Scenari.shouldPrint ? new String[]{"via"} : null);
				return;
			} catch (MqttException | JSONException | IOException e) {
				Helper.print("non sono riusciuto");
				d2 = new Date();
				time = Math.abs(d2.getTime()-d.getTime());
			}
		}
		if(time>=600000) {
			Helper.print("Tentativo di riconnessione fallito");
			System.exit(1);
		}
	}

	@Override
	public void deliveryComplete(IMqttDeliveryToken arg0) {
		// Nessuna operazione
		Helper.print("inviato");

	@Override
	public void messageArrived(String topic, MqttMessage message) throws MqttException, JSONException, IOException {
		if(topic.equals("to/all")) {
			Helper.print("invio lo stato dell'automa");
			sendRequested(Scenari.getMqttTree("from/","scenari/description"),false);
			return;
		}
		if(topic.equals(Scenari.getMqttTree("rpc/","scenari"))) {
			Helper.print("invio la mia configurazione");
			sendRequested(Scenari.getMqttTree("from/","scenari"),true);
			return;
		}
		JSONObject msgJson = new JSONObject(message.toString());
//		gli event sono 0 o 1; i trigger quando sono attivati/premuti inviano un 1 quando rilasciati, che e' l'unico elemento che mi interessa
		if(topic.startsWith("from/")){
			if(topic.equals(Scenari.getMqttTree("from/","gpio/"+scenari.getLearnTrigger()))) {
				Helper.print("trigger per learn");
				if(!msgJson.has("event"))//se l'antifurto e' attivo, non posso attivare gli scenari
					return;
				int newStatus = msgJson.getInt("event");
				if(newStatus != 1)
					return;
				Helper.print("cambio lo stato di learn");
				handleEvent(scenari.getLearnTrigger());
				return;
			}
			if(topic.equals(Scenari.getMqttTree("from/","gpio/"+scenari.getAttivaScenari()))) {
				Helper.print("trigger per antifurto");
				if(!msgJson.has("event"))//se l'apprendimento e' attivo, non posso attivare l'antifurto
					return;
				int newStatus = msgJson.getInt("event");
				if(newStatus != 1)
					return;
				Helper.print("richiedo il cambio di stato dell'antifurto alla luce");
				toggleAntifurtoLight();
				return;
			}
			if(topic.startsWith(Scenari.getMqttTree("from/","gpio/IN"))) {
				Helper.print("totalmente inutile per me!");
				return;//non mi interessa altro da IN
			}
			if(topic.equals(Scenari.getMqttTree("from/","gpio/"+scenari.getLuceAntifurto()))) {
				if(msgJson.has("status")){
					Helper.print("controllo lo stato antifurto");
					int newStatus = msgJson.getInt("status");
					setAntifurtoStatus(newStatus == 1);
				} else if(msgJson.has("event")){
					Helper.print("luce che indica il cambio di stato antifurto\tlearn: "+
					automa.getLearn());
					contatoreMessaggiBB--;
					if(contatoreMessaggiBB < 0){
						contatoreMessaggiBB = 0;
						Helper.print("ricevuto un messaggio in piu");
						return;
					}
					// int ev = msgJson.getInt("event");
					Helper.print("posso cambiare lo stato antifurto");
					handleEvent(scenari.getAttivaScenari());
				}
			if(topic.startsWith(Scenari.getMqttTree("from/","gpio/OUT"))) {
				if(msgJson.has("event")) {
					Helper.print("se learn==true, salvo questo event!");
					Helper.print(automa.getLearn()+"\t"+msgJson.toString());
				}
				if(!automa.getLearn() || !msgJson.has("event"))
					return;
				if(scenarioName == null) {
					handleLearn(true);
				}
				int val = msgJson.getInt("event");
				String luce = topic.substring(23);
				handleLearnData(luce,val);
				return;
			}
			return;
		}
		if(topic.equals(Scenari.getMqttTree("to/","scenari"))) {
			Helper.print("Cambio quale scenario e' attivo, se antifurto attivo\t"+automa.getAntifurto());
			if(!automa.getAntifurto() || !msgJson.has("evento") || !msgJson.has("nome"))
			changeActiveScenario(msgJson);
			return;
		}
		if(topic.equals(Scenari.getMqttTree("to/","scenari/salva"))) {
			Helper.print("rinomino l'ultimo scenario salvato");
			if(!msgJson.has("nome"))//se non sono appena stato nello stato di registrazione, non serve andare avanti
				return;
			renameLastScenario(msgJson);
Alfredo Chissotti's avatar
Alfredo Chissotti committed
		if(topic.equals(Scenari.getMqttTree("to","scenari/sensoreAntifurto"))){
			Helper.print("messaggio per cambiare il sensore che imposta l'antifurto");//serve se l'antifurto cambia sensore
			if(!msgJson.has("attiva-scenari"))
Alfredo Chissotti's avatar
Alfredo Chissotti committed
				return;
			changeSensor(msgJson.getString("attiva-scenari"));
			return;
		}
		if(topic.equals(Scenari.getMqttTree("to","scenari/luceAntifurto"))) {
			Helper.print("messaggio per cambiare la luce che indica lo stato dell'antifurto");//serve se l'antifurto cambia sensore
			if(!msgJson.has("attiva-scenari"))
				return;
			changeLight(msgJson.getString("attiva-scenari"));
Alfredo Chissotti's avatar
Alfredo Chissotti committed
			return;
		}

		Helper.print("Impossibile");
	private void changeSensor(String newSensor) throws JSONException, IOException, MqttException {
Alfredo Chissotti's avatar
Alfredo Chissotti committed
		scenari.setAttivaScenari(newSensor);
		Helper.print("sensore cambiato in "+scenari.getAttivaScenari());
		// query the luceAntifurto to set the correct status
		String req = "{request:status}";
		scenari.sendMqttMessage(Scenari.getMqttTree("to", "gpio/" + scenari.getLuceAntifurto()), req);
	}

	private void changeLight(String newLight) throws JSONException, IOException {
		scenari.setLuceAntifurto(newLight);
		Helper.print("luce cambiata in "+scenari.getLuceAntifurto());
	private int contatoreMessaggiBB = 0;

	private void toggleAntifurtoLight() throws JSONException, IOException, MqttException {
		String luce = scenari.getLuceAntifurto();
		if(luce == null)
			return;
		String topic = Scenari.getMqttTree("to/","gpio/"+luce);
		int newStatus = automa.getAntifurto() ? 0 : 1;
		String msg = "{cmd:"+newStatus+"}";
		contatoreMessaggiBB++;
		scenari.sendMqttMessage(topic, msg);
	}

	private void handleEvent(String which) throws JSONException, MqttException, IOException{
		final int oldStatoAutoma = automa.getStato();
		final String cosa = which == scenari.getLearnTrigger() ? "learn" : "antifurto";
		final String cmd = automa.findPossibleCommand(cosa);
		if(cmd == null)
			return;
		Helper.print("handling event: "+cosa+"\t"+cmd);
		automa.setStato(new JSONObject().put(cosa,cmd).toString());
		final int newStatoAutoma = automa.getStato();
		Helper.print("nuovo stato\t"+automa.getStato());
		esec.setLoopCondition(automa.getAntifurto());
		if(Helper.compareText(cosa, "learn")) {
			final boolean val = Helper.compareText(cmd, "on");
			handleLearn(val);
		} else {
			esec.releaseUserChoice(newStatoAutoma == 2);
		}
		if(newStatoAutoma == oldStatoAutoma)
			return;
		switch(newStatoAutoma) {
			case 0://non sto registrando ne' l'antifurto e' attivo
				switch(oldStatoAutoma) {
					case 1://stavo registrando
						sendEventResponse(Scenari.getMqttTree("from/","scenari/learn"),true);
						break;
					case 2://l'antifurto era attivo
						sendEventResponse(Scenari.getMqttTree("from/","scenari/antifurto"),false);
						break;
				}
				break;
			case 1://sto registrando
				switch(oldStatoAutoma) {
					case 0://non stavo registrando ne' l'antifurto e' attivo
						sendEventResponse(Scenari.getMqttTree("from/","scenari/learn"),true);
						break;
					case 2://l'antifurto era attivo
						sendEventResponse(Scenari.getMqttTree("from/","scenari/learn"),true);
						sendEventResponse(Scenari.getMqttTree("from/","scenari/antifurto"),false);
						break;
				}
				break;
			case 2://l'antifurto e' attivo
				switch(oldStatoAutoma) {
					case 0://non stavo registrando ne' l'antifurto e' attivo
						sendEventResponse(Scenari.getMqttTree("from/","scenari/antifurto"),false);
						break;
					case 1://stavo registrando
						sendEventResponse(Scenari.getMqttTree("from/","scenari/learn"),true);
						sendEventResponse(Scenari.getMqttTree("from/","scenari/antifurto"),false);
						break;
				}
				break;
		}
	}

	private void sendEventResponse(String topic,boolean learn) throws JSONException, MqttException, IOException {
		JSONObject j = new JSONObject();
		j.put("event", learn ? automa.getLearn() : automa.getAntifurto());
		scenari.sendMqttMessage(topic, j.toString());
	private String scenarioName = null;
	private void handleLearn(boolean shouldLearn) throws JSONException, IOException, MqttException{
		Helper.print("handleLearn "+shouldLearn+" ; "+automa.getLearn());
		final Boolean passedThroughZero = automa.setStato(new JSONObject().put("learn",shouldLearn ? "on" : "off").toString());
		esec.setLoopCondition(automa.getAntifurto());
		if(passedThroughZero != null && !passedThroughZero){
			// devo assicurarmi di modificare lo stato della luce che gestisce l'antifurto
			String luce = scenari.getLuceAntifurto();
			if(luce == null)
				return;
			String topic = Scenari.getMqttTree("to/","gpio/"+luce);
			String msg = "{cmd:"+(shouldLearn ? 1 : 0)+"}";
			scenari.sendMqttMessage(topic, msg);
		}
		Helper.print("learn?\t"+automa.getLearn());
		if(automa.getLearn()) {
			if(scenarioName == null) {
				scenarioName = "scenario-"+LocalDateTime.now().toString().replace(':', '-')+".json";
			}
		} else {
			scenarioName = null;
//			TODO tell antifurto to turn off if shouldLearn == true
		}
	}
	private void handleLearnData(String luce, int val) throws MqttException, IOException, JSONException {
		JSONObject j = new JSONObject();
//		tempo passato dallo scorso comando
		LocalTime now = LocalTime.now();
		j.put("tempo", now.format(DateTimeFormatter.ofPattern("HH-mm-ss")));
//		quale luce
		j.put("luce", luce);
//		accesa o spenta?
		j.put("cmd", val);
		Helper.appendiFile(j, esec.DB_FOLDER+scenarioName,false);
	private void changeActiveScenario(JSONObject scenario) throws IOException, JSONException, MqttException {
		String nuovoScenario = esec.getUCS().requestToChange(scenario);
		Helper.print(nuovoScenario);
		JSONObject j = new JSONObject();
		j.put("nome", nuovoScenario);
		scenari.sendMqttMessage(Scenari.getMqttTree("from/","/scenari/attiva"), j.toString());
	private void sendRequested(String topic,boolean moreInfo) throws MqttException, JSONException, IOException {
		JSONObject j = new JSONObject();
		j.put("stato", automa.getStato());
		if(moreInfo) {
			j.put("learn", automa.getLearn());
			boolean antifurto = automa.getAntifurto();
			j.put("antifurto", antifurto);
Alfredo Chissotti's avatar
Alfredo Chissotti committed
			j.put("learn-trigger", scenari.getLearnTrigger());
			j.put("attiva-scenari", scenari.getAttivaScenari());
			j.put("luce-antifurto", scenari.getLuceAntifurto());
//			invio tutti gli scenari
			{
				ArrayList<File> allScenariFile = esec.getAllScenariAvailable();
				JSONArray arr = new JSONArray();
				for(File f : allScenariFile) {
					JSONObject scenarioData = new JSONObject();
					String scenNome = esec.getScenarioNome(f);
					Helper.print(scenNome);
					scenarioData.put("nome", !esec.isFileRenamed(scenNome)? scenNome.substring(0,28) : esec.removeData(scenNome));
					scenarioData.put("data", esec.getScenarioData(f));
					arr.put(scenarioData);
				}
				j.put("scenari-disponibili", arr);
			}
//			invio lo scenario attivo
			if(antifurto) {
				String scenarioAttivo = esec.getScenarioAttivo();
				if(scenarioAttivo != null && !scenarioAttivo.equals("none")) {
					JSONObject scenarioValori = new JSONObject();
					scenarioValori.put("nome", !esec.isFileRenamed(scenarioAttivo) ? scenarioAttivo.substring(0,28) : esec.removeData(scenarioAttivo));
					scenarioValori.put("data", esec.getDataScenarioAttivo());
					j.put("scenario-attivo", scenarioValori);
				}
			}
		scenari.sendMqttMessage(topic, j.toString());

	private void renameLastScenario(JSONObject json) throws IOException, MqttException, JSONException {
		String nuovoNome = json.getString("nome");
		nuovoNome += nuovoNome.endsWith(".json") ? "" : ".json";
		ArrayList<File> available = esec.getAllScenariAvailable();
//		cerco l'ultimo scenario (sono nominati in base al giorno e all'ora, se non sono rinominati dall'utente)

		File max = available.get(0);
		String maxString = max.toString();
		for(File f : available) {
			String fString = f.toString();
			if(esec.isFileRenamed(f))//non mi interessano i file rinominati
				continue;
			if(esec.isFileRenamed(max) || fString.compareToIgnoreCase(maxString) > 0) {
				max = f;
				maxString = fString;
			}
		}
		String nome = esec.getScenarioNome(max);
		String[] path = max.toString().split("/");
		StringBuilder rename = new StringBuilder();
		for(int i = 0; i< path.length-1; i++)
			rename.append(path[i]).append('/');
		LocalDateTime now = LocalDateTime.now();
		String date = now.getYear()+"-"+(now.getMonthValue() < 10 ? "0"+now.getMonthValue() : now.getMonthValue())+"-"+(now.getDayOfMonth() < 10 ? "0"+now.getDayOfMonth() : now.getDayOfMonth());
		rename.append(esec.removeExtension(nuovoNome)).append("---").append(date).append(".json");
		boolean renamed = max.renameTo(new File(rename.toString()));
		JSONObject j = new JSONObject();
		String nuovoNomeSenzaEstensione = esec.removeData(esec.removeExtension(renamed ? nuovoNome : nome));
		j.put("nome", nuovoNomeSenzaEstensione);
		j.put("data", date);
		scenari.sendMqttMessage(Scenari.getMqttTree("from/","scenari/salva"), j.toString());
	private void setAntifurtoStatus(boolean activateAntifurto) throws MqttException, JSONException, IOException {
		automa.setAntifurtoStatus(activateAntifurto);
		esec.setLoopCondition(automa.getAntifurto());
		sendRequested(Scenari.getMqttTree("from/","scenari/description"),false);
	}