Cuprins:

SmartBin: 8 pași
SmartBin: 8 pași

Video: SmartBin: 8 pași

Video: SmartBin: 8 pași
Video: Huawei Band 8 - Unboxing si review | Comparare cu band 7 si 6 2024, Noiembrie
Anonim
SmartBin
SmartBin

Este é um proiectat pentru un sistem inteligent de colete, nu pot fi pasionați de lixo recebem dados das lixeiras, identificând o cantitate de lixo prezentă în fiecare uma delas, e uma rota de coletă traçada, com base nas informações recuperadas.

Pentru a monta acest proiect, este necesar:

  • NodeMCU
  • Senzor ultrasonic de distanță
  • Caixa de paperão
  • Protoboard
  • Cabos
  • Dispozitiv Android

Pasul 1: Conectarea senzorului O

Primeiramente, vamos efetuar a conexão entre o sensor ultrassônico e o NODEMCU. Pentru atât, vom conecta ca portele declanșează și echo do sensor nas portas D4 și D3 do NodeMCU:

// definește numerele pinilor #define pino_trigger 2 // D4

#define pino_echo 0 // D3

Para efetuar a leitura dos dados do sensor, a fost urmat sau tutorial elaborat pelo FilipeFlop, disponível aqui.

float cmMsec, inMsec;

lung microsec = ultrasonic.timing ();

cmMsec = ultrasonic.convert (microsec, Ultrasonic:: CM);

inMsec = ultrasonic.convert (microsec, Ultrasonic:: IN);

// Exibe nu informează monitorul serial

Serial.print ("Distancia em cm:");

Serial.print (cmMsec);

Serial.print ("- Distancia em polegadas:");

Serial.println (inMsec);

Date șir = Șir (cmMsec);

Serial.println (date);

Pasul 2: Montando a Lixeira

Agora, vamos montar a lixeira inteligente. Precisaremos conectar o sensor ultrassônico no “teto” da lixeira. Pentru un exemplu, utilizați um cabo și fita izolant. Em urmată, avem că medir a distanței inițiale, pentru saber o valoare pentru a lixeira vazia. No meu caso, foi de 26, 3cm. Esse é o valor care considerarmos pentru uma lixeira vazia.

Para simulação, visto que não possuo mais de um sensor ultrassônico, a fost făcut um algoritm pentru a salva aleatoriu la distanță lida em 4 lixeiras diferite.

// Simulando 4 lixeiras

lung lixeiraID;

bucla nulă () {

lixeiraID = aleatoriu (1, 5);

}

Pasul 3: Încărcați Para a Nuvem

Agora, precisamos enviar estes dados para a nuvem. Eu escolhi o ThingSpeak, por familiaritate com chiar. Primeiramente, este necesar un criar um novo canal, recebendo 4 parametri, referințe la volumul de fiecare lixeira.

Se conectează la aplicație cu ThingSpeak, este necesar să se salveze numărul de API de canal criado. Siga os passos descritos no site oficial.

De volta à aplicação, vamos use a biblioteca ESP8266WiFi.h for efetuar connection with o ThingSpeak, and transferir os dados.

Primeiramente, uma funcționare pentru a efectua conexiuni com a rede (defina anterior duas variáveis, ssid e pass , contendo o identificador e a senha de sua rede).

void connectWifi () {

Serial.print ("Conectarea la" + * ssid);

WiFi.begin (ssid, pass);

while (WiFi.status ()! = WL_CONNECTED) {

întârziere (500);

Serial.print (".");

}

Serial.println ("");

Serial.print ("Conectado na rede");

Serial.println (ssid);

Serial.print ("IP:");

Serial.println (WiFi.localIP ());

}

În timpul configurării, încercăm să conectăm o conexiune cu un red.

configurare nulă () {

Serial.begin (9600);

Serial.println ("Lendo dados do sensor …");

// Conectarea ao Wi-Fi

connectWifi ();

}

E, pentru a trimite date pentru o ThingSpeak, basta deschide o conexiune HTTP padrão, trecând numărul de API și parametrii.

