Cześć
Postanowiłem podzielić się sposobem na odczyt lokalizacji telefonów za pomocą usługi lokalizacyjnej Google. Oczywiście można to zrealizować za pomocą np. GPSTracker Binding, ale wykorzystanie usług Google ma niezaprzeczalne zalety:
- nie wymaga instalacji żadnego oprogramowania (usługi Google są standardowo w telefonach z Androidem)
- nie powoduje zwiekszonego zużycia baterii
- lokalizuje telefony dzieci, jeśli mają zainstalowanego FamilyLinka
- lokalizuje telefony, na których udostepniono lokalizację do podłączonego konta
Inspirowałem się tym wpisem https://community.openhab.org/t/google-family-location-sharing-in-openhab-via-python-and-mqtt/.
Jako, że od jakiegoś czasu jestem fanem kontenerów zatem zaczynamy od instalacji dockera
curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo usermod -aG docker $USER
Ostatnia komenda pozwoli używać dockera bez używania sudo. Aby tak się stało należy ponownie zalogować się do konsoli.
Kolejnym krokiem jest pozyskanie ciastka:
- instalujemy dodatek do Firefoxa do zapisywania ciastek (np. https://addons.mozilla.org/en-US/firefox/addon/export-cookies-txt/ )
- otwieramy nowe okno prywatne i wpisujemy adres https://maps.google.com/
- logujemy się na konto google
- klikamy ikone dodatku “Export cookies”, a następnie “All Domains” i zapisujemy ciastko.
Następnie tworzymy folder, w którym umieścimy konfigurację dockera i ciastko, które pozwoli uzyskać dostęp do konta Google.
mkdir -p google_location cd google_location wget https://github.com/kamiKAC/google-location/raw/main/compose.yaml
Do folderu google_location wrzucamy pobrane z przegladąrki ciastko jako googlemaps_cookie.txt (jeśli zapiszemy pod inną nazwą, to trzeba potem uwzględnić to w pliku compose.yaml).
Otwieramy plik compose.yaml edytorem i konfigurujemy
nano compose.yaml
Niezbędne jest wpisanie naszego emaila. Jeśli nasz serwer MQTT znajduje się na tym samym hoście, co nasz kontener dockera, działa na domyślnym porcie 1883 i nie wymaga autentykacji, to można pozostawić wartości domyślne w tym pliku.
Po zapisaniu pliku, uruchamiamy kontener (domyślnie kontener jest tak skonfigurowany, że uruchamia się automatycznie po uruchomieniu system operacyjnego, zatem nie ma potrzeby używania do tego żadnych skryptów).
docker compose up -d
Jeśli nie popełniliśmy błędu to kontener powinien działać, logi widać po wydaniu komendy
docker logs -f google_location-google-location-1
Zatrzymujemy (niszczymy) kontener dockera komendą
docker compose down
Aby odczytać dane lokalizacji dodajemy do mqtt.things (przyjmujemy, że mamy już skonfigurowany bridge o nazwie mosquitto)
Thing mqtt:topic:googlelocation_User1 "Google Location: User1" (mqtt:broker:mosquitto){ Channels: Type number : Accuracy [ stateTopic="googlelocation/User1/accuracy"] Type string : Address [ stateTopic="googlelocation/User1/address"] Type number : Battery_Level [ stateTopic="googlelocation/User1/battery_level"] Type contact : Charging [ stateTopic="googlelocation/User1/charging", on="True", off="False"] Type string : Country_Code [ stateTopic="googlelocation/User1/country_code"] Type datetime : Timestamp [ stateTopic="googlelocation/User1/datetime", transformationPattern="JS:googletimestamp.js"] Type string : Full_Name [ stateTopic="googlelocation/User1/full_name"] Type string : Id_number [ stateTopic="googlelocation/User1/id"] Type number : Latitude [ stateTopic="googlelocation/User1/latitude"] Type number : Longitude [ stateTopic="googlelocation/User1/longitude"] Type string : Photo_URL [ stateTopic="googlelocation/User1/picture_url"] }
Plik googletimestamp.js (folder transform)
(function(timestamp){ return timestamp.substring(0,10) + 'T' + timestamp.substring(11,24) + timestamp.substring(26,29) + timestamp.substring(30,32) })(input)
Plik location.items
Number GPSLocation_User1_Accuracy "Accuracy" (Logged) {channel="mqtt:topic:googlelocation_User1:Accuracy"} String GPSLocation_User1_Address "Address" (Logged) {channel="mqtt:topic:googlelocation_User1:Address"} Number:Dimensionless GPSLocation_User1_Battery_Level "Battery Level [%d%%]" (Logged) {channel="mqtt:topic:googlelocation_User1:Battery_Level"} Contact GPSLocation_User1_Charging "Charging" (Logged) {channel="mqtt:topic:googlelocation_User1:Charging"} String GPSLocation_User1_Country_Code "Country Code" (Logged) {channel="mqtt:topic:googlelocation_User1:Country_Code"} DateTime GPSLocation_User1_Timestamp "Timestamp [%1$tH:%1$tM %1$td %1$tb %1$ty]" (Logged) {channel="mqtt:topic:googlelocation_User1:Timestamp"} String GPSLocation_User1_Full_Name "Full Name" (Logged) {channel="mqtt:topic:googlelocation_User1:Full_Name"} String GPSLocation_User1_Id_number "ID Number" (Logged) {channel="mqtt:topic:googlelocation_User1:Id_number"} Number GPSLocation_User1_Latitude "Latitude" (Logged) {channel="mqtt:topic:googlelocation_User1:Latitude"} Number GPSLocation_User1_Longitude "Longitude" (Logged) {channel="mqtt:topic:googlelocation_User1:Longitude"} Location GPSLocation_User1_Location "Location" (Logged) String GPSLocation_User1_Photo_URL "Photo URL" (Logged) {channel="mqtt:topic:googlelocation_Weronika:Photo_URL"}
Plik location.rules
rule "Position - User1" when Item GPSLocation_User1_Latitude changed or Item GPSLocation_User1_Longitude changed then if (GPSLocation_User1_Latitude.state !== "UNDEF" && GPSLocation_User1_Longitude.state !== "UNDEF") { GPSLocation_User1_Location.postUpdate(new PointType(GPSLocation_User1_Latitude.state.toString + "," + GPSLocation_User1_Longitude.state.toString)) } else { GPSLocation_User1_Location.postUpdate("-") } end
Mam nadzieję, że komus się przyda - ja korzystam od kilku miesięcy i działa bardzo dobrze 🙂
UPDATE:
Zaktualizowałem program i nie potrzeba już transform oraz rules.
mqtt.things
Thing mqtt:topic:googlelocation_User1 "Google Location: User1" (mqtt:broker:mosquitto){ Channels: Type number : Accuracy [ stateTopic="googlelocation/User1/accuracy"] Type string : Address [ stateTopic="googlelocation/User1/address"] Type number : Battery_Level [ stateTopic="googlelocation/User1/battery_level"] Type contact : Charging [ stateTopic="googlelocation/User1/charging", on="True", off="False"] Type string : Country_Code [ stateTopic="googlelocation/User1/country_code"] Type datetime : Timestamp [ stateTopic="googlelocation/User1/datetime_iso8061"] Type string : Full_Name [ stateTopic="googlelocation/User1/full_name"] Type string : Id_number [ stateTopic="googlelocation/User1/id"] Type number : Latitude [ stateTopic="googlelocation/User1/latitude"] Type number : Longitude [ stateTopic="googlelocation/User1/longitude"] Type string : Photo_URL [ stateTopic="googlelocation/User1/picture_url"] Type string : Coordinates [ stateTopic="googlelocation/User1/coordinates"] }
location.items
Number GPSLocation_User1_Accuracy "Accuracy" (Logged) {channel="mqtt:topic:googlelocation_User1:Accuracy"} String GPSLocation_User1_Address "Address" (Logged) {channel="mqtt:topic:googlelocation_User1:Address"} Number:Dimensionless GPSLocation_User1_Battery_Level "Battery Level [%d%%]" (Logged) {channel="mqtt:topic:googlelocation_User1:Battery_Level"} Contact GPSLocation_User1_Charging "Charging" (Logged) {channel="mqtt:topic:googlelocation_User1:Charging"} String GPSLocation_User1_Country_Code "Country Code" (Logged) {channel="mqtt:topic:googlelocation_User1:Country_Code"} DateTime GPSLocation_User1_Timestamp "Timestamp [%1$tH:%1$tM %1$td %1$tb %1$ty]" (Logged) {channel="mqtt:topic:googlelocation_User1:Timestamp"} String GPSLocation_User1_Full_Name "Full Name" (Logged) {channel="mqtt:topic:googlelocation_User1:Full_Name"} String GPSLocation_User1_Id_number "ID Number" (Logged) {channel="mqtt:topic:googlelocation_User1:Id_number"} Number GPSLocation_User1_Latitude "Latitude" (Logged) {channel="mqtt:topic:googlelocation_User1:Latitude"} Number GPSLocation_User1_Longitude "Longitude" (Logged) {channel="mqtt:topic:googlelocation_User1:Longitude"} Location GPSLocation_User1_Location "Location" (Logged) {channel="mqtt:topic:googlelocation_User1:Coordinates"} String GPSLocation_User1_Photo_URL "Photo URL" (Logged) {channel="mqtt:topic:googlelocation_User1:Photo_URL"}
Pozdrawiam i życzę udanego śledzenia 😉
Pojawiło się pytanie:
Jak zainstalować obraz dockerowy na QNAPie (model z Container Station)?
Wszystkie parametry, łącznie z nazwą obrazu są podane w compose.yaml podanym w linku w poradniku (uruchomienie z docker compose).
W dokumentacji w repo jest też pokazane jak uruchomić obraz bez docker compose, więc można stamtąd wziąć konfigurację.
Obraz jest dostępny na DockerHubie.
W Container Station docker compose występuje jako Container Station Application, więc można wrzucić tego YAMLa i powinno też działać :
https://www.qnap.com/en/how-to/tutorial/article/how-to-use-container-station-3
Co ile następuję odświeżenie pozycji czy da się zmienić częstotliwość?
@szpila86 Domyślnie jest to 60s i można zmienić poprzez zmienną środowiskową INTERVAL (uzupełniłem dokumentacje w repo).
Nie wiem tylko czy to zwiększy częstotliwość odczytu pozycji. Czy to nie jest tak, że usługi Google same decydują, kiedy nastąpi przesłanie aktualnej pozycji telefonu, a my tylko mamy wpływ na to, jak często odczytujemy pozycję z usługi Google.
Tak czułem że pałeczka leży po stronie google.
Na osi czasu jest trasa z całego dnia jakby odczyt był co metr, a na podglądzie w OH już tak nie jest.