domenica 4 agosto 2013

Come far parlare il Raspberry Pi tramite php


Qualche tempo fa ho cominciato a divertirmi con il mio Raspberry Pi. Una delle prime cose che ho voluto fare è stata quella di far parlare il raspPi attraverso il sintetizzatore vocale. In che modo? Con una pagina php richiamata dall'utente.
Per realizzare il tutto, basta installare un webserver (lighttpd nel mio caso) con interprete php5 e il sintetizzatore vocale (espeak), configurando i diritti della www-root:

sudo apt-get install lighttpd
sudo apt-get install php5-common php5-cgi php5
sudo lighty-enable-mod fastcgi-php
sudo service lighttpd force-reload
sudo chown www-data:www-data /var/www
sudo chmod 775 /var/www
sudo apt-get install espeak
Facciamo una prova, poi eseguiamo visudo per dare i diritti di esecuzione all'utente www-data attraverso visudo
espeak -vit "Prova di testing"
sudo visudo
Lo so che è un incredibile errore di sicurezza, ma tanto il mio RaspberryPi sta solo in casa e quindi per facilità ho abilitato l'utente a poter eseguire con sudo e senza password qualsiasi comando. Aggiungiamo quindi la seguente riga nel visudo
www-data ALL=(ALL) NOPASSWD: ALL
Creiamo una pagina php sotto la cartella /var/www con il seguente contenuto:
<?php 
echo exec(" sudo /usr/bin/espeak -vit \"Questo messaggio viene riprodotto ogni volta che si visita la pagina da un browser\"", $out, $out2);
?>
Questo ovviamente apre uno scenario fantastico relativo alla domotica :-)

sabato 3 agosto 2013

C# - programma per l'update automatico degli eseguibili

Ho creato qualche tempo fa un piccolo e semplice programma in C# che si occupa di fare da "loader" per le applicazioni. Ad esempio ipotizziamo di avere una applicazione HelloWorld; il loader (un altro eseguibile) si comporterà come segue:
  • appena viene eseguito, controlla sul server (tramite un percorso di rete windows) se la versione dell'applicazione HelloWorld presente in locale sia meno recente di quella sul server. Se così è, scarica la versione più recente dal percorso (è possibile specificare dalla configurazione se aggiornare una intera cartella o solo l'eseguibile).
  • una volta finito il primo punto, esegue l'applicazione HelloWorld che si è copiato in locale.
Tutto il comportamento è racchiuso dentro un BackgroundWorker (un semplice oggetto per gestire un thread in C#). Vediamo nel dettaglio il comportamento:
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                FileInfo fi1 = 
                         new FileInfo(Properties.Settings.Default.eseguibileRemoto);
                FileInfo fi2 = 
                         new FileInfo(Properties.Settings.Default.eseguibileLocale);
                //Se la directory locale non esiste, la creo
                if (!(Directory.Exists(Properties.Settings.Default.cartellaLocale)))
                {
                    Directory.CreateDirectory(Properties.Settings.Default.cartellaLocale);
                }
                //Controllo che il timestamp di modifica del file eseguibile remoto sia
                //più recente di quello locale
                if (fi1.LastWriteTime.Ticks > fi2.LastWriteTime.Ticks)
                {
                    if (Properties.Settings.Default.copiaTutto)
                    {
                        //Devo copiare tutto il contenuto della directory in locale
                        foreach (string fileTrovato in Directory.GetFiles(Properties.Settings.Default.cartellaRemota))
                        {
                            FileInfo FTEMP = new FileInfo(fileTrovato);
                            //Copio il file remoto in locale
                            File.Copy(fileTrovato, Properties.Settings.Default.cartellaLocale + FTEMP.Name, true);
                        }
                    }
                    else
                    {
                        //Procedura per la copia solo di alcuni files (ad esempio, eseguibili Visual Fox)
                        foreach (string nomeFile in Properties.Settings.Default.copiaSoloQuestiFiles)
                        {
                            FileInfo FTEMP = new FileInfo(nomeFile);
                            File.Copy(Properties.Settings.Default.cartellaRemota + nomeFile, Properties.Settings.Default.cartellaLocale + nomeFile, true);
                        }
                    }

                }
   
            }
            catch (Exception ex) { }
        }
Appena terminato il lavoro (RunWorkerCompleted), l'applicazione verrà eseguita e il loader verrà terminato:

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //Al termine della copia, mi preparo ad eseguire il programma
            ProcessStartInfo p = new ProcessStartInfo();
            p.FileName = Properties.Settings.Default.eseguibileLocale;
            p.Arguments = Properties.Settings.Default.parametri;
            //Se è impostato "eseguiDa" (ad esempio per JT) eseguo il programma dal percorso impostato
            if (Properties.Settings.Default.eseguiDa.Length > 0) p.WorkingDirectory = Properties.Settings.Default.eseguiDa;
            //Altrimenti uso la cartella locale
            else p.WorkingDirectory = Properties.Settings.Default.cartellaLocale;
            try
            {
                //Eseguo il programma
                Process.Start(p);
            }
            catch (Exception exep)
            {
                MessageBox.Show("Impossibile avviare il programma richiesto\r\n" + exep.Message);
            }
            Application.Exit();
        }
Le impostazioni possibili nella configurazione del loader sono le seguenti:


Il codice sorgente può essere liberamente scaricabile da Github (qui il link del progetto sul mio sito personale)