├── LICENSE ├── README.md ├── ambient ├── ambient-widgets ├── ambient.d └── trains │ ├── AT_OEBB.fish │ ├── CZ_CD.fish │ ├── DE_ICE.fish │ ├── EU_Eurostar.fish │ └── _icomera.fish ├── bitbar └── ambient.60s.sh ├── functions.d ├── ambient_get_ssid.fish ├── ambient_is_ssid.fish └── ambient_resolve4.fish ├── lib ├── _dispatch_ambient.fish └── _dispatch_widgets.fish └── widgets.d └── trains ├── AT_OEBB.fish ├── CZ_CD.fish ├── DE_ICE.fish ├── EU_Eurostar.fish └── _icomera.fish /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ambient 2 | ======== 3 | 4 | This is a script which captures ambient information available on certain public networks, such as the route, speed and delay information available on: 5 | - German ICE trains 6 | - Eurostar 7 | - Austrian RailJet trains 8 | 9 | If you spot a network with some tidbits of information available, please open a PR to add it! 10 | 11 | Requirements 12 | ------------ 13 | 14 | The set of dependencies is intentionally kept small: 15 | 16 | - `fish` (the shell) 17 | - `iw` (to check what network you're on) 18 | - `jq` 19 | - The POSIX standard tools, such as `grep` and `sed` (On macOS, you'll need to install the GNU coreutils with `brew install coreutils`) 20 | 21 | Usage 22 | ----- 23 | 24 | If you just run `ambient` on its own, it'll output all the data it can find in `KEY=VALUE` format, such that it can be given to `env`. 25 | 26 | As a convenience, running eg. `ambient myscript.py` will run the given command with all of this data in the environment. 27 | 28 | Example output (abbreviated): 29 | 30 | ``` 31 | $ ./ambient 32 | AMBIENT_DE_ICE_SPEED=158 33 | AMBIENT_DE_ICE_SPEED_UNIT=km/h 34 | AMBIENT_DE_ICE_TZN=Tz4652 35 | AMBIENT_DE_ICE_SERIES=406 36 | AMBIENT_DE_ICE_WAGON_CLASS=SECOND 37 | AMBIENT_DE_ICE_TRAIN_TYPE=ICE 38 | AMBIENT_DE_ICE_TRIP_DATE=2020-01-02 39 | AMBIENT_DE_ICE_VZN=14 40 | AMBIENT_DE_ICE_STOP_FIRST=Frankfurt (Main) Hbf 41 | AMBIENT_DE_ICE_STOP_FIRST_DEPART_SCHEDULED=2020-01-02T13:29:00Z 42 | AMBIENT_DE_ICE_STOP_FIRST_DEPART_ACTUAL=2020-01-02T13:54:00Z 43 | AMBIENT_DE_ICE_STOP_FIRST_DEPART_DELAY=+25 44 | AMBIENT_DE_ICE_STOP_LAST=Bruxelles Midi 45 | AMBIENT_DE_ICE_STOP_LAST_ARRIVE_SCHEDULED=2020-01-02T16:35:00Z 46 | AMBIENT_DE_ICE_STOP_LAST_ARRIVE_ACTUAL=2020-01-02T17:32:00Z 47 | AMBIENT_DE_ICE_STOP_LAST_ARRIVE_DELAY=+57 48 | AMBIENT_DE_ICE_STOP_NEXT=Bruxelles-Nord 49 | AMBIENT_DE_ICE_STOP_NEXT_DEPART_SCHEDULED=2020-01-02T16:28:00Z 50 | AMBIENT_DE_ICE_STOP_NEXT_DEPART_ACTUAL=2020-01-02T17:25:00Z 51 | AMBIENT_DE_ICE_STOP_NEXT_DEPART_DELAY=+57 52 | AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_SCHEDULED=2020-01-02T16:26:00Z 53 | AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_ACTUAL=2020-01-02T17:23:00Z 54 | AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_DELAY=+57 55 | ``` 56 | 57 | Running `ambient-widgets` will run the built-in widget scripts (WIP, uses Font Awesome): 58 | 59 | ``` 60 | $ ./ambient-widgets 61 |  Bruxelles-Nord 62 |  ICE-14 63 |  219 km/h 64 | ``` 65 | 66 | Status bar usage 67 | ---------------- 68 | 69 | Do you want to see how late your current train is, from the comfort of your status bar? Look no further! 70 | 71 | ### i3status-rs 72 | 73 | ``` 74 | [[block]] 75 | block = "custom" 76 | command = "/path/to/ambient/ambient-widgets | tr '\n' ' '" 77 | interval = 120 78 | hide_when_empty = true 79 | ``` 80 | 81 | ### awesomewm (+ vicious) 82 | 83 | Create a custom widget which calls the widget script, and replace all newlines with spaces. 84 | 85 | ``` 86 | myambien = wibox.widget.textbox() 87 | vicious.register(myambien, function(format, warg) 88 | local f = io.popen("echo -n ' '; " .. os.getenv("HOME") .. "/path/to/ambient/ambient-widgets") 89 | local out = f:read("*all") 90 | f:close() 91 | return { out:gsub('\n', ' ') } 92 | end, "$1", 31) 93 | ``` 94 | 95 | Remember to add it to your `wibox` list! Search for `mytextclock` with a default configuration. 96 | 97 | ### BitBar 98 | 99 | Link `bitbar/ambient.60s.sh` into your BitBar plugin directory. 100 | 101 | ``` 102 | ln -s $(pwd)/bitbar/ambient.60s.sh ~/.bitbar 103 | ``` 104 | 105 | You can put a file named `bitbar/plugins/ambient.json` in one of [the usual locations](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) (e.g. `~/.config`) to configure the plugin: 106 | 107 | - If `showIfEmpty` is false, the plugin will disappear entirely from your menu bar as long as you're not in a known network. Note that BitBar displays its own menu if none of the plugins are active. (Default: `true`) 108 | 109 | Why `fish`? Why not `bash` or `zsh`? 110 | ------------------------------------ 111 | 112 | First of all, this was written on a horribly delayed ICE train, and I happen to use `fish` as my daily driver. 113 | 114 | Second, it's quite fast and has a number of nice features like lazy-loaded functions, and semantics that make it harder to shoot yourself in the foot. 115 | 116 | If people want it migrated to `bash` or `zsh`, that's totally doable. 117 | -------------------------------------------------------------------------------- /ambient: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env fish 2 | 3 | # Change to the script's directory for now, it makes things easier. 4 | set -l ambient_path (dirname (status --current-filename)) 5 | cd $ambient_path 6 | 7 | # Accumulate non-empty KEY=VALUE pairs output from subscripts. 8 | for kv in (./lib/_dispatch_ambient.fish) 9 | if test -z "$kv" 10 | continue 11 | end 12 | set -a environment $kv 13 | end 14 | 15 | # If arguments are given, call it as a command, with ambient data in the environment. 16 | if [ (count $argv) -gt 0 ] 17 | env $environment $argv 18 | else 19 | for kv in $environment 20 | echo $kv 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /ambient-widgets: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env fish 2 | 3 | # Change to the script's directory for now, it makes things easier. 4 | set -l ambient_path (dirname (status --current-filename)) 5 | cd $ambient_path 6 | 7 | # Use ambient to run the widget dispatcher with data in the environment. 8 | ./ambient ./lib/_dispatch_widgets.fish 9 | -------------------------------------------------------------------------------- /ambient.d/trains/AT_OEBB.fish: -------------------------------------------------------------------------------- 1 | ambient_is_ssid "OEBB"; or exit 2 | 3 | curl -s https://railnet.oebb.at/assets/modules/fis/combined.json | jq -r '" 4 | AMBIENT_AT_OEBB_SITUATION=\(.operationalMessagesInfo.situation) 5 | AMBIENT_AT_OEBB_DELAY=\(.operationalMessagesInfo.delay) 6 | AMBIENT_AT_OEBB_SPEED=\(.operationalMessagesInfo.speed) 7 | AMBIENT_AT_OEBB_SPEED_UNIT=km/h 8 | AMBIENT_AT_OEBB_LATITUDE=\(.mapInfo.latitude) 9 | AMBIENT_AT_OEBB_LONGITUDE=\(.mapInfo.longitude) 10 | AMBIENT_AT_OEBB_ORIENTATION=\(.mapInfo.orientation) 11 | AMBIENT_AT_OEBB_SERVER_TIME=\(.operationalMessagesInfo.time | strptime("%s") | todate) 12 | AMBIENT_AT_OEBB_TRAIN_TYPE=\(.currentJourney.trainType) 13 | AMBIENT_AT_OEBB_TRIP_NUMBER=\(.currentJourney.tripNumber) 14 | AMBIENT_AT_OEBB_LINE_NUMBER=\(.currentJourney.linepNumber) 15 | AMBIENT_AT_OEBB_ACTUAL_DISTANCE_FROM_LAST_STOP=\(.operationalMessagesInfo.distance) 16 | AMBIENT_AT_OEBB_STOP_FIRST=\(.currentJourney.start.all) 17 | AMBIENT_AT_OEBB_STOP_FIRST_DEPART_SCHEDULED=\((.forecastTimes | first).departureSchedule) 18 | AMBIENT_AT_OEBB_STOP_LAST=\(.currentJourney.destination.all) 19 | AMBIENT_AT_OEBB_STOP_LAST_ARRIVE_SCHEDULED=\((.forecastTimes | last).arrivalSchedule) 20 | AMBIENT_AT_OEBB_STOP_LAST_ARRIVE_ACTUAL=\((.forecastTimes | last).arrivalForecast) 21 | AMBIENT_AT_OEBB_STOP_NEXT=\({stationList: .stationList[], station_id: .operationalMessagesInfo.situationStation} | select(.stationList.id == .station_id).stationList.name.all) 22 | AMBIENT_AT_OEBB_STOP_NEXT_DEPART_SCHEDULED=\({forecastTimes: .forecastTimes[], station_id: .operationalMessagesInfo.situationStation} | select(.forecastTimes.station_id == .station_id) | .forecastTimes.departureSchedule) 23 | AMBIENT_AT_OEBB_STOP_NEXT_DEPART_ACTUAL=\({forecastTimes: .forecastTimes[], station_id: .operationalMessagesInfo.situationStation} | select(.forecastTimes.station_id == .station_id) | .forecastTimes.departureForecast) 24 | AMBIENT_AT_OEBB_STOP_NEXT_ARRIVE_SCHEDULED=\({forecastTimes: .forecastTimes[], station_id: .operationalMessagesInfo.situationStation} | select(.forecastTimes.station_id == .station_id) | .forecastTimes.arrivalSchedule) 25 | AMBIENT_AT_OEBB_STOP_NEXT_ARRIVE_ACTUAL=\({forecastTimes: .forecastTimes[], station_id: .operationalMessagesInfo.situationStation} | select(.forecastTimes.station_id == .station_id) | .forecastTimes.arrivalForecast) 26 | "' 27 | -------------------------------------------------------------------------------- /ambient.d/trains/CZ_CD.fish: -------------------------------------------------------------------------------- 1 | ambient_is_ssid "CDWiFi"; or exit 2 | 3 | curl -s http://cdwifi.cz/portal/api/vehicle/realtime | jq -r '{ 4 | "AMBIENT_CZ_CD_GPS_LAT": (.gpsLat), 5 | "AMBIENT_CZ_CD_GPS_LNG": (.gpsLng), 6 | "AMBIENT_CZ_CD_PREV_GPS_LAT": (.gpsLat), 7 | "AMBIENT_CZ_CD_PREV_GPS_LNG": (.gpsLng), 8 | "AMBIENT_CZ_CD_PREV_GPS_LNG": (.gpsLng), 9 | "AMBIENT_CZ_CD_SPEED": (.speed), 10 | "AMBIENT_CZ_CD_DELAY": (.delay), 11 | "AMBIENT_CZ_CD_ALTITUDE": (.altitude), 12 | "AMBIENT_CZ_CD_TEMPERATURE": (.temperature), 13 | } | to_entries | map(select(.value != null)) | map(.key + "=" + (.value | tostring)) | join("\n")' 14 | -------------------------------------------------------------------------------- /ambient.d/trains/DE_ICE.fish: -------------------------------------------------------------------------------- 1 | ambient_is_ssid "WIFIonICE" "WIFI@DB"; or exit 2 | 3 | # Some ICEs use the SSID "WIFI@DB", but that's also used at stations in Germany. 4 | # We can tell if we're on a train if iceportal.de resolves to a private IP addr. 5 | string match '172.*' (ambient_resolve4 iceportal.de) >/dev/null; or exit 6 | 7 | # Also double-check that the API returns valid JSON, also not the case at stations. 8 | set train_status (curl -s https://iceportal.de/api1/rs/status) 9 | echo $train_status | jq type >/dev/null 2>&1; or exit 10 | 11 | echo $train_status | jq -r '{ 12 | "AMBIENT_DE_ICE_CONNECTION": (.connection), 13 | "AMBIENT_DE_ICE_CONNECTIVITY_STATE": (.connectivity.currentState), 14 | "AMBIENT_DE_ICE_SERVICE_LEVEL": (.servicelevel), 15 | "AMBIENT_DE_ICE_INTERNET": (.internet), 16 | "AMBIENT_DE_ICE_SPEED": (.speed), 17 | "AMBIENT_DE_ICE_SPEED_UNIT": "km/h", 18 | "AMBIENT_DE_ICE_GPS_STATUS": (.gpsStatus), 19 | "AMBIENT_DE_ICE_TZN": (.tzn), 20 | "AMBIENT_DE_ICE_SERIES": (.series), 21 | "AMBIENT_DE_ICE_LATITUDE": (.latitude), 22 | "AMBIENT_DE_ICE_LONGITUDE": (.longitude), 23 | "AMBIENT_DE_ICE_SERVER_TIME": (.serverTime / 1000 | round | todate), 24 | "AMBIENT_DE_ICE_WAGON_CLASS": (.wagonClass), 25 | "AMBIENT_DE_ICE_TRAIN_TYPE": (.trainType), 26 | } | to_entries | map(select(.value != null)) | map(.key + "=" + (.value | tostring)) | join("\n")' 27 | 28 | curl -s https://iceportal.de/api1/rs/tripInfo/trip | jq -r '{ 29 | "AMBIENT_DE_ICE_TRIP_DATE": .trip.tripDate, 30 | "AMBIENT_DE_ICE_VZN": .trip.vzn, 31 | "AMBIENT_DE_ICE_ACTUAL_POSITION": .trip.actualPosition, 32 | "AMBIENT_DE_ICE_ACTUAL_DISTANCE_FROM_LAST_STOP": .trip.distanceFromLastStop, 33 | "AMBIENT_DE_ICE_ACTUAL_TOTAL_DISTANCE": .trip.totalDistance, 34 | } + if .trip.stops then { 35 | "AMBIENT_DE_ICE_STOP_FIRST": (.trip.stops | first).station.name, 36 | "AMBIENT_DE_ICE_STOP_FIRST_DEPART_SCHEDULED": ((.trip.stops | first).timetable.scheduledDepartureTime / 1000 | round | todate), 37 | "AMBIENT_DE_ICE_STOP_FIRST_DEPART_ACTUAL": ((.trip.stops | first).timetable.actualDepartureTime/ 1000 | round | todate), 38 | "AMBIENT_DE_ICE_STOP_FIRST_DEPART_DELAY": (.trip.stops | first).timetable.departureDelay, 39 | 40 | "AMBIENT_DE_ICE_STOP_LAST": (.trip.stops | last).station.name, 41 | "AMBIENT_DE_ICE_STOP_LAST_ARRIVE_SCHEDULED": ((.trip.stops | last).timetable.scheduledArrivalTime / 1000 | round | todate), 42 | "AMBIENT_DE_ICE_STOP_LAST_ARRIVE_ACTUAL": ((.trip.stops | last).timetable.actualArrivalTime/ 1000 | round | todate), 43 | "AMBIENT_DE_ICE_STOP_LAST_ARRIVE_DELAY": (.trip.stops | last).timetable.arrivalDelay, 44 | 45 | "AMBIENT_DE_ICE_STOP_NEXT": ([.trip.stops[] | select(.info.passed == false)] | first).station.name, 46 | "AMBIENT_DE_ICE_STOP_NEXT_DEPART_SCHEDULED": (([.trip.stops[] | select(.info.passed == false)] | first).timetable.scheduledDepartureTime / 1000 | round | todate), 47 | "AMBIENT_DE_ICE_STOP_NEXT_DEPART_ACTUAL": (([.trip.stops[] | select(.info.passed == false)] | first).timetable.actualDepartureTime/ 1000 | round | todate), 48 | "AMBIENT_DE_ICE_STOP_NEXT_DEPART_DELAY": ([.trip.stops[] | select(.info.passed == false)] | first).timetable.departureDelay, 49 | "AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_SCHEDULED": (([.trip.stops[] | select(.info.passed == false)] | first).timetable.scheduledArrivalTime / 1000 | round | todate), 50 | "AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_ACTUAL": (([.trip.stops[] | select(.info.passed == false)] | first).timetable.actualArrivalTime/ 1000 | round | todate), 51 | "AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_DELAY": ([.trip.stops[] | select(.info.passed == false)] | first).timetable.arrivalDelay, 52 | } else {} end | to_entries | map(select(.value != null)) | map(.key + "=" + (.value | tostring)) | join("\n")' 53 | -------------------------------------------------------------------------------- /ambient.d/trains/EU_Eurostar.fish: -------------------------------------------------------------------------------- 1 | ambient_is_ssid "EurostarTrainsWiFi"; or exit 2 | 3 | # This is a horrible hack to get data out of a socket.io server, by pretending to be a broken 4 | # client (which can't correctly do websockets), and a bunch of data mangling. 5 | # 6 | # The socket.io protocol consists of messages in the form: 96:0:..., where 96 is the length of the 7 | # message, 0 is the message type, and ... is the actual data. 8 | # 9 | # First of all, the length is binary. By discarding all data that isn't a printable character, we 10 | # get something which we can pipe into `jq`, which will split out all JSON objects it can find. 11 | # Numbers are valid objects, which means that the type field will end up being one - so we further 12 | # discard any lines containing just numbers. 13 | # 14 | # This is brittle as all heck, but it works because the Eurostar only sends short payloads anyhow. 15 | function sio_poll 16 | set sid $argv[1] 17 | curl -s "https://onboard.eurostar.com:5555/socket.io/?EIO=3&transport=polling&sid=$sid" \ 18 | | tr -cd '[:print:]' | jq -c | sed -E 's/^[0-9]+$//' 19 | end 20 | 21 | set -l sid (sio_poll "" | jq -r '.sid') 22 | set -l payloads 23 | while [ -z "$payloads" ] 24 | set payloads (sio_poll $sid) 25 | end 26 | set -l payload $payloads[-1] 27 | 28 | echo $payload | jq -r '" 29 | AMBIENT_EU_EUROSTAR_LAT=\(.[1].LAT) 30 | AMBIENT_EU_EUROSTAR_LON=\(.[1].LON) 31 | AMBIENT_EU_EUROSTAR_SPEED=\(.[1].SPEED) 32 | AMBIENT_EU_EUROSTAR_TRAIN_ID=\(.[1].TRAIN_ID) 33 | "' 34 | -------------------------------------------------------------------------------- /ambient.d/trains/_icomera.fish: -------------------------------------------------------------------------------- 1 | set ambient_icomera_country "" 2 | set ambient_icomera_provider "" 3 | 4 | set -l ssid (ambient_get_ssid) 5 | switch $ssid 6 | case "GatwickExpress_WiFi" 7 | set ambient_icomera_country GB 8 | set ambient_icomera_provider "Gatwick Express" 9 | case "Thameslink_WiFi" 10 | set ambient_icomera_country GB 11 | set ambient_icomera_provider Thameslink 12 | case "Southern_WiFi" 13 | set ambient_icomera_country GB 14 | set ambient_icomera_provider Southern 15 | case "GreatNorthern_WiFi" 16 | set ambient_icomera_country GB 17 | set ambient_icomera_provider "Great Northern" 18 | case "SWR WiFi" 19 | set ambient_icomera_country GB 20 | set ambient_icomera_provider "South Western Railway" 21 | case "VirginTrainsEC-WiFi" 22 | set ambient_icomera_country GB 23 | set ambient_icomera_provider "Virgin Trains East Coast" 24 | case "TPE Wi-Fi" 25 | set ambient_icomera_country GB 26 | set ambient_icomera_provider "TransPennine Express" 27 | case "SJ" 28 | set ambient_icomera_country SE 29 | set ambient_icomera_provider SJ 30 | case "Irish Rail - WiFi" 31 | set ambient_icomera_country IE 32 | set ambient_icomera_provider "Irish Rail" 33 | case "THALYSNET" 34 | set ambient_icomera_country FR 35 | set ambient_icomera_provider Thalys 36 | end 37 | test -n "$ambient_icomera_provider"; or exit 38 | 39 | function ambient_get_icomera_endpoint 40 | set url https://www.ombord.info/api/jsonp/$argv/ 41 | 42 | if test (uname) = "Darwin" 43 | curl -s $url | tail -c +2 | ghead -c -3 44 | else 45 | curl -s $url | tail -c +2 | head -c -3 46 | end 47 | end 48 | 49 | echo AMBIENT_ICOMERA_PROVIDER=$ambient_icomera_provider 50 | echo AMBIENT_ICOMERA_COUNTRY=$ambient_icomera_country 51 | ambient_get_icomera_endpoint position | jq -r '" 52 | AMBIENT_ICOMERA_POSITION_LONGITUDE=\(.longitude) 53 | AMBIENT_ICOMERA_POSITION_LATITUDE=\(.latitude) 54 | AMBIENT_ICOMERA_POSITION_ALTITUDE=\(.altitude) 55 | AMBIENT_ICOMERA_POSITION_SPEED=\((.speed | tonumber)*60*60/1000 | round) 56 | AMBIENT_ICOMERA_POSITION_SATELLITES=\(.satellites) 57 | "' 58 | ambient_get_icomera_endpoint users | jq -r '" 59 | AMBIENT_ICOMERA_USERS_TOTAL=\(.total) 60 | AMBIENT_ICOMERA_USERS_ONLINE=\(.online) 61 | "' 62 | ambient_get_icomera_endpoint user | jq -r '" 63 | AMBIENT_ICOMERA_USER_DATA_DOWNLOAD_USED=\(.data_download_used) 64 | AMBIENT_ICOMERA_USER_DATA_UPLOAD_USED=\(.data_upload_used) 65 | AMBIENT_ICOMERA_USER_DATA_TOTAL_USED=\(.data_total_used) 66 | AMBIENT_ICOMERA_USER_DATA_DOWNLOAD_LIMIT=\(.data_download_limit) 67 | AMBIENT_ICOMERA_USER_DATA_UPLOAD_LIMIT=\(.data_upload_limit) 68 | AMBIENT_ICOMERA_USER_DATA_TOTAL_LIMIT=\(.data_total_limit) 69 | AMBIENT_ICOMERA_USER_BANDWIDTH_DOWNLOAD_LIMIT=\(.bandwidth_download_limit) 70 | AMBIENT_ICOMERA_USER_BANDWIDTH_UPLOAD_LIMIT=\(.bandwidth_upload_limit) 71 | AMBIENT_ICOMERA_USER_TIME_USER=\(.timeused) 72 | AMBIENT_ICOMERA_USER_TIME_LEFT=\(.timeleft) 73 | AMBIENT_ICOMERA_USER_EXPIRES=\(.expires) 74 | AMBIENT_ICOMERA_USER_CLASS=\(.userclass) 75 | AMBIENT_ICOMERA_USER_ONLINE=\(.online) 76 | AMBIENT_ICOMERA_USER_CAP_LEVEL=\(.cap_level) 77 | AMBIENT_ICOMERA_USER_AUTHENTICATED=\(.authenticated) 78 | "' 79 | -------------------------------------------------------------------------------- /bitbar/ambient.60s.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SOURCE="${BASH_SOURCE[0]}" 4 | while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink 5 | DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" 6 | SOURCE="$(readlink "$SOURCE")" 7 | [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located 8 | done 9 | DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" 10 | 11 | PATH="/usr/local/bin:$PATH" # to find Homebrew-installed fish 12 | 13 | # look for config file in XDG config dirs 14 | while IFS=: read -d: -r p; do 15 | if [ -z "$config_path" ] && [ -r "$p/bitbar/plugins/ambient.json" ]; then 16 | config_path="$p/bitbar/plugins/ambient.json" 17 | fi 18 | done <<<$(printf '%s:\0' "${XDG_CONFIG_HOME:-"${HOME}/.config"}:${XDG_CONFIG_DIRS:-/etc/xdg}") 19 | if [ -z "$config_path" ]; then 20 | config='{}' 21 | else 22 | config="$(cat "$config_path")" 23 | fi 24 | 25 | WIDGET=$(/usr/local/bin/fish $DIR/../ambient-widgets | tr '\n' ' ') 26 | 27 | if [ -z "$WIDGET" ]; then 28 | if echo "$config" | jq -e 'if has("showIfEmpty") then .showIfEmpty else true end' > /dev/null; then 29 | echo "🚄" 30 | fi 31 | else 32 | echo $WIDGET 33 | echo "---" 34 | echo "Go to map|href=https://iceportal.de/Karte_neu" 35 | echo $(/usr/local/bin/fish $DIR/../ambient | tr '\n' '\r\n') 36 | fi 37 | -------------------------------------------------------------------------------- /functions.d/ambient_get_ssid.fish: -------------------------------------------------------------------------------- 1 | function ambient_get_ssid 2 | if not set -q ambient_ssid 3 | if test (uname) = "Darwin" # On macOS, query the airport tool. 4 | set -g ambient_ssid (/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | sed -n 's/^ *SSID: //p') 5 | else 6 | # Try to get the SSID via `iw`. This is the quickest, most widely supported option. 7 | if command -q iw 8 | set -g ambient_ssid (iw dev | grep ssid | sed -n 's/^\s*ssid //p' | string trim) 9 | end 10 | 11 | # In some setups (why?), `iw dev` can't show an SSID. Try querying NetworkManager? 12 | if test -z $ambient_ssid; and command -q nmcli 13 | set -g ambient_ssid (nmcli -t -f type,name connection show --active |\ 14 | string match -rg '802-11-wireless:(.*)') 15 | end 16 | end 17 | end 18 | echo $ambient_ssid 19 | end 20 | -------------------------------------------------------------------------------- /functions.d/ambient_is_ssid.fish: -------------------------------------------------------------------------------- 1 | function ambient_is_ssid 2 | set -l ssid (ambient_get_ssid) 3 | for arg in $argv 4 | if [ "$arg" = "$ssid" ] 5 | return 0 6 | end 7 | end 8 | return 1 9 | end 10 | -------------------------------------------------------------------------------- /functions.d/ambient_resolve4.fish: -------------------------------------------------------------------------------- 1 | function ambient_resolve4 2 | host -tA iceportal.de | sed 's/.*has address //' 3 | end 4 | -------------------------------------------------------------------------------- /lib/_dispatch_ambient.fish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env fish 2 | 3 | # Make fish autoload our functions before trying built-in ones. 4 | set -p fish_function_path ./functions.d 5 | 6 | for file in ./ambient.d/**/*.fish 7 | source $file 8 | end 9 | -------------------------------------------------------------------------------- /lib/_dispatch_widgets.fish: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env fish 2 | 3 | for file in ./widgets.d/**/*.fish 4 | source $file 5 | end 6 | -------------------------------------------------------------------------------- /widgets.d/trains/AT_OEBB.fish: -------------------------------------------------------------------------------- 1 | if set -q AMBIENT_AT_OEBB_STOP_NEXT 2 | echo " $AMBIENT_AT_OEBB_STOP_NEXT" 3 | end 4 | if [ -n "$AMBIENT_AT_OEBB_STOP_NEXT_ARRIVE_ACTUAL" ] 5 | echo " $AMBIENT_AT_OEBB_STOP_NEXT_ARRIVE_ACTUAL" 6 | end 7 | if set -q AMBIENT_AT_OEBB_TRAIN_TYPE 8 | echo " $AMBIENT_AT_OEBB_TRAIN_TYPE-$AMBIENT_AT_OEBB_VZN" 9 | end 10 | if set -q AMBIENT_AT_OEBB_SPEED 11 | echo " $AMBIENT_AT_OEBB_SPEED km/h" 12 | end 13 | -------------------------------------------------------------------------------- /widgets.d/trains/CZ_CD.fish: -------------------------------------------------------------------------------- 1 | if set -q AMBIENT_CZ_CD_SPEED 2 | echo "💨 $AMBIENT_CZ_CD_SPEED km/h" 3 | end 4 | -------------------------------------------------------------------------------- /widgets.d/trains/DE_ICE.fish: -------------------------------------------------------------------------------- 1 | if set -q AMBIENT_DE_ICE_STOP_NEXT 2 | echo "🚏 $AMBIENT_DE_ICE_STOP_NEXT" 3 | end 4 | if set -q AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_SCHEDULED 5 | echo "⌚" (date -d "$AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_SCHEDULED" +%H:%M) 6 | end 7 | if [ -n "$AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_DELAY" ] 8 | echo "⏱ $AMBIENT_DE_ICE_STOP_NEXT_ARRIVE_DELAY" 9 | end 10 | if set -q AMBIENT_DE_ICE_TRAIN_TYPE 11 | echo -n "🚄 $AMBIENT_DE_ICE_TRAIN_TYPE" 12 | # If iceportal.de is having a moment, we may not have the train number. 13 | set -q AMBIENT_DE_ICE_VZN; and echo -n " $AMBIENT_DE_ICE_VZN" 14 | echo 15 | end 16 | if set -q AMBIENT_DE_ICE_SPEED 17 | echo "💨 $AMBIENT_DE_ICE_SPEED km/h" 18 | end 19 | switch "$AMBIENT_DE_ICE_CONNECTIVITY_STATE" 20 | case 'HIGH' 21 | echo "📶 🛜" 22 | case 'WEAK' 23 | echo "📶️ ♒" 24 | case 'UNSTABLE' 25 | echo "📶 〰️" 26 | case 'NO_INFO' 27 | # :( 28 | end 29 | -------------------------------------------------------------------------------- /widgets.d/trains/EU_Eurostar.fish: -------------------------------------------------------------------------------- 1 | if set -q AMBIENT_EU_EUROSTAR_TRAIN_ID 2 | echo "🚄 Eurostar $AMBIENT_EU_EUROSTAR_TRAIN_ID" 3 | end 4 | if set -q AMBIENT_EU_EUROSTAR_SPEED 5 | echo "💨 $AMBIENT_EU_EUROSTAR_SPEED km/h" 6 | end 7 | -------------------------------------------------------------------------------- /widgets.d/trains/_icomera.fish: -------------------------------------------------------------------------------- 1 | if set -q AMBIENT_ICOMERA_PROVIDER 2 | echo "🚄 $AMBIENT_ICOMERA_PROVIDER" 3 | end 4 | if set -q AMBIENT_ICOMERA_POSITION_SPEED 5 | echo "💨 $AMBIENT_ICOMERA_POSITION_SPEED km/h" 6 | end 7 | --------------------------------------------------------------------------------