Další možnost využití Raspberry Pi v domácnosti :). Před časem jsem si pořídil zařízení WD My Cloud – 3TB od western digital (byl za cenu HDD) a zjistil jsem, že není třeba, aby zařízení běželo 24/7. Spotřeba tohoto zařízení v klidovém stavu je cca 6-10 watů, a to o proti raspberry pi je téměř 5ti násobné. Jenže takovéto domácí cloudy se dají pouze vypnout přes webové rozhraní, ale už nejdou nijak vzdáleně spustit. Jak to tedy udělat, aby si každý v domácnosti toto zařízení sám vzdáleně spustil, popřípadě zkontroloval, zda již neběží. (Samozřejmostí je mít veřejnou IP adresu, aby se to dalo ovládat i přes internet. Pokud není, tak bude fungovat pouze na místní síti).
Základní součástky a zapojení
- relé
- prodlužovací kabel se zásuvkou na 220V o délce 1,5m
- mikro spínač
- odpor 10K
- kabely a nepájivé pole
zapojení tlačítka
bude umístěné na stole v nepájivém poli pro případné zapnutí, vypnutí NAS serveru (pokud člověk nechce zapínat přes aplikaci přes telefon, popřípadě přes ssh), zapojeného do této zásuvky
prodlužovací kabel se zásuvkou + relé
kabel pro ovládání relé
nůžkami jsem odstřihnul 4 pin, tak aby to šlo zastrčit do relé
Ovládání pomocí mikrotlačítka
skript pro ovládání tlačítkem, musí nejdříve zkontrolovat stav (zapnuto/vypnuto) a poté udělat příslušnou operaci.
vytvoření skriptu button.py
[notice]sudo nano button.py[/notice]
a vložit
[notice]
import time import RPi.GPIO as GPIO def main(): GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) GPIO.setup(19,GPIO.IN) GPIO.setup(26,GPIO.OUT) while True: if GPIO.input(19): testButton = "false" else: testButton = "true" #print testButton time.sleep(0.15) if GPIO.input(26): testZasuvka = "true" else: testZasuvka = "false" # print testZasuvka time.sleep(0.15) if(testButton=="true" and testZasuvka=="true"): GPIO.output(26,False) if (testButton=="true" and testZasuvka=="false"): GPIO.output(26,True) #GPIO.cleanup() if __name__=="__main__": main()
[/notice]
uzavřít a uložit soubor (CTRL+x a pak „y“ a enter)
aby se tento skript automaticky vždy spustil po startu RPi (aby mohlo být tlačítko obslouženo, v případě stisknutí), tak je nutné dodat řádek do cronu s nastavením pro tento skript
[notice]sudo crontab -e[/notice]
na konec přidáme tento řádek
[notice]@reboot sudo python /home/pi/button.py[/notice]
uzavřít a uložit soubor (CTRL+x a pak „y“ a enter)
Ovládání a kontrola stavu pomocí konzole (přes SSH)
vytvoření skriptu status.py pro kontrolu stavu, zda je nyní zásuvka zapnutá, popřípadě vypnutá
[notice]sudo nano status.py[/notice]
a vložit
[notice]
import RPi.GPIO as GPIO import time GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(26,GPIO.OUT) if GPIO.input(26): testZasuvka = "running" else: testZasuvka = "stopped" print testZasuvka
[/notice]
uzavřít a uložit soubor (CTRL+x a pak „y“ a enter)
test skriptu status.py
vytvoření skriptu cloud.py pro zapnutí, popřípadě vypnutí (záleží na tom, v jakém je to aktuálním stavu)
[notice]sudo nano cloud.py[/notice]
a vložit
[notice]
import RPi.GPIO as GPIO import time GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(26,GPIO.OUT) if GPIO.input(26): GPIO.output(26,False) testZasuvka = "stopped" else: GPIO.output(26,True) testZasuvka = "running" print testZasuvka
[/notice]
uzavřít a uložit soubor (CTRL+x a pak „y“ a enter)
test skriptu cloud.py
Ovládání a kontrola stavu přes Android zařízení
pro ovládání přes internet je nutné mít veřejnou IP adresu. (Jinak funguje pouze po připojení v místní síti). Ve skriptu programu pro android, se při spuštění zkontroluje současný stav přes StatusCloud() – zavolá dotaz na PHP skript (android_cloud.php) a tento skript zavolá skript pro zjištění stavu v PYTHONu (status.py viz. výše), pak se zjistí google účet (GetUserAccount()) a ID zařízení (GetAndroidID()) a to z toho důvodu, aby ovládání zásuvky ovládal jen oprávněný uživatel a nemohlo dojít k nějakému zneužití :). Poslední metodou tam je CloudControl(), který může ovládat zásuvku, který pošle dotaz s uživatelským jménem a ID zařízení na PHP skript (android_cloud_control.php), který nejdříve ověří, že se jedná o oprávněného uživatele a pokud ano, tak PHP skript zavolá skript v PYTHONu (cloud.py viz. výše), který provede změnu.
MainActivity.java
[notice]
package cz.androidapk.teplota; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.regex.Pattern; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.json.JSONArray; import org.json.JSONObject; import cz.androidapk.teplota.R.id; import android.accounts.Account; import android.accounts.AccountManager; import android.content.Context; import android.os.Bundle; import android.os.StrictMode; import android.app.Activity; import android.content.pm.ActivityInfo; import android.graphics.Color; import android.graphics.Typeface; import android.provider.Settings; import android.util.Log; import android.util.Patterns; import android.util.TypedValue; import android.view.Window; import android.view.WindowManager; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import android.widget.ToggleButton; public class MainActivity extends Activity { String resultStatusCloud = ""; ImageView statusImage; String UserAccountEmail; String AndroidID; ToggleButton toggle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_main); statusImage = (ImageView) findViewById(id.imageView); StrictMode.enableDefaults(); getData(); } public void getData(){ StatusCloud(); UserAccountEmail = GetUserAccount(); AndroidID = GetAndroidID(); CloudControl(); } public void StatusCloud(){ //status cloud InputStream isr = null; try{ HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost("http://localhost/android_cloud.php"); HttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); isr = entity.getContent(); }catch(Exception e) { Log.e("log_tag","Error on HTTP connection " + e.toString()); resultView.setText("Couldnt connect to HTTP"); } try{ BufferedReader reader = new BufferedReader(new InputStreamReader(isr,"iso-8859-1"), 8); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null){ sb.append(line + "\n"); } isr.close(); resultStatusCloud = sb.toString(); }catch(Exception e){ Log.e("log_tag","Error converting result "+ e.toString()); } //parse json data try{ ; Log.e("log_tag", resultStatusCloud); if(resultStatusCloud.equals("stopped\n")){ statusImage.setBackgroundResource(R.drawable.red_on_64); }else if(resultStatusCloud.equals("running\n")){ statusImage.setBackgroundResource(R.drawable.green_on_64); }else{ statusImage.setBackgroundResource(R.drawable.white_on_64); } }catch (Exception e){ Log.e("log_tag", "Error Parsing data "+ e.toString()); } } public String GetUserAccount() { Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+ Account[] accounts = AccountManager.get(this).getAccountsByType("com.google"); String possibleEmail = null; for (Account account : accounts) { if (emailPattern.matcher(account.name).matches()) { possibleEmail = account.name; //Log.e("log_tag",possibleEmail); } } return possibleEmail; } public String GetAndroidID(){ String android_id = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID); // Log.e("log_tag",android_id); return android_id; } public void CloudControl(){ toggle = (ToggleButton) findViewById(id.toggleButton); if (resultStatusCloud=="stopped"){ toggle.setChecked(false); }else if (resultStatusCloud=="running"){ toggle.setChecked(true); } toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { InputStream isr = null; String resultControlCloud; try { HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost("http://localhost/android_cloud_control.php"); //add your data ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); nameValuePairs.add(new BasicNameValuePair("username",UserAccountEmail)); nameValuePairs.add(new BasicNameValuePair("password",AndroidID)); httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); //Execute HTTP Post Request HttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); isr = entity.getContent(); }catch(Exception e) { Log.e("log_tag","Error on HTTP connection " + e.toString()); resultView.setText("Couldnt connect to HTTP"); }Log.e("log_tag","isChecked - true"); try{ BufferedReader reader = new BufferedReader(new InputStreamReader(isr,"iso-8859-1"), 8); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null){ sb.append(line + "\n"); } isr.close(); resultControlCloud = sb.toString(); Log.e("log_tag",resultControlCloud); if(resultControlCloud.equals("error\n")){ toggle.setChecked(false); Context context = getApplicationContext(); CharSequence text = "Tak to ti neprojde :) "; int duration = Toast.LENGTH_LONG; Toast toast = Toast.makeText(context, text, duration); toast.show(); } }catch(Exception e) { Log.e("log_tag", "Error converting result " + e.toString()); } getData(); } else { InputStream isr = null; String resultControlCloud; try { HttpClient httpclient = new DefaultHttpClient(); HttpPost httppost = new HttpPost("http://localhost/android_cloud_control.php"); //add your data ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); nameValuePairs.add(new BasicNameValuePair("username",UserAccountEmail)); nameValuePairs.add(new BasicNameValuePair("password",AndroidID)); httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); //Execute HTTP Post Request HttpResponse response = httpclient.execute(httppost); HttpEntity entity = response.getEntity(); isr = entity.getContent(); }catch(Exception e) { Log.e("log_tag","Error on HTTP connection " + e.toString()); resultView.setText("Couldnt connect to HTTP"); }Log.e("log_tag","isChecked - else"); try{ BufferedReader reader = new BufferedReader(new InputStreamReader(isr,"iso-8859-1"), 8); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null){ sb.append(line + "\n"); } isr.close(); resultControlCloud = sb.toString(); Log.e("log_tag",resultControlCloud); if(resultControlCloud.equals("error\n")){ toggle.setChecked(true); Context context = getApplicationContext(); CharSequence text = "Tak to ti neprojde :) "; int duration = Toast.LENGTH_LONG; Toast toast = Toast.makeText(context, text, duration); toast.show(); } }catch(Exception e) { Log.e("log_tag", "Error converting result " + e.toString()); } getData(); } } }); } }
[/notice]
je3t2 je nutné zde sudo nano /etc/sudoers přidat tento řádek, aby bylo možné spouštět python skripty z PHP kódu.
[notice]
sudo nano /etc/sudoers
[/notice]
přidat na konec tento řádek:
www-data ALL=(ALL) NOPASSWD: ALL
uzavřít a uložit soubor (CTRL+x a pak „y“ a enter)
android_cloud.php
[notice]
<?php // Path to the python script - either FULL path or relative to PHP script $pythonScript = 'status.py'; // Path to python executable - either FULL path or relative to PHP script $pythonExec = '/var/www/'; // Check the file exists and PHP has permission to execute it clearstatcache(); if (!file_exists($pythonExec)) { exit("The python executable '$pythonExec' does not exist!"); } if (!is_executable($pythonExec)) { exit(("The python executable '$pythonExec' is not executable!")); } if (!file_exists($pythonScript)) { exit("The python script file '$pythonScript' does not exist!"); } // Execute it, and redirect STDERR to STDOUT so we can see error messages as well exec("echo 'heslo' | sudo -S python \"$pythonExec\"\"$pythonScript\" 2>&1", $output); // Show the output of the script print_r($output[0]); ?>
[/notice]
android_cloud_control.php
[notice]
<?php $username = $_POST['username']; $password = $_POST['password']; if($username == "xxxxx@gmail.com" && $password == "xxxxxxxxxxxxx") { // Path to the python script - either FULL path or relative to PHP script $pythonScript = 'cloud.py'; // Path to python executable - either FULL path or relative to PHP script $pythonExec = '/var/www/'; // Check the file exists and PHP has permission to execute it clearstatcache(); if (!file_exists($pythonExec)) { exit("The python executable '$pythonExec' does not exist!"); } if (!is_executable($pythonExec)) { exit(("The python executable '$pythonExec' is not executable!")); } if (!file_exists($pythonScript)) { exit("The python script file '$pythonScript' does not exist!"); } // Execute it, and redirect STDERR to STDOUT so we can see error messages as $ exec("echo 'heslo' | sudo -S python \"$pythonExec\"\"$pythonScript\" 2>&1", $output); // Show the output of the script print_r($output[0]); } else { echo "error"; // echo $username; } ?>
[/notice]
12 pingů
Přeskočit k formuláři pro komentář ↓