Websocket

Frage: Wie kann ich mir vom RaspberryZ aus, die aktuelle GPS Position und die aktuelle Zeit holen?

Antwort: Kaufe ein GPS-Modul und ein RTC-Modul

Ich habe aber doch (fast immer) ein Smartphone, das doch genau diese Informationen bietet!?

Baue ich doch eine Verbindung zwischen den beiden auf, und hole mir die Daten vom Handy.

Erster Versuch - Websocket Clients

Mit dieser Seite https://en.proft.me/2018/05/10/quick-guide-websocket-communication-android/ habe ich für Android den Websocket-Client implementiert. Die IP des Servers (mein iMac) musste ich noch korrigieren. Als nächstes kam dann die GPS-Abfrage im Android dran. Dort war die Hürde, die Erlaubnis einzuholen (ActivityCompat.requestPermissions), wenn es auch nur eine Zeile Code ist. Der vorgeschlagene Code hatte ein Return am Ende, dass man rausnehmen muss. Sonst muss man die App zwei mal starten.

Auf dieser Seite https://en.proft.me/2014/05/16/realtime-web-application-tornado-and-websocket/ steht der Servercode. Den habe ich am iMac installiert und gestartet. index.html brauchte ich nicht und beim Versuch hat ihm der Pfad /ws/ gefehlt. Keine Ahnung, wo der hin muss. Im Directory, wo der Server ist, jedenfalls nicht.

Jetzt muss ich mir nur überlegen, wer de Server und der Client werden soll…

Nächster Versuch - Websocket Server

Mein Problem war, dass ich vom macOS nicht an den Emulierten Server dran gekommen bin. Bin fast verzweifelt. Habe diverse Server ausprobiert, von ganz alten, bis ganz komplizierten, da ich dachte, es liegt am Server. Nein, es lag an der Verbindung. Auch das auf der Seite https://developer.android.com/studio/run/emulator-networking vorgeschlagene forwarding über redir hat nicht funktioniert. Dann hat Apple auch noch den Port 5000 für sich beansprucht, und wieso auch immer, ging es mit Port 8000 auch nicht. Erst die einfache Zeile brachte erfolg

adb forward tcp:9000 tcp:6000

Im Python client example script von hier: https://github.com/websocket-client/websocket-client mit dem

pip3 install websocket-client

und dem eingetragenen URL:

"ws://127.0.0.1:9000/"

war ich erfolgreich. Ok, dann kanne s in den nächsten Tagen weiter gehen.

import websocket
if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.create_connection("ws://127.0.0.1:9000/")
    ws.recv()
    print("Sending 'Hello, World'...")
    ws.send("Hello, World")
    print("Sent")
    print("Receiving...")
    result = ws.recv()
    print("Received '%s'" % result)
    ws.close()

oder

import asyncio
import websockets

async def test():

    async with websockets.connect('ws://127.0.0.1:9000/') as websocket:

        await websocket.send("hello")

        response = await websocket.recv()
        print(response)

asyncio.get_event_loop().run_until_complete(test())

GPS Wifi und Server-Websocket

Ich habe eine Hauptaktivität und Location sowie Wifi als eigene Klassen. Von der Hauptaktivität rufe ich alles auf. Problem ist, dass das ja immer seine Zeit braucht, bis die Daten gesammelt sind. Da muss ich noch googlen. AKtuell schreibt die eine Klasse direkt in ein Feld und die andere setzt ein Flag, das ich abfrage um neue Daten zu holen.

GPS Abfragen im Hintergrund brauchen eine eigene Berechtigung!

WiFi-Scan im Hintergrund geht nur alle zwei Minuten, was inakzeptabel ist. Alternativ werde ich einen ForgroundService bauen, in den das reinkommt. Im Vordergund kann mal 4 Abfragen in 2 Minuten machen. Das passt.

Der Server läuft und wenn die App im Vordergrund ist, werden auch Daten übermittelt. Jetzt kann ich mir überlegen, ob als nächstes die Anbindung an den Raspberry oder die verschönerung der App dran ist.

https://stackoverflow.com/questions/33229869/get-json-data-from-url-using-android

app am handy, um raspberryZero zu steuern

https://stackoverflow.com/questions/28099656/websocket-server-on-android https://github.com/koush/AndroidAsync

Zwei wifi, einer als ap, der andere zum internet:

https://raspberrypi.stackexchange.com/questions/83486/simultaneously-connect-to-a-wifi-network-and-create-a-wifi-ap

Zeroconf

Mein Android WebsocketServer funktioniert jetzt. Bei XIAOMI Redmi gibt es eine Energiesparmodus, der den Prozess im Hintergrund schlafen legt. Weder Background_Location noch ForegroundService haben daran was geändert. Erst wenn man der App in den Einstellungen sagt, dass kein Energiesparen nötig ist, klappt alles wie gewünscht - mindestens 2 verlorene Tage. Falls man auf API 30 ist und die Energiesparfunktion eingeschaltet ist, wird gleich der richtige Intent geöffnet. Vorher nur die Übersicht der Apps und man muss es selber machen.

Dann noch länger mit jmdns-discovery rumprobiert, bis ich gefunden habe, dass Android jetzt sowas mitbringt mittels NSD. Braucht man da noch das Multicast? Nachdem das eingebaut war, noch schnell zeroconf am raspberry mittels Python installiert (s.u.). Jetzt findet der raspberry den Server, verbindet sich und legt los.

pip3 install zeroconf
from zeroconf import ServiceBrowser, Zeroconf


class MyListener:

    def remove_service(self, zeroconf, type, name):
        print("Service %s removed" % (name,))

    def add_service(self, zeroconf, type, name):
        info = zeroconf.get_service_info(type, name)
        print("Service %s added, service info: %s" % (name, info))


zeroconf = Zeroconf()
listener = MyListener()
browser = ServiceBrowser(zeroconf, "_http._tcp.local.", listener)
try:
    input("Press enter to exit...\n\n")
finally:
    zeroconf.close()

Stand Februar 2022