Skip to content
Snippets Groups Projects
Commit 8e9df482 authored by Elisa Giglio's avatar Elisa Giglio
Browse files

codice antifurto

parent e11386f8
No related branches found
No related tags found
No related merge requests found
Showing
with 653 additions and 0 deletions
File added
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
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.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Antifurto {
private static String brokerUrl;
private String interruttore;
private String interruttoreOutputSuono;
private static ArrayList<String> topicsSub;
private Date date = new Date();
private String clientId = Long.toString(date.getTime()) + "-sub-pub"; // unique client id
private Automa automa;
private MqttClient mqttClient;
public Antifurto(Automa automa) throws JSONException, IOException, MqttException {
this.automa = automa;
JSONObject jsonObject = new JSONObject(leggiFile("./CONF/conf.json"));
brokerUrl = jsonObject.getString("protocol") + "://" + jsonObject.getString("broker") + ":" + jsonObject.getInt("port");
topicsSub = new ArrayList<String>();
// Su questo topic ricevero' un messaggio del tipo {request:description.json}
// Dovro' quindi mandare la mia descrizione json
topicsSub.add("to/all");
// Su questo topic ricevero' le richieste di inviare il mio stato attuale
topicsSub.add("rpc/gruppo2/luci/antifurto");
jsonObject = new JSONObject(leggiFile("./CONF/zona.json"));
interruttore = jsonObject.getString("interruttore");
topicsSub.add("from/gruppo2/luci/gpio/" + interruttore); // Sottoscrivo i messaggi che notificano il cambiamento di stato dell'interruttore
// Per ogni sensore di movimento, sottoscrivo i messaggi che notificano il loro cambiamento di stato
JSONArray sensori = jsonObject.getJSONArray("sensoriMovimento");
for(int i=0; i<sensori.length(); i++) {
topicsSub.add("from/gruppo2/luci/gpio/" + sensori.get(i));
}
interruttoreOutputSuono = jsonObject.getString("outputSuono");
topicsSub.add("from/gruppo2/luci/gpio/" + interruttoreOutputSuono); // Sottoscrivo i messaggi che notificano il cambiamento di stato dell'interruttore
this.mqttClient = new MqttClient(brokerUrl, clientId);
}
public void startClient(Esecutore esec, Publisher publisher) throws MqttException {
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(false);
mqttClient.setCallback(new SubscribeCallback(this, publisher, interruttore, interruttoreOutputSuono, esec, automa));
mqttClient.connect(options);
for(String t: topicsSub)
mqttClient.subscribe(t);
}
public void publishMethod(String topic, String msg) throws MqttException {
final MqttTopic msgTopic = mqttClient.getTopic(topic);
msgTopic.publish(new MqttMessage(msg.getBytes()));
}
private String leggiFile(String path) throws IOException {
String line;
String answer = "";
FileReader fileReader = new FileReader(path);
BufferedReader bufferedReader = new BufferedReader(fileReader);
while((line = bufferedReader.readLine()) != null) {
answer += line;
}
bufferedReader.close();
return answer;
}
/*
* 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 {
//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();
// }
// }
}
private static void startSystem() throws JSONException, IOException, MqttException {
MyQueue<Integer> codaVal = new MyQueue<Integer>();
MyQueue<Pair> codaMsg = new MyQueue<Pair>();
Automa automa = new Automa();
Antifurto antifurto = new Antifurto(automa);
Publisher publisher = new Publisher(codaMsg, antifurto);
Esecutore esec = new Esecutore(publisher, codaVal, automa, antifurto.interruttoreOutputSuono);
Timer timer = new Timer(30000,-5,esec,automa);
antifurto.startClient(esec, publisher);
publisher.start();
esec.start();
timer.start();
}
}
File added
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Iterator;
import org.json.JSONException;
import org.json.JSONObject;
public class Automa {
private JSONObject jsonObject; //tabella che descrive l'automa
private Hashtable<String,Integer> deltaSensori; // ad ogni sensore di movimento e' associato il valore di delta
private int statoAttuale;
private String statoInterruttore;
private String statoSuono;
public Automa() throws JSONException, IOException {
this.jsonObject = new JSONObject(leggiFile("./automa.json"));
this.statoInterruttore = "off";
this.statoSuono = "off";
this.statoAttuale = 0;
riempiHashTable();
}
private void riempiHashTable() throws JSONException, IOException {
this.deltaSensori = new Hashtable<String, Integer>();
JSONObject jsObj = new JSONObject(leggiFile("./CONF/deltaSensoriMovimento.json"));
Iterator<String> keys = jsObj.keys();
while(keys.hasNext()) {
String key = keys.next();
int value = jsObj.getInt(key);
deltaSensori.put(key, value);
}
}
private String leggiFile(String path) throws IOException {
String line;
String answer = "";
FileReader fileReader = new FileReader(path);
BufferedReader bufferedReader = new BufferedReader(fileReader);
while((line = bufferedReader.readLine()) != null) {
answer += line;
}
bufferedReader.close();
return answer;
}
public int getDelta(String nomeSensore) {
return deltaSensori.get(nomeSensore);
}
// SERVIRA FORSE PER LA PERSISTENZA
// private synchronized void calcolaStato(String newStatoInterruttore, String newStatoSuono) throws JSONException {
// Iterator<String> keys = jsonObject.keys();
// while(keys.hasNext()) {
// String key = keys.next();
// JSONObject riga = jsonObject.getJSONObject(key);
// if(riga.getString("out0").equals(newStatoInterruttore) && riga.getString("out1").equals(newStatoSuono)) {
// this.statoAttuale = riga.getInt("stato");
// this.statoInterruttore = newStatoInterruttore;
// this.statoSuono = newStatoSuono;
// }
// }
// }
// e' cambiato lo stato dell'interruttore, per cui cerco nel file json in quale nuovo stato devo andare
private synchronized void calcolaNuovoStatoMsgFromInterruttore(String newStatoInterruttore) throws JSONException {
Iterator<String> keys = jsonObject.keys();
while(keys.hasNext()) {
String key = keys.next();
JSONObject riga = jsonObject.getJSONObject(key);
if(riga.getInt("stato")==statoAttuale) {
this.statoAttuale = riga.getInt("cmd"+newStatoInterruttore);
aggiornaInterruttoreESuono();
}
}
}
//in base allo stato attuale dell'antifurto, calcolo lo stato dell'interruttore e del suono
private synchronized void aggiornaInterruttoreESuono() throws JSONException {
Iterator<String> keys = jsonObject.keys();
while(keys.hasNext()) {
String key = keys.next();
JSONObject riga = jsonObject.getJSONObject(key);
if(riga.getInt("stato")==statoAttuale) {
this.statoInterruttore = riga.getString("out0");
this.statoSuono = riga.getString("out1");
}
}
}
// e' cambiato lo stato del suono, per cui cerco nel file json in quale nuovo stato devo andare
private synchronized void calcolaNuovoStatoMsgFromSuono(String newStatoSuono) throws JSONException {
String jsonKey = "";
if(newStatoSuono.equals("on"))
jsonKey = "eventValMaggioreSoglia";
else
jsonKey = "eventValMinoreSoglia";
Iterator<String> keys = jsonObject.keys();
while(keys.hasNext()) {
String key = keys.next();
JSONObject riga = jsonObject.getJSONObject(key);
if(riga.getInt("stato")==statoAttuale) {
this.statoAttuale = riga.getInt(jsonKey);
aggiornaInterruttoreESuono();
}
}
}
public synchronized void changeStatoInterruttore() throws JSONException {
if(statoInterruttore.equals("on"))
calcolaNuovoStatoMsgFromInterruttore("off");
else
calcolaNuovoStatoMsgFromInterruttore("on");
}
public synchronized void aggiornaStatoSuono(String newStatoSuono) throws JSONException {
calcolaNuovoStatoMsgFromSuono(newStatoSuono);
}
public synchronized String getStatoAutoma() {
return "{\"stato\":"+statoAttuale+",\"interruttore\":\""+statoInterruttore+"\",\"allarme\":\""+statoSuono+"\"}";
}
public synchronized String getStatoInterruttore() {
return statoInterruttore;
}
public synchronized String getStatoSuono() {
return statoSuono;
}
// Ritorna true se l'antifurto e' attivo
public synchronized boolean antifurtoAttivo() {
if(statoInterruttore.equals("on"))
return true;
return false;
}
// Ritorna true se l'antifurto sta suonando
public synchronized boolean allarme() {
if(statoSuono.equals("on"))
return true;
return false;
}
// con input la stringa "0" restituisce "off"
// con input la stringa "1" restituisce "on"
public String converter(int num) {
if(num==0)
return "off";
return "on";
}
}
{
"confdir": "./CONF",
"homedir": "./home",
"broker": "localhost",
"protocol": "tcp",
"port": 1883
}
{
"IN1":33,
"IN2":4,
"IN3":8
}
{
"interruttore": "IN0",
"sensoriMovimento": [
"IN1",
"IN2",
"IN3"
],
"outputSuono":"OUT3"
}
File added
File added
import java.time.Duration;
import java.time.LocalDateTime;
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, String outputSuono) {
this.codaVal = codaVal;
this.valore = 0;
this.automa = automa;
this.publisher = publisher;
this.outputSuono = outputSuono;
}
public void run() {
final long DURATA_SUONO = 5; // l'allarme dura 5 minuti e poi smette di suonare
int delta;
LocalDateTime tempoAllarme = null;
while(true) {
while(automa.antifurtoAttivo()) { System.out.println("VALORE = "+ valore);
delta = codaVal.receive();
valore = valore + delta;
if(valore >= SOGLIA && (!automa.allarme()) ) {
publisher.aggiungiComando("to/gruppo2/luci/gpio/"+outputSuono, "{cmd:1}");
tempoAllarme = LocalDateTime.now();
}
else {
if(automa.allarme()) {
LocalDateTime tempoAttuale = LocalDateTime.now();
long durata = Math.abs(Duration.between(tempoAllarme, tempoAttuale).toMinutes());
if(valore < SOGLIA || durata >= DURATA_SUONO || !automa.antifurtoAttivo() ) {
publisher.aggiungiComando("to/gruppo2/luci/gpio/"+outputSuono, "{cmd:0}"); // l'allarme viene disattivato
}
}
}
}
if(!automa.antifurtoAttivo()) {
reset();
}
}
}
public void aggiungiVal(int n) {
codaVal.send(n);
}
public void reset() {
valore = 0;
codaVal.removeAll();
}
}
File added
File added
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();
}
}
File added
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;
}
}
File added
import org.eclipse.paho.client.mqttv3.MqttException;
public class Publisher extends Thread {
private MyQueue<Pair> coda;
private Antifurto client;
public Publisher(MyQueue<Pair> coda, Antifurto client) {
this.coda = coda;
this.client = client;
}
public void aggiungiComando(String topic, String msg) {
coda.send(new Pair(topic, msg));
}
public void run() {
while(true) {
Pair p = coda.receive();
try {
client.publishMethod(p.getTopic(), p.getMsg());
} catch (MqttException e) {
e.printStackTrace();
}
}
}
}
File added
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 String nomeInterruttore;
private String nomeOutputSuono;
private Esecutore esec;
private Automa automa;
public SubscribeCallback(Antifurto client, Publisher publisher, String nomeInterruttore, String nomeOutputSuono, Esecutore esec, Automa automa) {
this.client = client;
this.publisher = publisher;
this.nomeInterruttore = nomeInterruttore;
this.nomeOutputSuono = nomeOutputSuono;
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 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 Exception {
if(topic.equals("to/all"))
sendDescription("from/gruppo2/luci/antifurto/description");
else {
if(topic.equals("rpc/gruppo2/luci/antifurto"))
sendMyState("from/gruppo2/luci/antifurto"); // 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
else {
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)
if(topic.equals("from/gruppo2/luci/gpio/"+nomeOutputSuono)) {
int newStatus = -1;
if(msgJson.has("status"))
newStatus = msgJson.getInt("status");
else {
if(msgJson.has("event"))
newStatus = msgJson.getInt("event");
}
handleStateMsgFromOutputSuono(newStatus);
}
else {
int event = msgJson.getInt("event");
if(event==0) {
// e' stato premuto l'interruttore / il sensore di movimento ha rilevato qualcuno
if(topic.equals("from/gruppo2/luci/gpio/"+nomeInterruttore))
handleStateMsgFromInterruttore();
else {
// il topic sara' from/gruppo2/luci/gpio/IN0 dove IN0 e' un sensore di movimento
String[] t = topic.split("/");
handleMovimento(t[4]);
}
}
}
}
}
}
private synchronized void handleStateMsgFromInterruttore() throws JSONException {
automa.changeStatoInterruttore();
if(automa.getStatoInterruttore().equals("off")) {
publisher.aggiungiComando("to/gruppo2/luci/gpio/"+nomeOutputSuono, "{cmd:0}");
esec.reset();
}
}
private synchronized void handleStateMsgFromOutputSuono(int newStatus) throws JSONException {
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 void handleMovimento(String nomeSensore) {
if(automa.getStatoInterruttore().equals("on"))
esec.aggiungiVal(automa.getDelta(nomeSensore));
}
private void sendMyState(String topic) throws MqttException {
publisher.aggiungiComando(topic, "{\"status\":"+automa.getStatoAutoma()+"}");
}
private void sendDescription(String topic) {
// DA FARE: guardare quale descrizione manda netmon, archiver, meter,... e implementare di conseguenza questo metodo
// String msg =
// publisher.aggiungiComando(topic, msg);
}
}
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment