Android Steuerung per Webschnittstelle

Hallo,
ich habe hier mehrere Odys Next Android Tablets und nutze diese z.B. zum Ausgeben von Hinweisen per Sprachausgabe.

Bis jetzt habe ich terRemote und Tasker benutzt, so wie hier beschrieben. Leider ist die Konfiguration doch etwas mühselig, daher habe ich mir schon überlegt ob ich mir selbst etwas in Android programmiere. Allerdings ist Java nicht so meine Welt und nach jeder Änderung muss ich ja auch erst umständlich die apk verteilen.

Da ich auf meinem Raspberry Pi schon erfolgreich einen kompletten Webserver per Python mit einem Framework betrieben habe, wollte ich mal sehen wie weit Python auf Android ist. Um es kurz zu machen: sehr weit und sehr beeindruckend.

Los gehts:

  • Als erstes braucht man Python. Dies gibt es schon fix und fertig als „qpython“ im Playstore und kann bedenkenlos installiert werden

  • Nach dem Start am besten die Einstellungen aufrufen. Dort findet man einen fertig konfigurierten FTP-Server, den man einfach startet (eventuell Username/Passwort ändern). Danach kann man bequem vom PC per FTP-Client (nutze MobaXterm) programmieren

  • Auf der Hauptseite kommt man durch wischen auf die zweite Seite und sollte erstmal Package Index starten. Dort QPython Libraries wählen und das Paket Wsgiref installieren

  • Nun auf dem PC von der Seite http://bottlepy.org/ die bottle.py runterladen und per FTP in das scripts-Verzeichnis schieben

  • eine neue Datei webtest.py erzeugen und folgendes Beispiel eintragen:


from bottle import route, run, template
import androidhelper

droid = androidhelper.Android()

@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)

@route('/say/<text>')
def say(text):
    droid.ttsSpeak(text)
    return 'ok'

@route('/msgbox/<text>')
def dlg(text):
    droid.dialogCreateAlert(
    'Hinweis',
    text)
    droid.dialogSetPositiveButtonText('Yes')
    droid.dialogSetNegativeButtonText('No')
    droid.dialogShow()
    response = droid.dialogGetResponse().result
    droid.dialogDismiss()
    return 'ok: ' % response
    
run(host='0.0.0.0', port=8080)

Wenn man es startet (per My QPython), sollte man auf dem PC per Browser mit :8080/hello/world das hello world angezeigt bekommen.

Nun kann man das Tablet per IPS Sprechen lassen:


file_get_contents('http://<IP>:8080/say/' . rawurlencode('hallo ich bin ein hinweis'));

Oder ein Hinweisdialog anzeigen:


file_get_contents('http://192.168.0.43:8080/msgbox/' . rawurlencode('hier der hinweis'));

Hinweis:
wenn man per FTP was ändert, dann muss man das Script zwei mal ausführen. Am besten immer die Ausgabe von der Notification prüfen ob der Server wirklich läuft.

Bye,
Norman

Kannst du auch das tablet von außen aufwecken ? Ergo Screen_ON ?

Gesendet von meinem iPad mit Tapatalk

Geht hier per „droid.wakeLockAcquireBright()“. Eine gute Referenz findet man hier.

Für das einfache Testen ist folgendes ganz nützlich:


@route('/eval/<text>')
def gefahr(text):
    eval(text)
    return 'ok'

Unter IPS geht dann:


file_get_contents('http://<IP>:8080/eval/' . rawurlencode("droid.wakeLockAcquireBright()"))

Klingt nach einer interessanten Alternative !

Dennoch ein ziemlich heftiger Aufriss für eine - augenscheinlich - banale Funktion.
Kenn jemand einen anderen Workarround, der ein dauerhaft an Strom und WLAN hängendes Android 4.2 Tablet den Screen aufwecken bzw. einschlafen lässt ?

So, habe noch etwas experimentiert

Webserver:
Ich brauche eigentlich kein Framework mit Threads, Templates, Sessions, DB-Zugriff und diesem ganzen kram, sondern ein einfachen Server bei dem ich die URL parsen kann. Nun verwende ich BaseHTTPServer direkt von der Python-Lib, so dass man Wsgiref und bottle.py sparen kann.

Meine webserver.py:


from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
import urllib
import androidhelper

droid = androidhelper.Android()

runserver = True