void sendDataTS (float cmMsec, id lung) {

if (client.connect (server, 80)) {

Serial.println ("Enviando dados para o ThingSpeak");

String postStr = apiKey;

postStr + = "& câmp";

postStr + = id;

postStr + = "=";

postStr + = String (cmMsec);

postStr + = "\ r / n / r / n";

Serial.println (postStr);

client.print ("POST / actualizare HTTP / 1.1 / n");

client.print ("Gazdă: api.thingspeak.com / n");

client.print ("Conexiune: închidere / n");

client.print ("X-THINGSPEAKAPIKEY:" + apiKey + "\ n");

client.print ("Content-Type: application / x-www-form-urlencoded / n");

client.print („Lungime conținut:”);

client.print (postStr.length ());

client.print ("\ n / n");

client.print (postStr);

întârziere (1000);

}

client.stop ();

}

O primul parametru corespunde distanței cu centimetri găsit cu senzor ultrasonic. O al doilea parametru este o ID da lixeira care a fost lida (care a fost gerat aleatoriu, un număr de 1 la 4).

O ID da lixeira serve alsom for identificar for qual field will done o upload do valor lido.

Pasul 4: Recuperarea Dados Do ThingSpeak

O ThingSpeak permite efetuar leitura dos dados do seu canal, através de um serviço returnando um JSON. As diferite opțiuni pentru leitura do feed do seu canal estão descritas aqui:

www.mathworks.com/help/thingspeak/get-a-ch…

În acest proiect, optou-se por ler diretamente os dados de cada campo. O pagină de URL pentru acest cenário este:

api.thingspeak.com/channels/CHANNEL_ID/fields/FIELD_NUMBER/last.json?api_key=API_KEY&status=true

Cada campo está descrito no link informado previamente. Os mais important for o projecteto são:

  • CHANNEL_ID: numărul do seu canal
  • FIELD_NUMBER: o numărul do campo
  • API_KEY: a chave de API do seu canal

Aceasta este o adresă URL care va fi aplicată pentru Android, pentru a recupera dosarele ThingSpeak.

Pasul 5: Criando a Aplicação Android

Nu există Android Studio, creează un proiect nou pentru Android. Pentru funcționarea corectă a aplicației, este necesar să configurați permisiunea abaixo în AndroidManifest.

Pentru a utiliza Google Maps, va fi necesar să vă conectați la Google. Siga os passos descritos no link Obter chave de API.

Uma vez com a chave, você deve alsom configurá-la na aplicação.

Cheia API pentru API-urile bazate pe Google Maps este definită ca o resursă șir.

(A se vedea fișierul „res / values / google_maps_api.xml”).

Rețineți că cheia API este legată de cheia de criptare utilizată pentru semnarea APK-ului. Aveți nevoie de o altă cheie API pentru fiecare cheie de criptare, inclusiv cheia de lansare utilizată pentru semnarea APK-ului pentru publicare. Puteți defini cheile pentru țintele de depanare și de lansare în src / debug / și src / release /.

<meta-date

android: name = "com.google.android.geo. API_KEY"

android: value = "@ string / google_maps_key" />

O configurare completă este mo arquivo AndroidManifest anexado ao projeto.

n

Pasul 6: Recuperarea feedului O fără Android

Na atividade principal no Android, MainActivity, crie 4 variáveis pentru a identifica fiecare um dos canais do ThingSpeak a serem lidos:

private String url_a = "https://api.thingspeak.com/channels/429823/fields/1/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; private String url_b = "https://api.thingspeak.com/channels/429823/fields/2/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; private String url_c = "https://api.thingspeak.com/channels/429823/fields/3/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true"; private String url_d = "https://api.thingspeak.com/channels/429823/fields/4/last.json?api_key="+API_THINGSPEAK_KEY+"&status=true";

Para efetuar a leitura dos dados, iremos use uma class do Android specific, chamada JSONObject. Mai multe ori, vamos criar um obiect pentru fiecare URL:

JSONObject responseLixeiraA; JSONObject responseLixeiraB; JSONObject responseLixeiraC; JSONObject responseLixeiraD;

