diff --git a/ScenariMicroservizio/1657636848310-scenari-tcplocalhost1883/.lck b/ScenariMicroservizio/1657636848310-scenari-tcplocalhost1883/.lck
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/ScenariMicroservizio/1657636876590-scenari-tcplocalhost1883/.lck b/ScenariMicroservizio/1657636876590-scenari-tcplocalhost1883/.lck
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/ScenariMicroservizio/java-commandline.txt b/ScenariMicroservizio/java-commandline.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e0cb82743a61731d93bbcc63c7e77cd379ccaeb0
--- /dev/null
+++ b/ScenariMicroservizio/java-commandline.txt
@@ -0,0 +1,6 @@
+compilare:
+javac -cp .:./org.eclipse.paho.client.mqttv3_1.2.5.jar:./org.json-1.0.0.v201011060100.jar -d bin src/utility/* src/scenari/*
+
+partire:
+cd bin
+java -classpath .:../org.eclipse.paho.client.mqttv3_1.2.5.jar:../org.json-1.0.0.v201011060100.jar scenari.Scenari
diff --git a/ScenariMicroservizio/org.eclipse.paho.client.mqttv3_1.2.5.jar b/ScenariMicroservizio/org.eclipse.paho.client.mqttv3_1.2.5.jar
new file mode 100644
index 0000000000000000000000000000000000000000..f75a141b10d88b1fa98a90519c826e690b62beab
Binary files /dev/null and b/ScenariMicroservizio/org.eclipse.paho.client.mqttv3_1.2.5.jar differ
diff --git a/ScenariMicroservizio/org.json-1.0.0.v201011060100.jar b/ScenariMicroservizio/org.json-1.0.0.v201011060100.jar
new file mode 100644
index 0000000000000000000000000000000000000000..2aa70fdf80f4cc14a2063a8f118c847506c6c579
Binary files /dev/null and b/ScenariMicroservizio/org.json-1.0.0.v201011060100.jar differ
diff --git a/ScenariMicroservizio/src/scenari.json b/ScenariMicroservizio/src/scenari.json
new file mode 100644
index 0000000000000000000000000000000000000000..bd43971ae01e7596921e6278d126d2c2f3dabe58
--- /dev/null
+++ b/ScenariMicroservizio/src/scenari.json
@@ -0,0 +1,16 @@
+{"stato-attuale":0,
+"automa":[{"stato":0,
+"learn-off":0,
+"learn-on":1,
+"antifurto-on":2,
+"antifurto-off":0},
+{"stato":1,
+"learn-off":0,
+"learn-on":1,
+"antifurto-on":1,
+"antifurto-off":1},
+{"stato":2,
+"learn-off":2,
+"learn-on":2,
+"antifurto-on":2,
+"antifurto-off":0}]}
\ No newline at end of file
diff --git a/ScenariMicroservizio/src/scenari/Automa.java b/ScenariMicroservizio/src/scenari/Automa.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c725c747cd28661ef18900628066ad5c969a71e
--- /dev/null
+++ b/ScenariMicroservizio/src/scenari/Automa.java
@@ -0,0 +1,167 @@
+package scenari;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import utility.Helper;
+
+public class Automa {
+//	0: learn = off, antifurto = off
+//	1: learn = on, antifurto = off
+//	2: learn = off, antifurto = on => scenari = on
+
+	private int stato;
+	private JSONObject jsonObject;
+	private boolean learn;
+	private boolean antifurto;
+	private final String DATABASE_PATH = "./scenari.json";
+
+	public Automa() throws JSONException, IOException {
+		this.jsonObject = new JSONObject(Helper.leggiFile(DATABASE_PATH));
+		setCollaterals(this.jsonObject.getInt("stato-attuale"));
+	}
+	
+	public synchronized void setStato(String command) {
+		setStato(command,false);
+	}
+
+	public synchronized void setStato(String command,boolean fromDatabase) {
+		if (command == null || !Helper.checkJSON(command)
+				|| (!command.contains("\"learn\":") && !command.contains("\"antifurto\":"))
+				|| (!command.contains(":\"on\"") && !command.contains(":\"off\"")))
+			return;
+		String[] cmd = command.split(":");
+		String cosa = cmd[0].split("\"", 3)[1];
+		String come = cmd[1].split("\"", 3)[1];
+
+		if (Helper.compareText(cosa, "learn")) {
+			if (Helper.compareText(come, "on") && this.stato == 0) {
+				setCollaterals(1,!fromDatabase);
+			} else if (Helper.compareText(come, "off") && this.stato == 1) {
+				setCollaterals(0,!fromDatabase);
+			}
+			return;
+		}
+		if (Helper.compareText(cosa, "antifurto")) {
+			if (Helper.compareText(come, "on") && this.stato == 0) {
+				setCollaterals(2,!fromDatabase);
+			} else if (Helper.compareText(come, "off") && this.stato == 2) {
+				setCollaterals(0,!fromDatabase);
+			}
+			return;
+		}
+	}
+	
+	public String findPossibleCommand(String which) throws JSONException{
+		Boolean learn = null;
+		if(!(learn=Helper.compareText(which, "learn")) && !Helper.compareText(which, "antifurto"))
+			return null;
+//		devo cercare nel jsonObject lo stato attuale e trovare la stringa corrispondente al which, poi discriminare in base a cio' che mi permette di cambiare stato
+		@SuppressWarnings("unchecked")
+		Iterator<String> keys = jsonObject.keys();
+		while(keys.hasNext()) {
+			String key = keys.next();
+			try {
+				JSONArray array = jsonObject.getJSONArray(key);
+				for(int i =0; i<array.length(); i++) {
+					JSONObject a = array.getJSONObject(i);
+					int stato = a.getInt("stato");
+					if(stato != this.stato)
+						continue;
+					if(learn) {
+						int learnOff = a.getInt("learn-off");
+						if(learnOff != stato)
+							return "off";
+						int learnOn = a.getInt("learn-on");
+						if(learnOn != stato)
+							return "on";
+					} else {
+						int antifurtoOff = a.getInt("antifurto-off");
+						if(antifurtoOff != stato)
+							return "off";
+						int antifurtoOn = a.getInt("antifurto-on");
+						if(antifurtoOn != stato)
+							return "on";
+					}
+				}
+			} catch (JSONException e) {
+				if(!e.getMessage().contains("stato-attuale"))
+					System.out.println(e.getMessage());
+			}
+//			if(riga.getInt("stato")==statoAttuale) {
+//				this.statoAttuale = riga.getInt("cmd"+newStatoInterruttore);
+//				aggiornaInterruttoreESuono();
+//			}
+		}
+		return null;
+	}
+	
+	private synchronized void setCollaterals(int stato) {
+		setCollaterals(stato,false);
+	}
+
+	private synchronized void setCollaterals(int stato,boolean write) {
+		switch (stato) {
+			case 0: {
+				this.stato = 0;
+				this.learn = false;
+				this.antifurto = false;
+				break;
+			}
+			case 1: {
+				this.stato = 1;
+				this.learn = true;
+				this.antifurto = false;
+				break;
+			}
+			case 2: {
+				this.stato = 2;
+				this.learn = false;
+				this.antifurto = true;
+				break;
+			}
+		}
+		notifyAll();
+		if(write)
+			writeStatoOnDatabase();
+	}
+
+	private synchronized void writeStatoOnDatabase() {
+		try {
+			this.jsonObject.put("stato-attuale", this.stato);
+			Helper.scriviFile(jsonObject,DATABASE_PATH);
+		} catch (JSONException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	public int getStato() {
+		return this.stato;
+	}
+	
+	public boolean getLearn() {
+		return this.learn;
+	}
+	
+	public boolean getAntifurto() {
+		return this.antifurto;
+	}
+	
+	public synchronized boolean waitForAntifurto() {
+		while(!this.antifurto) {
+			try {
+				wait();
+			} catch(InterruptedException ex) {
+				System.out.println("Interrupted exception");
+			}
+		}
+		return this.antifurto;
+	}
+
+}
diff --git a/ScenariMicroservizio/src/scenari/Scenari.java b/ScenariMicroservizio/src/scenari/Scenari.java
new file mode 100644
index 0000000000000000000000000000000000000000..63f8c0e65f5bb5c2487140c9a9e628e27e24bc8d
--- /dev/null
+++ b/ScenariMicroservizio/src/scenari/Scenari.java
@@ -0,0 +1,175 @@
+package scenari;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+
+import org.eclipse.paho.client.mqttv3.IMqttToken;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttTopic;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import utility.Esecutore;
+import utility.Helper;
+import utility.MyQueue;
+import utility.Pair;
+import utility.Publisher;
+import utility.SubscribeCallback;
+
+public class Scenari {
+
+	private static String brokerUrl;
+	private String learnTrigger;
+	private String attivaScenari;
+	private static ArrayList<String> topicsSub;
+	private String clientId = Long.toString(new Date().getTime()) + "-scenari"; // unique client id
+	private Automa automa;
+	
+	public MqttClient mqttClient;
+	
+	public Scenari(Automa automa) throws JSONException, IOException, MqttException {
+		this.automa = automa;
+		
+		JSONObject config = new JSONObject(Helper.leggiFile("./CONF/conf.json"));
+		brokerUrl = config.getString("protocol") + "://" + config.getString("broker") + ":" + config.getInt("port");
+		
+		topicsSub = new ArrayList<String>();
+		topicsSub.add("to/all"); //mandare la mia descrizione json
+		topicsSub.add("rpc/gruppo2/luci/scenari"); //mandare lo stato attuale
+		
+		// inutile aggiungere i topic, perche subbo gia' tutto gpio/#
+		config = new JSONObject(Helper.leggiFile("./CONF/zona.json"));
+		learnTrigger = config.getString("learn-trigger");
+//		topicsSub.add("from/gruppo2/luci/gpio/" + learnTrigger); // Sottoscrivo i messaggi che notificano il cambiamento di stato dell'interruttore
+		attivaScenari = config.getString("attiva-scenari");
+//		topicsSub.add("from/gruppo2/luci/gpio/"+attivaScenari);
+		
+//		interruttoreOutputSuono = config.getString("outputSuono");
+//		topicsSub.add("from/gruppo2/luci/gpio/" + interruttoreOutputSuono); // Sottoscrivo i messaggi che notificano il cambiamento di stato dell'interruttore
+//		topicsSub.add("to/gruppo2/luci/scenari/learn");
+		topicsSub.add("from/gruppo2/luci/gpio/#");
+		
+		this.mqttClient = new MqttClient(brokerUrl, clientId, new MemoryPersistence());
+		//memory persistence serve per non avere errori in console
+		// https://github.com/eclipse/paho.mqtt.java/issues/794
+	}
+	
+	public void startClient(Esecutore esec, Publisher publisher) throws MqttException {
+		MqttConnectOptions options = new MqttConnectOptions();
+		options.setUserName("gruppo2");
+		options.setPassword("funziona".toCharArray());
+		options.setCleanSession(false);
+		mqttClient.setCallback(new SubscribeCallback(this, publisher, learnTrigger, attivaScenari, esec, automa));
+		
+		mqttClient.connect(options);
+		
+		for(String t: topicsSub) 
+			mqttClient.subscribe(t);
+	}
+	
+	
+	
+	
+	/*
+	 * Abbiamo 3 tipi di eventi:
+	 * 		to 		Command Events - mi viene richiesto di eseguire un comando --> sottoscrivo 
+	 * 		from 	Status Events - io annuncio un cambiamento di stato  	
+	 * 								(inviato a tutti i client che hanno sottoscritto il topic su cui faccio la publish)
+	 * 		rpc 	Query Events - richiesta di inviare uno stato a un client (o microservizio). --> sottoscrivo 
+	 * 			  				   Query implementati come coppia di eventi: <query event, status event>
+	 * RICORDIAMO COME ABBIAMO IMPLEMENTATO LA RPC SU MQTT
+	 * 
+	 * 
+	 * 
+	 * Il cuore della nostra business logic è un metodo in cui mi metto in attesa su mqtt e: 
+	 * 		se arriva un comando, chiamo il metodo responsabile per eseguire quel comando;
+	 * 		se arriva un evento di stato, chiamo il metodo responsabile per gestire quell'evento di stato;
+	 * 		se arriva una remote procedure call, attivo la risposta sulla remote procedure call 
+	 * 
+	 * 
+	 * 
+	 * Capire come gestire sistema a regole (vedi slide "Esempio" in "Applicazioni IoT "Cloud Based"")
+	 * 
+	 * 
+	 * 
+	 * Sicurezza gestita con TLS
+	 * 
+	 * 
+	 * 
+	 * FILE DA FARE per un servizio: (?)
+	 * 		file che contiene le informazioni per connettersi al mosquitto locale 
+	 * 		file che dice qual'è la porta che lui deve esporre
+	 * 		file che mi dice tutte le cose che lo configurano, ad esempio quanti device deve guardare
+	 * 		...
+	 * 
+	 * 	I file di configurazione sono in JSON o in XML
+	 * I dati persistiti si troveranno nella sottodirectory (chiamata con il nome del servizio) di Home
+	 * 
+	 * 
+	 * Nella fase di configurazione potremo ancora modificare i file di configurazione (ad esempio aggiungendo device, 
+	 * regole). Dopodiché quando si fa partire il servizio si inizierà a usare l'altra parte di file system (ovvero il Local 
+	 * Dynamic File System) dove si andranno a salvare gli stati per renderli persistenti.
+	 * 
+	 * 
+	 * 
+	 * Ho un processo principale che come unico compito ha quello di fare una fork() e creare un processo figlio. 
+	 * Sarà questo processo figlio a eseguire effettivamente il programma. Se il processo figlio termina (PER UN QUALCHE 
+	 * PROBLEMA), allora il processo padre se ne accorge e fa ripartire un nuovo processo figlio.
+	 * 
+	 *  
+	 * Devo avere una thread di configurazione che obbedisce ai miei comandi (dati sulla HAT interface andando su 
+	 * 	192.168.0.101:9001/configure.html (dove 192.168.0.101 è l'indirizzo della beaglebone)
+	 * 
+	 * 
+	 * Ho una classe che implementa l'automa a stati finiti
+	 * 
+	 * 
+	*/
+	
+	public static void main(String args[]) throws JSONException, IOException, MqttException {
+		System.out.println("started");
+		//PER TESTARE PRIMA TOGLI IL TRY CATCH !!!!! POI QUANDO TUTTO FUNZIONA, METTI IL TRY CATCH, togli le throws E IMPLEMENTA LA RIPARTENZA!
+		
+//		while(true) {
+//			try {
+				startSystem();
+//			}
+//			catch(Exception e) {
+//				// DA FARE:
+//				// qui metto il codice per far ripartire il processo: rileggo lo stato dei sensori e dell'interruttore, 
+//				// capisco di conseguenza in quale stato dell'automa mi trovo e riparto.
+//				startSystem();
+//			}
+//		}
+//		Scenari antifurto = 
+//		new Scenari(new Automa());
+	}
+	
+	
+	private static void startSystem() throws JSONException, IOException, MqttException {
+		
+//		MyQueue<Integer> codaVal = new MyQueue<Integer>();
+//		MyQueue<Pair> codaMsg = ;
+		Automa automa = new Automa();
+		Scenari scenari = new Scenari(automa);
+		Publisher publisher = new Publisher(new MyQueue<Pair>(), scenari);
+//		Esecutore esec = new Esecutore(publisher, codaVal, automa, antifurto.interruttoreOutputSuono);
+		Esecutore esec = new Esecutore(publisher,automa);
+//		Timer timer = new Timer(30000,-5,esec,automa);
+		
+		scenari.startClient(esec,publisher);//, publisher);
+		publisher.start();
+		esec.start();
+//		timer.start();
+	}
+
+	
+	
+	
+
+}
diff --git a/ScenariMicroservizio/src/test/AutomaTest.java b/ScenariMicroservizio/src/test/AutomaTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fe8cb0c344df074c53539995c01a7046296fa142
--- /dev/null
+++ b/ScenariMicroservizio/src/test/AutomaTest.java
@@ -0,0 +1,106 @@
+package test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.junit.jupiter.api.Test;
+
+import scenari.Automa;
+import scenari.Scenari;
+import utility.Esecutore;
+import utility.SubscribeCallback;
+
+public class AutomaTest {
+	
+	
+//	@Test
+	void test01() throws JSONException, IOException {
+		Automa a = new Automa();
+		JSONObject loff = new JSONObject().put("learn","off");
+		JSONObject lon = new JSONObject().put("learn","on");
+		JSONObject aoff = new JSONObject().put("antifurto","off");
+		JSONObject aon = new JSONObject().put("antifurto","on");
+		final int stato = a.getStato();
+		a.setStato(loff.toString());
+		a.setStato(aoff.toString());
+//		valid commands
+		assertEquals(0,a.getStato());
+		a.setStato(lon.toString());
+		assertEquals(1,a.getStato());
+		a.setStato(loff.toString());
+		assertEquals(0,a.getStato());
+		a.setStato(aon.toString());
+		assertEquals(2,a.getStato());
+		a.setStato(aoff.toString());
+		assertEquals(0,a.getStato());
+//		invalid commands
+		a.setStato(loff.toString());
+		assertEquals(0,a.getStato());
+		a.setStato(aoff.toString());
+		assertEquals(0,a.getStato());
+		a.setStato(lon.toString());
+		assertEquals(1,a.getStato());
+		a.setStato(lon.toString());
+		assertEquals(1,a.getStato());
+		a.setStato(aoff.toString());
+		assertEquals(1,a.getStato());
+		a.setStato(aon.toString());//secondo me questo dovrebbe essere valido
+		assertEquals(1,a.getStato());
+		a.setStato(loff.toString());
+		a.setStato(aon.toString());
+		assertEquals(2,a.getStato());
+		a.setStato(lon.toString());
+		assertEquals(2,a.getStato());
+		a.setStato(loff.toString());
+		assertEquals(2,a.getStato());
+		a.setStato(aon.toString());
+		assertEquals(2,a.getStato());
+		a.setStato(null);
+		assertEquals(2,a.getStato());
+		a.setStato("\"antifurto\":\"on\"");
+		assertEquals(2,a.getStato());
+		a.setStato("{\"dati\":\"on\"}");
+		assertEquals(2,a.getStato());
+		a.setStato("{\"antifurto\":true}");
+		assertEquals(2,a.getStato());
+		
+		resetStato(stato,a,loff,aoff,lon,aon);
+	}
+
+	private void resetStato(int stato,Automa a, JSONObject loff, JSONObject aoff, JSONObject lon, JSONObject aon) {
+		switch (stato) {
+			case 0: {
+				a.setStato(loff.toString());
+				a.setStato(aoff.toString());
+				break;
+			}
+			case 1: {
+				resetStato(0,a, aon, aon, aon, aon);
+				a.setStato(lon.toString());
+				break;
+			}
+			case 2: {
+				resetStato(0,a, aon, aon, aon, aon);
+				a.setStato(aon.toString());
+				break;
+			}
+		}
+	}
+	
+//	@Test
+//	void test02() throws JSONException, IOException, MqttException {
+//		Automa a = new Automa();
+//		a.setStato("{\"learn\":\"on\"}");
+//		SubscribeCallback sb = new SubscribeCallback(new Scenari(a), "IN4", "IN5", new Esecutore(a), a);
+////		sb.handleEvent(1, "IN4");
+//		MqttMessage mes = new MqttMessage();
+//		mes.setPayload("{\"event\":0}".getBytes());
+//		sb.messageArrived("from/gruppo2/luci/gpio/OUT3", mes);
+//	}
+
+}
diff --git a/ScenariMicroservizio/src/utility/Esecutore.java b/ScenariMicroservizio/src/utility/Esecutore.java
new file mode 100644
index 0000000000000000000000000000000000000000..1d1dd3cc854a22f4831f2c3a890345bea7f66e05
--- /dev/null
+++ b/ScenariMicroservizio/src/utility/Esecutore.java
@@ -0,0 +1,148 @@
+package utility;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import scenari.Automa;
+
+public class Esecutore extends Thread {
+
+//	private MyQueue<Integer> codaVal; // coda in cui vengono mantenuti i valori da sommare alla variabile valore
+//	private int valore; // variabile numerica cumulativa inizialmente impostata a 0
+//	public final int SOGLIA = 100;
+	private Publisher publisher;
+	private Automa automa;
+//	private String outputSuono; // nome logico dell'interruttore che fa scattare il suono dell'allarme 
+
+	public Esecutore( Publisher publisher, /*MyQueue<Integer> codaVal, */ Automa automa) {
+//		this.codaVal = codaVal;
+//		this.valore = 0;
+		this.automa = automa;
+		this.publisher = publisher;
+//		this.outputSuono = outputSuono;
+	}
+	
+//	private int numeroRighe = 0;
+
+	public void run() {
+//		qui ci va la business logic
+		try {
+			while (true) {
+				LocalTime ora = LocalTime.now();
+//				if(!automa.waitForAntifurto())
+				if(!automa.getAntifurto())
+					continue;
+				// l’antifurto è acceso
+				FileReader fr = randomFileScenari();
+				if(fr == null )//|| numeroRighe == 0)
+					continue;
+				BufferedReader br = new BufferedReader(fr);// selezioniamo un file contenente i comandi
+				String line = br.readLine();//su ogni linea si trova un nuovo comando, in ordine di tempo dal meno recente al piu' recente
+//				numeroRighe--;
+				while(line.isBlank()) {
+					line = br.readLine();
+//					numeroRighe--;
+				}
+				LocalTime tempoCmd = LocalTime.now();
+				boolean startedPublishing = false;
+//				String nomeLuce;
+//				String cmd;
+				while(line != null && ora.isBefore(tempoCmd)/*&& numeroRighe > 0*//*&& tempoCmd.isBefore(LocalTime.now())*/) {
+					ora = LocalTime.now();
+//					System.out.println("\tsecondo ciclo");
+					
+					JSONObject jline = new JSONObject(line);
+					String[] time = jline.getString("tempo").split("-");
+//					System.out.println("using: "+line+" + "+time.length);
+					if(time.length != 3) {
+//						System.out.println(jline.getString("tempo"));
+						continue;
+					}
+					tempoCmd = LocalTime.of(Integer.valueOf(time[0]), Integer.valueOf(time[1]), Integer.valueOf(time[2]));// otteniamo [la data e] l’ora in cui è stato inviato quel comando
+
+					LocalTime tempoAttuale = LocalTime.now();
+					try {
+						long waitingTime = Helper.timeDifference(tempoAttuale, tempoCmd)*1000;
+						if(waitingTime > 1000) {
+//							System.out.println(tempoAttuale);
+//							System.out.println(tempoCmd);
+//							System.out.println("Waiting to execute command");
+//							long offset = ((Double) (Math.random() * 10)).intValue()*1000;//trova un valore tra 1 e 10 (*1000)
+							//ThreadLocalRandom.current().nextLong(10000);
+//							if(offset%2 == 0) {
+//								waitingTime += offset;// + 1000;
+//							} else waitingTime -= offset;
+//							waitingTime += 1000;
+//							System.out.println(waitingTime);
+//							if(waitingTime > 1000)
+								Thread.sleep(waitingTime);
+							
+//							System.out.println("running...");
+							startedPublishing = true;
+						} //else System.out.println("useless");
+						if(startedPublishing) {
+//							System.out.println("\tpublishing");
+							String nomeLuce = jline.getString("luce");
+							String cmd = jline.getString("cmd");
+//							System.out.println("to/gruppo2/luci/gpio/"+nomeLuce);
+//							System.out.println("{cmd:"+cmd+"}");
+							publisher.aggiungiComando("to/gruppo2/luci/gpio/"+nomeLuce, "{cmd:"+cmd+"}");
+						}
+					} catch (InterruptedException e) {
+						e.printStackTrace();
+					}
+					line = br.readLine();
+//					numeroRighe--;
+					if(line != null)
+						while(line.isBlank()) {
+							line = br.readLine();
+	//						numeroRighe--;
+						}
+//					System.out.println("should restart? "+line != null+" ; "+ora.isBefore(tempoCmd));
+//					System.out.println(line != null && ora.isBefore(tempoCmd));
+				}
+//				now line == null so I'm done reading the file
+//				TODO something about this
+				br.close();
+				fr.close();
+//				numeroRighe = 0;
+			}
+		} catch (IOException | JSONException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private synchronized FileReader randomFileScenari() throws IOException {
+		// Creating a File object for directory
+		File directoryPath = new File("./db-scenari/");
+		// List of all files and directories
+		final ArrayList<File> filesListRaw = new ArrayList<File>(Arrays.asList(directoryPath.listFiles()));
+		final ArrayList<File> filesList = new ArrayList<File>();
+		for(File f : filesListRaw) {
+			if(f.toString().endsWith(".json"))
+				filesList.add(f);
+		}
+		int maxFiles = filesList.size();
+		if(maxFiles == 0)
+			return null;
+		if(maxFiles == 1) {
+			File f = filesList.get(0);
+//			numeroRighe = ((Long)(Files.lines(f.toPath()).count())).intValue();
+			return new FileReader(f);
+		}
+		File path = null;
+		do {
+			path = filesList.get(((Double) (Math.random() * maxFiles)).intValue());
+		} while(path == null);
+		return new FileReader(path);
+	}
+
+}
diff --git a/ScenariMicroservizio/src/utility/Helper.java b/ScenariMicroservizio/src/utility/Helper.java
new file mode 100644
index 0000000000000000000000000000000000000000..67cbba14bced3a2d6e78d597fcc22ea871be3df7
--- /dev/null
+++ b/ScenariMicroservizio/src/utility/Helper.java
@@ -0,0 +1,149 @@
+package utility;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.Duration;
+import java.time.temporal.Temporal;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class Helper {
+	
+	/*public static void sendResponse(String response, HttpExchange exchange) throws IOException {
+		System.out.println(response);
+		exchange.sendResponseHeaders(200, response.getBytes().length);
+		OutputStream os = exchange.getResponseBody();
+		os.write(response.getBytes());
+		os.close();
+	}
+	
+	public static void badRequest(HttpExchange exchange) throws IOException {
+		System.out.println("Errors in the request!");
+//		exchange.getResponseHeaders().remove("content-type");
+		String response = "{\"message\":\"Errors in the request!\"}";
+		exchange.sendResponseHeaders(400, response.getBytes().length);
+		OutputStream os = exchange.getResponseBody();
+		os.write(response.getBytes());
+		os.close();
+	}
+	
+	public static void pageNotFound(HttpExchange exchange) throws IOException {
+		System.out.println("Page not found!");
+//		exchange.getResponseHeaders().remove("content-type");
+		String response = "{\"message\":\"Page not found!\"}";
+		exchange.sendResponseHeaders(404, response.getBytes().length);
+		OutputStream os = exchange.getResponseBody();
+		os.write(response.getBytes());
+		os.close();
+	}
+	
+	public static void methodNotAllowed(HttpExchange exchange) throws IOException {
+		System.out.println("Method not allowed!");
+//		exchange.getResponseHeaders().remove("content-type");
+		String response = "{\"message\":\"Method not allowed!\"}";
+		exchange.sendResponseHeaders(405, response.getBytes().length);
+		OutputStream os = exchange.getResponseBody();
+		os.write(response.getBytes());
+		os.close();
+	}*/
+	
+	public static boolean compareText(String a, String b){
+		return a.compareToIgnoreCase(b) == 0;
+	}
+
+	public static String readBody(InputStream requestBody) {
+		int req;
+		StringBuffer sb = new StringBuffer();
+		try {
+			while((req = requestBody.read()) != -1)
+				sb.append(Character.toString((char)req));
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return sb.toString();
+	}
+	
+	public static boolean checkJSON(String body) {
+		if(!body.startsWith("{") || !body.endsWith("}"))
+			return false;
+		try {
+			new JSONObject(body);
+			return true;
+		} catch (JSONException e) {
+			return false;
+		}
+	}
+	
+	public static String leggiFile(String path) throws IOException {
+		String line;
+		StringBuffer answer = new StringBuffer();
+		BufferedReader bufferedReader = null;
+		try {
+			bufferedReader = new BufferedReader(new FileReader(path));
+			while((line = bufferedReader.readLine()) != null) {
+				answer.append(line).append("\n");
+			}
+		} catch (FileNotFoundException ex) {
+//            System.out.println("Unable to open file '" + path + "'");
+//            scriviFile("sono qui",path);
+//            System.out.println("file creato al path corrispondente");
+		} finally {
+			if(bufferedReader != null)
+				bufferedReader.close();
+		}
+		return answer.toString();
+	}
+	
+	public synchronized static void scriviFile(String text, String path) throws IOException {
+		BufferedWriter b = new BufferedWriter(new FileWriter(path));
+		String[] lines = text.split("\n");
+		for(String l : lines) {
+			b.write(l);
+			b.newLine();
+		}
+		b.close();
+	}
+
+	public synchronized static void scriviFile(JSONObject job, String path) throws IOException {
+		scriviFile(convertiJSON(job),path);
+	}
+	
+	private static String convertiJSON(JSONObject job) throws IOException {
+		String[] strings = job.toString().split(",");
+		StringBuffer text = new StringBuffer();
+		int index = 1;
+		for(String s : strings)
+			if(strings.length != index) {
+				text.append(s).append(",\n");
+				index++;
+			} else text.append(s);
+		return text.toString();
+	}
+	
+	public static void appendiFile(String text, String path) throws IOException {
+		String fileContents = leggiFile(path);
+		StringBuffer s = new StringBuffer();
+		if(!fileContents.isBlank())
+			s.append(fileContents).append("\n");
+		s.append(text);
+		scriviFile(s.toString(),path);
+	}
+	
+	public static void appendiFile(JSONObject job, String path, boolean splitLines) throws IOException {
+		appendiFile(splitLines ? convertiJSON(job) : job.toString() ,path);
+	}
+	
+	public static void appendiFile(JSONObject job, String path) throws IOException {
+		appendiFile(job,path,true);
+	}
+	
+	public static long timeDifference(Temporal older, Temporal newer) {
+		return Duration.between(older, newer).toSeconds();
+	}
+}
diff --git a/ScenariMicroservizio/src/utility/MyQueue.java b/ScenariMicroservizio/src/utility/MyQueue.java
new file mode 100644
index 0000000000000000000000000000000000000000..da7359c5a76a2c1749360e9336ea727d46ce4cf2
--- /dev/null
+++ b/ScenariMicroservizio/src/utility/MyQueue.java
@@ -0,0 +1,35 @@
+package utility;
+import java.util.ArrayList;
+
+public class MyQueue<T> {
+
+	private ArrayList<T> queue;
+	
+	public MyQueue() {
+		this.queue = new ArrayList<T>();
+	}
+	
+	public boolean isEmpty() {
+		return queue.isEmpty();
+	}
+	
+	public synchronized void send(T n) {
+		queue.add(n);
+		notifyAll();
+	}
+	
+	public synchronized T receive() {
+		while(isEmpty()) {
+			try {
+				wait();
+			} catch(InterruptedException ex) {
+				System.out.println("Interrupted exception");
+			}
+		}
+		return queue.remove(0);
+	}
+	
+	public synchronized void removeAll() {
+		queue.clear();
+	}
+}
diff --git a/ScenariMicroservizio/src/utility/Pair.java b/ScenariMicroservizio/src/utility/Pair.java
new file mode 100644
index 0000000000000000000000000000000000000000..5faf4f718bdde1b499ac822a2388ec5ba409c802
--- /dev/null
+++ b/ScenariMicroservizio/src/utility/Pair.java
@@ -0,0 +1,21 @@
+package utility;
+
+public class Pair {
+
+	private String topic;
+	private String msg;
+	
+	
+	public Pair(String topic, String msg) {
+		this.topic = topic;
+		this.msg = msg;
+	}
+	
+	public String getTopic() {
+		return topic;
+	}
+	
+	public String getMsg() {
+		return msg;
+	}
+}
diff --git a/ScenariMicroservizio/src/utility/Publisher.java b/ScenariMicroservizio/src/utility/Publisher.java
new file mode 100644
index 0000000000000000000000000000000000000000..a5c8b89907c85213a3cfa5444a672add5dfbb0b9
--- /dev/null
+++ b/ScenariMicroservizio/src/utility/Publisher.java
@@ -0,0 +1,38 @@
+package utility;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.MqttTopic;
+
+import scenari.Scenari;
+
+public class Publisher extends Thread {
+
+	private MyQueue<Pair> coda;
+	private Scenari scenari;
+	
+	public Publisher(MyQueue<Pair> coda, Scenari scenari) {
+		this.coda = coda;
+		this.scenari = scenari;
+	}
+	
+	public void aggiungiComando(String topic, String msg) {
+		coda.send(new Pair(topic, msg));
+	}
+	
+	
+	public void run() {
+		while(true) {
+			Pair p = coda.receive();
+			try {
+				sendMqttMessage(p.getTopic(), p.getMsg());
+			} catch (MqttException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+	
+	private void sendMqttMessage(String topic, String msg) throws MqttException {
+		final MqttTopic msgTopic = scenari.mqttClient.getTopic(topic);
+		msgTopic.publish(new MqttMessage(msg.getBytes()));
+	}
+}
diff --git a/ScenariMicroservizio/src/utility/SubscribeCallback.java b/ScenariMicroservizio/src/utility/SubscribeCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..0fd6f35b6c5e4e302302a9cbd89fee48f69fbb9f
--- /dev/null
+++ b/ScenariMicroservizio/src/utility/SubscribeCallback.java
@@ -0,0 +1,224 @@
+package utility;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+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 Publisher publisher;
+	private String learnTrigger;
+	private String attivaScenari;
+	private Esecutore esec;
+	private Automa automa;
+	
+	public SubscribeCallback(Scenari scenari, Publisher publisher, String learnTrigger, String attivaScenari, Esecutore esec, Automa automa) {
+		this.scenari = scenari;
+		this.publisher = publisher;
+		this.learnTrigger = learnTrigger;
+		this.attivaScenari = attivaScenari;
+		this.esec = esec;
+		this.automa = automa;
+	}
+
+	@Override
+	public void connectionLost(Throwable arg0) {
+		System.out.println("connessione persa\t"+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 {
+				System.out.println("retrying...");
+				
+				Scenari.main(null);
+				return;
+//				esec.interrupt();
+//				publisher.interrupt();
+//				publisher = new Publisher(new MyQueue<Pair>(), scenari);
+//				esec = new Esecutore(publisher,automa);
+				
+//				scenari.startClient(esec, publisher);
+//				retry = false;
+			} catch (MqttException | JSONException | IOException e) {
+				System.out.println("non sono riusciuto");
+				d2 = new Date();
+				time = Math.abs(d2.getTime()-d.getTime());
+			}
+		}
+		System.out.println("fuori dal while");
+		if(time>=600000) {
+			System.out.println("Tentativo di riconnessione fallito");
+			System.exit(1);
+		}
+	}
+
+	
+	@Override
+	public void deliveryComplete(IMqttDeliveryToken arg0) {
+		// Nessuna operazione
+		System.out.println("inviato");
+	}
+	
+
+	@Override
+	public void messageArrived(String topic, MqttMessage message) throws MqttException, JSONException, IOException {
+//		topic = topic.toLowerCase();
+		System.out.println("new message: "+topic+"  "+message.toString());
+		if(topic.equals("to/all")) {
+			System.out.println("invio lo stato dell'automa");
+			sendRequested("from/gruppo2/luci/scenari/description",false);
+			return;
+		}
+		if(topic.equals("rpc/gruppo2/luci/scenari")) {
+			System.out.println("invio la mia configurazione");
+			sendRequested("from/gruppo2/luci/scenari",true); // CONTROLLA SE VA BENE PUBBLICARE LO STATO SU QUESTO TOPIC O SE IL TOPIC DEVE ESSERE UN'ALTRO. NOTA: NON POSSO PUBBLICARE SULLO STESSO TOPIC CHE HO SOTTOSCRITTO
+			return;
+		}
+		
+		
+		JSONObject msgJson = new JSONObject(message.toString());
+		// CONTROLLA SULLA BEAGLEBONE CHE IL MESSAGGIO MANDATO SIA UN INT. CONTROLLA ANCHE IL TOPIC SU CUI MANDA I MESSAGGI (da aver sottoscritto i topic correttamente)
+		
+//		gli event sono 0 o 1; i trigger quando sono attivati/premuti inviano uno 0, che e' l'unico elemento che mi interessa
+		if(topic.equals("from/gruppo2/luci/gpio/"+learnTrigger)) {
+			System.out.println("trigger per learn\t"+!automa.getAntifurto());
+			if(automa.getAntifurto())//se l'antifurto e' attivo, non posso attivare gli scenari
+				return;
+			int newStatus = msgJson.getInt("event");
+			if(newStatus != 1)
+				return;
+			handleEvent(newStatus,learnTrigger);
+			return;
+		}
+		if(topic.equals("from/gruppo2/luci/gpio/"+attivaScenari)) {
+			System.out.println("trigger per antifurto\t"+!automa.getLearn());
+			if(automa.getLearn())//se l'apprendimento e' attivo, non posso attivare l'antifurto
+				return;
+			int newStatus = msgJson.getInt("event");
+			if(newStatus != 1)
+				return;
+			handleEvent(newStatus,attivaScenari);
+			return;
+		}
+		if(topic.startsWith("from/gruppo2/luci/gpio/IN")) {
+			System.out.println("totalmente inutile per me!");
+			return;//non mi interessa altro da IN
+		}
+//		if(topic.equals("to/gruppo2/luci/scenari/learn")) {//mi aspetto un {learn:true/false}, scritto da handleEvent
+//			System.out.println("messaggio per iniziare/terminare a imparare");
+//			boolean val = msgJson.getBoolean("learn");
+//			handleLearn(val);
+//			return;
+//		}
+		if(topic.startsWith("from/gruppo2/luci/gpio/OUT")) {
+			if(message.toString().contains("event")) {
+				System.out.println("se learn==true, salvo questo event!");
+				System.out.println(automa.getLearn()+"\t"+msgJson.toString());
+			}
+			if(!automa.getLearn() || !message.toString().contains("event"))
+				return;
+			if(scenarioName == null) {
+				handleLearn(true);
+			}
+			int val = msgJson.getInt("event");
+			String luce = topic.substring(23);
+			handleLearnData(luce,val);
+			return;
+		}
+		
+		System.out.println("Impossibile");
+	}
+	
+	private void handleEvent(int newStatus,String which) throws JSONException, MqttException{
+//		if(newStatus != 1)
+//			return;
+		String cosa = which == learnTrigger ? "learn" : "antifurto";
+		String cmd = automa.findPossibleCommand(cosa);
+		if(cmd == null)
+			return;
+		System.out.println("handling event: "+cosa+"\t"+cmd);
+		automa.setStato(new JSONObject().put(cosa,cmd).toString());
+		System.out.println("stato\t"+automa.getStato());
+		if(Helper.compareText(cosa, "learn")) {
+//			JSONObject j = new JSONObject().put("learn", Helper.compareText(cmd, "on"));
+//			Helper.sendMqttMessage(scenari.mqttClient, "to/gruppo2/luci/scenari/learn", j.toString());
+//			publisher.aggiungiComando("to/gruppo2/luci/scenari/learn", j.toString());//NON posso inviare ad un topic che subbo
+			boolean val = Helper.compareText(cmd, "on");
+			handleLearn(val);
+		}
+//		if(newStatus!=-1) {
+//		String statusOnOff = automa.converter(newStatus); // lo stato e' della forma "on" oppure "off"
+//		if(! statusOnOff.equals(automa.getStatoSuono()) ) {
+//			automa.aggiornaStatoSuono(statusOnOff);
+//		}
+	}
+	
+	private String scenarioName = null;//"scenario"+LocalTime.now();
+//	private LocalTime lastTime = null;
+	
+	private void handleLearn(boolean shouldLearn) {
+		System.out.println("handleLearn "+shouldLearn+" ; "+automa.getLearn());
+		automa.setStato("{\"learn\":"+ (shouldLearn ? "\"on\"" : "\"off\"")+"}");
+		System.out.println("\t"+automa.getLearn());
+		if(automa.getLearn()) {
+			if(/*lastTime == null &&*/ scenarioName == null) {
+//				lastTime = LocalTime.now();
+				scenarioName = "scenario-"+LocalDateTime.now().toString().replace(':', '-')+".json";
+			}
+		} else {
+//			lastTime = null;
+			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();
+//		long diff = Helper.timeDifference(lastTime,now);
+		j.put("tempo", now.format(DateTimeFormatter.ofPattern("HH-mm-ss")));
+//		lastTime = now;
+//		quale luce
+		j.put("luce", luce);
+//		accesa o spenta?
+		j.put("cmd", val);
+		Helper.appendiFile(j, "./db-scenari/"+scenarioName,false);
+	}
+	
+	private void sendRequested(String topic,boolean moreInfo) throws MqttException, JSONException {
+		JSONObject j = new JSONObject();
+		j.put("stato", automa.getStato());
+		if(moreInfo) {
+			j.put("learn", automa.getLearn());
+			j.put("antifurto", automa.getAntifurto());
+			j.put("learn-trigger", learnTrigger);
+			j.put("attiva-scenari", attivaScenari);
+		}
+//		Helper.sendMqttMessage(scenari.mqttClient, topic, j.toString());
+		publisher.aggiungiComando(topic,j.toString()); 
+	}
+	
+//	private void sendDescription(String topic) throws JSONException, MqttException {
+		// DA FARE: guardare quale descrizione manda netmon, archiver, meter,... e implementare di conseguenza questo metodo
+//		String msg = 
+//		publisher.aggiungiComando(topic, msg); 
+//	}
+	
+
+}