class MyHTTPRequestHandler(BaseHTTPRequestHandler):
    
  # GET Kommando
  def do_GET(self):
    global runserver
    # URL encodieren und aufsplitten in Kommando und Parameter
    list = urllib.unquote(self.path).decode('utf8').split(' ', 1)
    # Kommando ohne Slash
    cmd = list[0][1:]
    params = list[1] 
    # loggen
    print(cmd + ": " + params)
    
    # Beenden-Kommando
    if cmd == "quit":
      runserver = False
      
    # Funktion WC_<Kommando> aufrufen
    globals()["WC_" + cmd](self, params)

  def send(self, text):
    self.send_response(200)
    self.send_header('Content-type','text-html')
    self.end_headers()
    self.wfile.write(text)


def WC_say(handler, params):
  droid.ttsSpeak(params)
  handler.send("Sage " + params)
     
     
           	 
def run():
  print('Starte Server')
  server_address = ('0.0.0.0', 8080)
  httpd = HTTPServer(server_address, MyHTTPRequestHandler)
  while runserver:
    httpd.handle_request()
  print('Stoppe Server')
    
if __name__ == '__main__':
  run()

Der Aufruf erfolgt später wie üblich:


file_get_contents('http://<IP>:8080/' . rawurlencode('<Kommando> <Parameter>'))

Für jedes Kommando kann man dann einfach eine WC_-Funktion implementieren.

IOS:
Ich bekam eine Anfrage, ob so etwas auch mit einem iPad möglich wäre. Mein Wissensstand war eigentlich, dass Apple eigentlich kein Scripting auf IOS erlaubt, aber das ist wohl inzwischen möglich. Für IOS gibt es Pythonista (Pythonista for iOS), welches auch eine BaseHTTPServer Lib mitbringt.

Eine Spachausgabe geht damit wohl auch (mangels iPad nicht getestet):


import speech
...
def WC_say(handler, params):
  speech.say(params)
  handler.send("Sage " + params)

Hallo normancz,
danke für die Idee und die Scripte. Da ich meine Androids bisher noch nicht gesteuert habe find ich die Lösung einen guten Start für mich.
Habe qpython auf meinem Acer A210 installiert. Der FTP-Server ist gestartet, user und PW geändert. Unter „scripts“ hab ich eine Datei „webserver.py“ angelegt und den Inhalt Deines „webserver.py“ aus Post 5 reinkopiert.
In IPS hab ich ein Script mit folgendem Inhalt angelegt:


<?
// sprachausgabe
//file_get_contents('http://AcerA210-01:8080/say/' . rawurlencode('hallo ich bin ein hinweis'));

//Hinweisdialog anzeigen
file_get_contents('http://AcerA210-01:8080/msgbox/' . rawurlencode('hier der hinweis'));

?>

Als Ausgabe bekomm ich folgenden Fehler:


IPS-Err-PHP                  2014-01-25 19:08:26.562  Warning: file_get_contents(http://AcerA210-01:8080/msgbox/hier%20der%20hinweis): failed to open stream: Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte.         Error in Script D:\IPS\scripts\13723.ips.php on Line 6    133 in IPSLibrary\app\core\IPSLogger\IPSLogger.inc.php (call IPSLogger_Out)     37 in IPSLibrary\app\core\IPSLogger\IPSLogger_PhpErrorHandler.inc.php (call IPSLogger_Err)        in IPSLogger_PhpErrorHandler      6 in 13723.ips.php (call file_get_contents)

Warning:  file_get_contents(http://AcerA210-01:8080/msgbox/hier%20der%20hinweis): failed to open stream: Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte.
 in D:\IPS\scripts\13723.ips.php on line 6

Muss ich noch irgend wo Zugangsdaten mitgeben? oder am Tablet noch irgend was „freischalten“?

Das zweite Script ohne bottle.py? Dort muss ein Leerzeichen anstatt eines Slash hinter dem Kommando stehen, also z.B.:


file_get_contents('http://AcerA210-01:8080/say ' . rawurlencode('hallo ich bin ein hinweis'));

Es gibt zudem noch Probleme mit Umlauten. Beim Testen auf dem PC konnte ich diese einfach mit den „decode(‚utf8‘)“ Zusatz decodieren, aber auf dem Android Gerät funktioniert das leider nicht.

Hallo normancz,

So weit kommts gar nicht.

failed to open stream: Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte.

Noch ne Idee?

Was wird denn bei der Ausgabe (auf diese Notify Klicken) angezeigt?

Hallo normancz,

Was wird denn bei der Ausgabe (auf diese Notify Klicken) angezeigt?

versteh ich nicht. Hab das Script in der Console ausgeführt. Mit dem Ergebnis aus Post 6 und 8.

Kriegs auch nicht hin.

Wie bekomme ich den HttpBaseServer mit drauf ? Finde nur Source Codes. In ein .py Script schreiben und abspeichern ? Will irgendwie auch nicht.

Die HttpBaseServer-Lib ist bei der QPython app dabei. Einfach die webserver.py per ftp in den scripts Ordner hochladen und dann starten. Die IP sollte natürlich fix eingestellt sein und die Datei als ASCII Format mit Unix-LF statt CRLF Zeilenumbruch vorliegen.

Wenn man in der Notify-bar auf das QPython-symbol klickt, kann man sich die Ausgabe anzeigen lassen und dort müsste ein „Starte Server“ stehen. Per Browser sollte nun ein „http://<IP-Adresse>:8080/say huhu“ den Androiden sprechen lassen und ein „sage huhu“ zurückliefern.

Ich bin raus. Mir zu aufregend :slight_smile:

Gesendet von meinem iPad mit Tapatalk

Hallo normancz,

ich hab noch nicht aufgegeben. Habs jetzt so weit hinbekommen, dass ich via:
192.168.178.59:8080/say „test“
eine Sprachausgabe auf dem Tablet bekomme. „msgbox“ funktioniert auf diesem Weg allerdings nicht.

Auch der Aufruf via IPS-Script funktioniert nicht.
„failed to open stream: HTTP request failed! <head>“

Hab die webserver.py mit dem notepad++ unter Win7 erstellt und mit utf8 codiert. Ist das so OK?

Wie bekomm ich das jetzt via IPS-Script ans laufen?

@roadsterhh: QPython ist noch ein wenig zickig, daher habe ich den Webkram auch direkt mit Python auf dem PC getestet. Am Wochenende werde ich mich nochmal richtig damit befassen.

@wolfgang: für eine einfache Messagebox reicht z.B. folgender Codeschnipsel in der webserver.py:


def WC_dialog(handler, params):
  droid.dialogCreateAlert('Hinweis', params)
  droid.dialogSetPositiveButtonText('Ok')
  droid.dialogSetNegativeButtonText('Abbruch')  
  droid.dialogShow()
  response = droid.dialogGetResponse()
  droid.dialogDismiss()
  handler.send(response)

Der Aufruf erfolgt dann so:


echo file_get_contents('http://<IP>:8080/' . rawurlencode('dialog hier bin ich'))  

Moinsen,
von IPS aus ging’s bei mir auch nicht! Liegt an „file_get_contents“. Hier der Ersatzfunktion:
-Joe


<?
$url = ('http://<ip-adresse>:8080/') .rawurlencode('say ' . ("hallo hier bin ich"));
print($url)."
";
//$content = file_get_contents($url);
//print $content;



$curl_handle=curl_init();
curl_setopt($curl_handle, CURLOPT_URL,$url);
curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'IP-Symcon');
$query = curl_exec($curl_handle);
print $query;
curl_close($curl_handle);

?>

Hallo!
Ich habe zwar noch nicht angefangen mit deinem Vorschlag zu experimentieren finde den Ansatz aber sehr vielversprechend. Ich würde allerdings noch eine Funktion benötigen, die folgendes macht:
Ich übergebe per http call einen link auf ein MP3-File und die Sekunden, für wie lange dieser MP3 File am Androiden abgespielt werden soll (ist eine Art Mailboxfunktion die ich in PHP programmiert habe - man kann damit dem Haus eine Nachricht mailen die einerseits einen gesprochenen Text hat der dann per TTS abgespielt werden soll, dem Mail kann aber auch ein MP3 File mitgegeben werden, welches eine Textnachricht enthält; wenn dann die Haustür aufgeht, wírd dieser Mailboxtext abgespielt…).
Beispiel-Calls:
http://192.168.88.220:8080/mp3=http://192.168.88.98/message.mp3&seconds=10
oder ohne Sekunden, dann wird das gesamte MP3 file abgespielt
http://192.168.88.220:8080/mp3=http://192.168.88.98/message.mp3

Wie wäre das in Phyton zu realisieren?

Danke schon mal im Voraus
Martin

Also bei mir klappt das mit der Sprachausgabe via Phyton (die einfache Variante) ganz gut.

Nur der Wake up funktioniert nicht.

Ich habe mir ein


def WC_wakeup(handler, params):
  droid.wakeLockAcquireBright()
  handler.send("Wake Up angefordert")

eingebaut, aber ein „http://<IP>/wakeup 1“ ruft das coding zwar auf, aber es passiert nichts.

Ideen?

Zudem: Wie startet man QPyhton + ein Skript beim booten?

ich hab einen HP Slate 21 und kann nach der Installation den FTP Server nicht starten. Jemand eine Idee woran das liegen kann?

Gruß Stephan