Pentru a deschide o conexiune com as urls, vamos use criar uma class auxiliar, chamada HttpJsonParser. Această clasă va fi responsabilă pentru a deschide o conexiune cu un URL, efectua leitura dos dados encontrados, e returnar o object JSON montado.

public JSONObject makeHttpRequest (String url, String method, Map params) {

încerca {

Uri. Builder builder = nou Uri. Builder (); URL urlObj; String encodedParams = ""; if (params! = null) {for (Map. Entry entry: params.entrySet ()) {builder.appendQueryParameter (entry.getKey (), entry.getValue ()); }} if (builder.build (). getEncodedQuery ()! = null) {encodedParams = builder.build (). getEncodedQuery ();

}

if ("GET".equals (method)) {url = url + "?" + encodedParams; urlObj = URL nou (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metodă);

} altceva {

urlObj = URL nou (url); urlConnection = (HttpURLConnection) urlObj.openConnection (); urlConnection.setRequestMethod (metodă); urlConnection.setRequestProperty ("Content-Type", "application / x-www-form-urlencoded"); urlConnection.setRequestProperty ("Content-Length", String.valueOf (encodedParams.getBytes (). length)); urlConnection.getOutputStream (). write (encodedParams.getBytes ()); } // Conectați-vă la server urlConnection.connect (); // Citiți răspunsul este = urlConnection.getInputStream (); Cititor BufferedReader = nou BufferedReader (nou InputStreamReader (este)); StringBuilder sb = new StringBuilder (); Linia de corzi;

// Analizați răspunsul

while ((line = reader.readLine ())! = null) {sb.append (line + "\ n"); } este aproape(); json = sb.toString (); // Convertiți răspunsul în obiect JSON jObj = new JSONObject (json);

} catch (UnsupportedEncodingException e) {

e.printStackTrace (); } catch (ProtocolException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); } catch (JSONException e) {Log.e ("JSON Parser", "Error parsing data" + e.toString ()); } catch (Exception e) {Log.e ("Exception", "Error parsing data" + e.toString ()); }

// returnează obiectul JSON

retur jObj;

}

}

De volta a atividade principal, vamos efetuar a chamada às urls de forma assíncrona, escrevendo this code inside do method doInBackground.

@Override protejat String doInBackground (String … params) {HttpJsonParser jsonParser = new HttpJsonParser ();

responseLixeiraA = jsonParser.makeHttpRequest (url_a, "GET", nul);

responseLixeiraB = jsonParser.makeHttpRequest (url_b, "GET", nul); responseLixeiraC = jsonParser.makeHttpRequest (url_c, "GET", nul); responseLixeiraD = jsonParser.makeHttpRequest (url_d, "GET", nul);

return nul;}

Când o metodă doInBackgroundé încearcă, sau controlul de execuție pe Android trece pentru o metodă onPostExecute. În această metodă, putem crea obiecte Lixeira, și popularele noastre sunt recuperate de ThingSpeak:

void protejat onPostExecute (rezultat șir) {pDialog.dismiss (); runOnUiThread (nou Runnable () {public void run () {

// ListView listView = (ListView) findViewById (R.id.feedList);

Vizualizare mainView = (Vizualizare) findViewById (R.id.activity_main); if (success == 1) {try {// Cria feedDetail para cada lixeira Lixeira feedDetails1 = new Lixeira (); Lixeira feedDetails2 = new Lixeira (); Lixeira feedDetails3 = new Lixeira (); Lixeira feedDetails4 = new Lixeira ();

feedDetails1.setId ('A');

feedDetails1.setPesoLixo (Double.parseDouble (responseLixeiraA.getString (KEY_FIELD1))); feedDetails1.setVolumeLixo (Double.parseDouble (responseLixeiraA.getString (KEY_FIELD1)));

feedDetails2.setId ('B');

feedDetails2.setPesoLixo (Double.parseDouble (responseLixeiraB.getString (KEY_FIELD2))); feedDetails2.setVolumeLixo (Double.parseDouble (responseLixeiraB.getString (KEY_FIELD2)));

feedDetails3.setId („C”);

feedDetails3.setPesoLixo (Double.parseDouble (responseLixeiraC.getString (KEY_FIELD3))); feedDetails3.setVolumeLixo (Double.parseDouble (responseLixeiraC.getString (KEY_FIELD3)));

feedDetails4.setId ('D');

feedDetails4.setPesoLixo (Double.parseDouble (responseLixeiraD.getString (KEY_FIELD4))); feedDetails4.setVolumeLixo (Double.parseDouble (responseLixeiraD.getString (KEY_FIELD4)));

feedList.add (feedDetails1);

feedList.add (feedDetails2); feedList.add (feedDetails3); feedList.add (feedDetails4);

// Calcula dados das lixeiras

Calculator SmartBinService = nou SmartBinService (); calculator.montaListaLixeiras (feedList);

// Recupera componente

TextView createDate = (TextView) mainView.findViewById (R.id.date); ListView listaDeLixeiras = (ListView) findViewById (R.id.lista); adapter.addAll (feedList);

// Date atuale

Data currentTime = Calendar.getInstance (). GetTime (); SimpleDateFormat simpleDate = nou SimpleDateFormat ("zz / LL / aaaa"); String currentDate = simpleDate.format (currentTime); createDate.setText (KEY_DATE + currentDate + ""); listaDeLixeiras.setAdapter (adaptor);

} catch (JSONException e) {

e.printStackTrace (); }

} altceva {

Toast.makeText (MainActivity.this, "A apărut o eroare la încărcarea datelor", Toast. LENGTH_LONG).show ();

}

} }); }

Agora, na tela initial do applicativo, serão listados os dados de cada lixeira.

Pasul 7: Mostrando fără hartă

Mostrando No Map
Mostrando No Map

Ainda na atividade principal, vamos adicionar uma ação a ser related to botão Mapa, na tela initial.

/ ** Apelat când utilizatorul atinge butonul Mapa * / public void openMaps (Vizualizare vizualizare) {Intent intent = new Intent (aceasta, LixeiraMapsActivity.class);

// Passa a lista de lixeiras

Bundle bundle = pachet nou (); bundle.putParcelableArrayList ("lixeiras", feedList); intent.putExtras (pachet);

startActivity (intenție);

}

No map, avem três atividades to executar:

  1. marcar a posição atual do caminha de lixo
  2. marcar os pontos corespondente a fiecare lixeira no mapa
  3. traçar a rota între os pontos

Pentru a executa pasul acima, folosim un API Google Directions. Pentru a dezvolta ca roti, foram urmăriți și treceți tutorial Desenarea direcțiilor rutei de conducere între două locații folosind Direcțiile Google în Google Map Android API V2

Primeiro, vamos criar localidades para cada um dos pontos que desejamos marcar:

// Locații

curent LatLng privat;

private LatLng lixeiraA; private LatLng lixeiraB; private LatLng lixeiraC; private LatLng lixeiraD;.

Pentru a adăuga o poziție actuală pe o hartă, a fost criat sau metodă:

private void checkLocationandAddToMap () {// Verificarea dacă utilizatorul a acordat permisiunea dacă (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (this, android. Manifest) ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Solicitarea permisiunii de localizare ActivityCompat.requestPermissions (acest nou șir {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); întoarcere; }

// Preluarea ultimei locații cunoscute folosind Fus

Location location = LocationServices. FusedLocationApi.getLastLocation (googleApiClient);

// MarkerOptions sunt folosite pentru a crea un nou Marker. Puteți specifica locația, titlul etc. cu MarkerOptions

this.current = new LatLng (location.getLatitude (), location.getLongitude ()); MarkerOptions markerOptions = new MarkerOptions (). Position (current).title ("Posição atual");

// Adăugarea marcatorului creat pe hartă, mutarea camerei în poziție

markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_GREEN)); System.out.println ("++++++++++++++ Passei aqui! ++++++++++++++"); mMap.addMarker (markerOptions);

// Mutați camera instantaneu în locație cu un zoom de 15.

mMap.moveCamera (CameraUpdateFactory.newLatLngZoom (curent, 15));

// Măriți, animând camera.

mMap.animateCamera (CameraUpdateFactory.zoomTo (14), 2000, nul);

}

Em urmat, pentru fiecare lixeira, foram criados métodos similar ao abaixo:

private void addBinALocation () {// Verificarea dacă utilizatorul a acordat permisiunea dacă (ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_FINE_LOCATION)! = PackageManager. PERMISSION_GRANTED && ActivityCompat.checkSelfPermission (this, android. Manifest.permission. ACCESS_COARSE_LOCATION)! = PackageManager. PERMISSION_GRANTED) {// Solicitarea permisiunii de localizare ActivityCompat.requestPermissions (acest nou șir {android. Manifest.permission. ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); întoarcere; }

// Praça da Estação

latitudine dublă = -19.9159578; longitudine dublă = -43.9387856; this.lixeiraA = LatLng nou (latitudine, longitudine);

MarkerOptions markerOptions = new MarkerOptions (). Poziție (lixeiraA).title ("Lixeira A");

markerOptions.icon (BitmapDescriptorFactory.defaultMarker (BitmapDescriptorFactory. HUE_RED)); mMap.addMarker (markerOptions); }

As posições de latitude e longitude de cada lixeira foram recuperated através do próprio Google Maps, e deixadas fixas no code. În mod ideal, aceste valori sunt salvate cu un banc de date (de exemplu Firebase). A fost prima evoluție a acestui proiect!

O último passo agora é traçar as rotas entre os pontos. Pentru tal, um conceito muito important, și care va fi folosit în acest proiect, s-a salvat de Waypoints!

Foi criado um method for traçar a rota între dois dados pontos:

private String getDirectionsUrl (origine LatLng, LatLng dest, List waypointsList) {

// Originea traseului

String str_origin = "origin =" + origin.latitude + "," + origin.longitude;

// Destinația traseului

String str_dest = "destination =" + dest.latitude + "," + dest.longitude;

// Puncte de parcurs de-a lungul traseului

//waypoints=optimize:true|-19.9227365, -43.9473546 | -19.9168006, -43.9361124 String waypoints = "waypoints = optimize: true"; pentru (punct LatLng: waypointsList) {waypoints + = "|" + point.latitude + "," + point.longitude; }

// Senzor activat

String sensor = "senzor = fals";

// Construirea parametrilor serviciului web

Parametrii șirului = str_origin + "&" + str_dest + "&" + senzor + "&" + puncte de referință;

// Format de iesire

Șir de ieșire = "json";

// Construirea adresei URL către serviciul web

String url = "https://maps.googleapis.com/maps/api/directions/"+output+"?"+parameters; System.out.println ("+++++++++++++++" + url);

returnează adresa URL;

}

E, prin film, juntand tot nu metoda principala din clasa, onMapReady:

@Override public void onMapReady (GoogleMap googleMap) {mMap = googleMap;

checkLocationandAddToMap ();

if (lixeirasList.get (0).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE

|| lixeirasList.get (0).getPesoLixo () - 10> Lixeira. MIN_SIZE_GARBAGE) {addBinALocation (); } if (lixeirasList.get (1).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (1).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinBLocation (); } if (lixeirasList.get (2).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (2).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinCLocation (); } if (lixeirasList.get (3).getVolumeLixo ()> Lixeira. MIN_VOLUME_GARBAGE || lixeirasList.get (3).getPesoLixo ()> Lixeira. MIN_SIZE_GARBAGE) {addBinDLocation (); }

// Desenați trasee

// Obținerea URL-ului către API-ul Google Directions

Puncte de listă = ArrayList nou (); points.add (lixeiraB); points.add (lixeiraC); points.add (lixeiraD);

String url = getDirectionsUrl (curent, lixeiraA, puncte);

DownloadTask downloadTask = new DownloadTask (); // Începeți să descărcați date JSON din Google Directions API downloadTask.execute (url); }

Aqui passamos apenas pelos pontos principal. O cod complet al proiectului va fi disponibilizat pentru consultare.

Pasul 8: Concluzie

Este foi um projeto trabalhando conceitos de IoT, mostrando uma das várias opções de conectar dispozitive através da nuvem, e efetuar tomada de decisões sem interferência humana direta. Anexează, îmi urmează un videoclip complet proiectat, pentru ilustrație, și fonturile din activități criadă fără Android.

Recomandat: