├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── screenshot.png └── src ├── garage.rs ├── main.rs └── weather.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "alsa" 7 | version = "0.1.10" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d59934ece7c39ba89796b3cae0e7a56cd0a346a1b6b9194dd3e2a1a48b629249" 10 | dependencies = [ 11 | "alsa-sys", 12 | "bitflags", 13 | "libc", 14 | ] 15 | 16 | [[package]] 17 | name = "alsa-sys" 18 | version = "0.1.2" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" 21 | dependencies = [ 22 | "libc", 23 | "pkg-config", 24 | ] 25 | 26 | [[package]] 27 | name = "autocfg" 28 | version = "1.0.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 31 | 32 | [[package]] 33 | name = "bar" 34 | version = "0.1.0" 35 | dependencies = [ 36 | "serde", 37 | "serde_json", 38 | "systemstat", 39 | "unixbar", 40 | "ureq", 41 | ] 42 | 43 | [[package]] 44 | name = "base64" 45 | version = "0.13.0" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" 48 | 49 | [[package]] 50 | name = "bitflags" 51 | version = "0.8.2" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" 54 | 55 | [[package]] 56 | name = "bytesize" 57 | version = "1.1.0" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70" 60 | 61 | [[package]] 62 | name = "cfg-if" 63 | version = "1.0.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 66 | 67 | [[package]] 68 | name = "chan" 69 | version = "0.1.23" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "d14956a3dae065ffaa0d92ece848ab4ced88d32361e7fdfbfd653a5c454a1ed8" 72 | dependencies = [ 73 | "rand 0.3.23", 74 | ] 75 | 76 | [[package]] 77 | name = "chrono" 78 | version = "0.2.25" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00" 81 | dependencies = [ 82 | "num", 83 | "time", 84 | ] 85 | 86 | [[package]] 87 | name = "chrono" 88 | version = "0.4.19" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 91 | dependencies = [ 92 | "libc", 93 | "num-integer", 94 | "num-traits", 95 | "winapi", 96 | ] 97 | 98 | [[package]] 99 | name = "chunked_transfer" 100 | version = "1.4.0" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e" 103 | 104 | [[package]] 105 | name = "form_urlencoded" 106 | version = "1.0.1" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" 109 | dependencies = [ 110 | "matches", 111 | "percent-encoding", 112 | ] 113 | 114 | [[package]] 115 | name = "fuchsia-cprng" 116 | version = "0.1.1" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 119 | 120 | [[package]] 121 | name = "idna" 122 | version = "0.2.3" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" 125 | dependencies = [ 126 | "matches", 127 | "unicode-bidi", 128 | "unicode-normalization", 129 | ] 130 | 131 | [[package]] 132 | name = "itoa" 133 | version = "1.0.2" 134 | source = "registry+https://github.com/rust-lang/crates.io-index" 135 | checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" 136 | 137 | [[package]] 138 | name = "lazy_static" 139 | version = "1.4.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 142 | 143 | [[package]] 144 | name = "libc" 145 | version = "0.2.103" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" 148 | 149 | [[package]] 150 | name = "log" 151 | version = "0.4.14" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 154 | dependencies = [ 155 | "cfg-if", 156 | ] 157 | 158 | [[package]] 159 | name = "matches" 160 | version = "0.1.9" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" 163 | 164 | [[package]] 165 | name = "memchr" 166 | version = "1.0.2" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" 169 | dependencies = [ 170 | "libc", 171 | ] 172 | 173 | [[package]] 174 | name = "memchr" 175 | version = "2.3.4" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 178 | 179 | [[package]] 180 | name = "minimal-lexical" 181 | version = "0.2.1" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 184 | 185 | [[package]] 186 | name = "nom" 187 | version = "3.2.1" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" 190 | dependencies = [ 191 | "memchr 1.0.2", 192 | ] 193 | 194 | [[package]] 195 | name = "nom" 196 | version = "7.1.1" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" 199 | dependencies = [ 200 | "memchr 2.3.4", 201 | "minimal-lexical", 202 | ] 203 | 204 | [[package]] 205 | name = "num" 206 | version = "0.1.42" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" 209 | dependencies = [ 210 | "num-integer", 211 | "num-iter", 212 | "num-traits", 213 | ] 214 | 215 | [[package]] 216 | name = "num-integer" 217 | version = "0.1.44" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 220 | dependencies = [ 221 | "autocfg", 222 | "num-traits", 223 | ] 224 | 225 | [[package]] 226 | name = "num-iter" 227 | version = "0.1.42" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" 230 | dependencies = [ 231 | "autocfg", 232 | "num-integer", 233 | "num-traits", 234 | ] 235 | 236 | [[package]] 237 | name = "num-traits" 238 | version = "0.2.14" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 241 | dependencies = [ 242 | "autocfg", 243 | ] 244 | 245 | [[package]] 246 | name = "once_cell" 247 | version = "1.8.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 250 | 251 | [[package]] 252 | name = "percent-encoding" 253 | version = "2.1.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 256 | 257 | [[package]] 258 | name = "pkg-config" 259 | version = "0.3.20" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" 262 | 263 | [[package]] 264 | name = "proc-macro2" 265 | version = "1.0.40" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" 268 | dependencies = [ 269 | "unicode-ident", 270 | ] 271 | 272 | [[package]] 273 | name = "quote" 274 | version = "1.0.10" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 277 | dependencies = [ 278 | "proc-macro2", 279 | ] 280 | 281 | [[package]] 282 | name = "rand" 283 | version = "0.3.23" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" 286 | dependencies = [ 287 | "libc", 288 | "rand 0.4.6", 289 | ] 290 | 291 | [[package]] 292 | name = "rand" 293 | version = "0.4.6" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" 296 | dependencies = [ 297 | "fuchsia-cprng", 298 | "libc", 299 | "rand_core 0.3.1", 300 | "rdrand", 301 | "winapi", 302 | ] 303 | 304 | [[package]] 305 | name = "rand_core" 306 | version = "0.3.1" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 309 | dependencies = [ 310 | "rand_core 0.4.2", 311 | ] 312 | 313 | [[package]] 314 | name = "rand_core" 315 | version = "0.4.2" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 318 | 319 | [[package]] 320 | name = "rdrand" 321 | version = "0.4.0" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 324 | dependencies = [ 325 | "rand_core 0.3.1", 326 | ] 327 | 328 | [[package]] 329 | name = "ryu" 330 | version = "1.0.5" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 333 | 334 | [[package]] 335 | name = "serde" 336 | version = "1.0.137" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" 339 | dependencies = [ 340 | "serde_derive", 341 | ] 342 | 343 | [[package]] 344 | name = "serde_derive" 345 | version = "1.0.137" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" 348 | dependencies = [ 349 | "proc-macro2", 350 | "quote", 351 | "syn", 352 | ] 353 | 354 | [[package]] 355 | name = "serde_json" 356 | version = "1.0.81" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" 359 | dependencies = [ 360 | "itoa", 361 | "ryu", 362 | "serde", 363 | ] 364 | 365 | [[package]] 366 | name = "syn" 367 | version = "1.0.98" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" 370 | dependencies = [ 371 | "proc-macro2", 372 | "quote", 373 | "unicode-ident", 374 | ] 375 | 376 | [[package]] 377 | name = "systemstat" 378 | version = "0.1.11" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "5f5dc96f7634f46ac7e485b8c051f5b89ec8ee5cc023236dd12fe4ae2fb52f80" 381 | dependencies = [ 382 | "bytesize", 383 | "chrono 0.4.19", 384 | "lazy_static", 385 | "libc", 386 | "nom 7.1.1", 387 | "winapi", 388 | ] 389 | 390 | [[package]] 391 | name = "time" 392 | version = "0.1.44" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 395 | dependencies = [ 396 | "libc", 397 | "wasi", 398 | "winapi", 399 | ] 400 | 401 | [[package]] 402 | name = "tinyvec" 403 | version = "1.5.0" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" 406 | dependencies = [ 407 | "tinyvec_macros", 408 | ] 409 | 410 | [[package]] 411 | name = "tinyvec_macros" 412 | version = "0.1.0" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 415 | 416 | [[package]] 417 | name = "unicode-bidi" 418 | version = "0.3.7" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" 421 | 422 | [[package]] 423 | name = "unicode-ident" 424 | version = "1.0.1" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" 427 | 428 | [[package]] 429 | name = "unicode-normalization" 430 | version = "0.1.19" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" 433 | dependencies = [ 434 | "tinyvec", 435 | ] 436 | 437 | [[package]] 438 | name = "unixbar" 439 | version = "0.1.3" 440 | source = "git+https://github.com/wezm/unixbar.git?branch=awesome#f0e766d24ce7bd7fb57c9cfe63e959fd3dd6987a" 441 | dependencies = [ 442 | "alsa", 443 | "chan", 444 | "chrono 0.2.25", 445 | "libc", 446 | "nom 3.2.1", 447 | "serde", 448 | "serde_derive", 449 | "serde_json", 450 | "systemstat", 451 | "xml_writer", 452 | ] 453 | 454 | [[package]] 455 | name = "ureq" 456 | version = "2.4.0" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "9399fa2f927a3d327187cbd201480cee55bee6ac5d3c77dd27f0c6814cff16d5" 459 | dependencies = [ 460 | "base64", 461 | "chunked_transfer", 462 | "log", 463 | "once_cell", 464 | "serde", 465 | "serde_json", 466 | "url", 467 | ] 468 | 469 | [[package]] 470 | name = "url" 471 | version = "2.2.2" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" 474 | dependencies = [ 475 | "form_urlencoded", 476 | "idna", 477 | "matches", 478 | "percent-encoding", 479 | ] 480 | 481 | [[package]] 482 | name = "wasi" 483 | version = "0.10.0+wasi-snapshot-preview1" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 486 | 487 | [[package]] 488 | name = "winapi" 489 | version = "0.3.9" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 492 | dependencies = [ 493 | "winapi-i686-pc-windows-gnu", 494 | "winapi-x86_64-pc-windows-gnu", 495 | ] 496 | 497 | [[package]] 498 | name = "winapi-i686-pc-windows-gnu" 499 | version = "0.4.0" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 502 | 503 | [[package]] 504 | name = "winapi-x86_64-pc-windows-gnu" 505 | version = "0.4.0" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 508 | 509 | [[package]] 510 | name = "xml_writer" 511 | version = "0.4.0" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "3a74a847d8392999f89e9668c4dd46283b91fd6fc1f34aa5ecf4ceaf8fa3258e" 514 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bar" 3 | version = "0.1.0" 4 | authors = ["Wesley Moore "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | ureq = { version = "2.4.0", default-features = false, features = ["json"] } 9 | serde = { version = "1.0.137", features = ["derive"] } 10 | serde_json = "1.0.81" 11 | systemstat = "0.1.11" 12 | unixbar = { git = "https://github.com/wezm/unixbar.git", branch = "awesome", default-features = false, features = ["awesome", "systemstat"] } 13 | #unixbar = { path = "../unixbar", features = ["awesome", "systemstat"], default-features = false } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bar 2 | 3 | This is a small Rust program that uses [unixbar] to generate some status info. It is used by 4 | [awesome] to show audio volume, battery level, and weather info. 5 | 6 | Screen show of bar in action 7 | 8 | See my [rc.lua] for how it's used from awesome. 9 | 10 | ## Dependencies 11 | 12 | ### FreeBSD 13 | 14 | * dbus 15 | * pkgconfig 16 | * xcb 17 | * python3 :( 18 | 19 | [unixbar]: https://github.com/myfreeweb/unixbar 20 | [awesome]: https://awesomewm.org/ 21 | [rc.lua]: https://github.com/wezm/dotfiles/blob/3e773263c0222a8b956923164e8e08438865cd55/config/awesome/rc.lua#L215-L227 22 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wezm/bar/578fd8901ff684e53852276ce4844bb1346a581d/screenshot.png -------------------------------------------------------------------------------- /src/garage.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | 3 | use crate::weather::WeatherError; 4 | 5 | const GARAGE_URL: &str = "http://10.0.0.11:8888/door.json"; 6 | 7 | pub struct Client {} 8 | 9 | //{ 10 | // "state": "Closed", 11 | // "secs_since_notified": null, 12 | // "open_for": null 13 | //} 14 | 15 | #[allow(dead_code)] 16 | #[derive(Debug, Deserialize)] 17 | pub struct Door { 18 | pub state: DoorState, 19 | secs_since_notified: Option, 20 | open_for: Option, 21 | } 22 | 23 | #[derive(Debug, Deserialize)] 24 | pub enum DoorState { 25 | Open, 26 | Closed, 27 | Unknown, 28 | } 29 | 30 | impl Client { 31 | pub fn new() -> Self { 32 | Client {} 33 | } 34 | 35 | pub fn state(&self) -> Result { 36 | let resp = ureq::get(GARAGE_URL) 37 | .timeout(std::time::Duration::from_secs(10)) 38 | .call(); 39 | 40 | resp.map_err(|_err| WeatherError::HttpError) 41 | .and_then(|resp| resp.into_json::().map_err(WeatherError::JsonError)) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use systemstat::{Platform, System}; 3 | use unixbar::*; 4 | 5 | mod garage; 6 | mod weather; 7 | 8 | use crate::garage::{Door, DoorState}; 9 | use crate::weather::Observation; 10 | 11 | #[derive(Default)] 12 | struct Config { 13 | audio: bool, 14 | battery: bool, 15 | weather: bool, 16 | cpu_temp: bool, 17 | garage: bool, 18 | } 19 | 20 | impl Config { 21 | fn from_args() -> Self { 22 | let mut config = Config::default(); 23 | 24 | for arg in env::args().skip(1) { 25 | match arg.as_str() { 26 | "-a" => config.audio = true, 27 | "-b" => config.battery = true, 28 | "-w" => config.weather = true, 29 | "-c" => config.cpu_temp = true, 30 | "-g" => config.garage = true, 31 | _ => (), 32 | } 33 | } 34 | 35 | config 36 | } 37 | } 38 | 39 | fn main() { 40 | let config = Config::from_args(); 41 | 42 | let mut bar = UnixBar::new(AwesomeFormatter::new()); 43 | 44 | if config.audio { 45 | bar.add(Volume::new(default_volume(), |volume| { 46 | if volume.muted { 47 | bfmt![text["🔇"]] 48 | } else { 49 | let volume = (volume.volume * 100.).round() as i32; 50 | if volume < 1 { 51 | bfmt![fmt["🔈{}", volume]] 52 | } else if volume < 25 { 53 | bfmt![fmt["🔉{}", volume]] 54 | } else { 55 | bfmt![fmt["🔊 {}", volume]] 56 | } 57 | } 58 | })); 59 | } 60 | 61 | if config.battery { 62 | bar.add(Periodic::new(Duration::from_secs(30), || { 63 | let system = System::new(); 64 | let symbol = system.on_ac_power().map(|on_ac_power| if on_ac_power { "🔌" } else { "🔋" }); 65 | match (symbol, system.battery_life()) { 66 | (Ok(symbol), Ok(battery)) => 67 | bfmt![ pad[1] fmt["{} {}%", symbol, (battery.remaining_capacity * 100.).round() as i32]], 68 | (Ok(symbol), Err(_)) => 69 | bfmt![ pad[1] text[symbol]], 70 | (Err(err), _) => 71 | bfmt![fg["#bb1155"] pad[1] text[err.to_string()]], 72 | }} 73 | )); 74 | } 75 | 76 | if config.weather { 77 | bar.add(Periodic::new(Duration::from_secs(5 * 60), || { 78 | let weather = weather::Client::new(); 79 | 80 | let observation = weather.current_conditions().ok(); 81 | 82 | bfmt![ pad[1] fmt["{}", format_observation(&observation)] ] 83 | })); 84 | } 85 | 86 | if config.cpu_temp { 87 | bar.add(Periodic::new( 88 | Duration::from_secs(5), 89 | || match System::new().cpu_temp() { 90 | Ok(temp) => bfmt![pad[1] fmt["{}°C", temp]], 91 | Err(_) => bfmt![fg["#bb1155"] pad[1] text["cpu temp error"]], 92 | }, 93 | )); 94 | } 95 | 96 | if config.garage { 97 | bar.add(Periodic::new(Duration::from_secs(15), || { 98 | let garage = garage::Client::new(); 99 | 100 | let door = garage.state().ok(); 101 | 102 | let emoji = match door { 103 | Some(Door { 104 | state: DoorState::Open, 105 | .. 106 | }) => "🪟", 107 | Some(Door { 108 | state: DoorState::Closed, 109 | .. 110 | }) => "🚪", 111 | Some(Door { 112 | state: DoorState::Unknown, 113 | .. 114 | }) => "🚪❓", 115 | None => "🚪⁉️", 116 | }; 117 | 118 | bfmt![ pad[1] fmt["{}", emoji] ] 119 | })); 120 | } 121 | 122 | // .register_fn("prev", move || { MPRISMusic::new().prev(); }) 123 | // .register_fn("play_pause", move || { MPRISMusic::new().play_pause(); }) 124 | // .register_fn("next", move || { MPRISMusic::new().next(); }) 125 | // .add(Music::new(MPRISMusic::new(), 126 | // |song| { 127 | // if let Some(playing) = song.playback.map(|playback| playback.playing) { 128 | // bfmt![ 129 | // fg["#bbbbbb"] 130 | // multi[ 131 | // (click[MouseButton::Left => fn "prev"] no_sep text["[|<]"]), 132 | // (click[MouseButton::Left => fn "play_pause"] 133 | // no_sep text[if playing { "[||]" } else { "[>]" }]), 134 | // (click[MouseButton::Left => sh format!("firefox 'https://musicbrainz.org/artist/{}'", 135 | // song.musicbrainz_artist.unwrap_or("".to_owned()))] 136 | // no_sep pad[4] text[song.artist]), 137 | // (no_sep pad[4] text["-"]), 138 | // (click[MouseButton::Left => sh format!("firefox 'https://musicbrainz.org/recording/{}'", 139 | // song.musicbrainz_track.unwrap_or("".to_owned()))] 140 | // no_sep text[song.title]), 141 | // (click[MouseButton::Left => fn "next"] text["[>|]"]) 142 | // ] 143 | // ] 144 | // } else { 145 | // bfmt![click[MouseButton::Left => sh "rhythmbox"] 146 | // fg["#bbbbbb"] text["[start music]"]] 147 | // } 148 | // } 149 | // )) 150 | 151 | // .add(Text::new(bfmt![click[MouseButton::Left => sh "notify-send hi"] 152 | // click[MouseButton::Right => sh "notify-send 'what?'"] 153 | // fg["#11bb55"] text[" Hello World! "]])) 154 | 155 | // .add(Bspwm::new(|bsp| Format::Concat(bsp.desktops.iter().map(|d| Box::new({ 156 | // let bg = if d.focused { "#99aa11" } else { "#111111" }; 157 | // bfmt![click[MouseButton::Left => sh format!("bspc desktop -f {}", d.name)] 158 | // bg[bg] fmt[" {} ", d.name]] 159 | // })).collect()))) 160 | 161 | // .add(Text::new(bfmt![right])) 162 | 163 | // .add(Periodic::new( 164 | // Duration::from_secs(15), 165 | // || match System::new().memory() { 166 | // Ok(mem) => bfmt![bg["#556677"] fmt[" {}/{} RAM ", mem.free.to_string(false).replace(" GB", ""), mem.total]], 167 | // Err(_) => bfmt![fg["#bb1155"] text["error"]], 168 | // })) 169 | 170 | // .add(Delayed::new( 171 | // Duration::from_secs(5), 172 | // || System::new().cpu_load_aggregate().unwrap(), 173 | // |res| match res { 174 | // Ok(cpu) => bfmt![fg["#99aaff"] fmt[" {:04.1}% CPU ", (1.0 - cpu.idle) * 100.0]], 175 | // Err(_) => bfmt![fg["#bb1155"] text["error"]], 176 | // })) 177 | 178 | bar.run_no_stdin(); 179 | } 180 | 181 | pub fn format_observation(observation: &Option) -> String { 182 | if let Some(o) = observation { 183 | format!( 184 | "🌡{}°c ({}°c) 🌧 ️{}mm 💧{}°c 🌫 ️{}% 🛩 ️{}km/h", 185 | o.air_temp, o.apparent_t, o.rain_trace, o.dewpt, o.rel_hum, o.wind_spd_kmh 186 | ) 187 | } else { 188 | format!("🌡 --") 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/weather.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use serde::Deserialize; 4 | use serde_json::Value as JsonValue; 5 | 6 | // Melbourne 7 | // const OBSERVATIONS_URL: &str = "http://reg.bom.gov.au/fwo/IDV60901/IDV60901.95936.json"; 8 | // Sunshine Coast Airport http://www.bom.gov.au/products/IDQ60901/IDQ60901.94569.shtml 9 | // const OBSERVATIONS_URL: &str = "http://www.bom.gov.au/fwo/IDQ60901/IDQ60901.94569.json"; 10 | // Beerburrum http://www.bom.gov.au/products/IDQ60901/IDQ60901.95566.shtml 11 | const OBSERVATIONS_URL: &str = "http://www.bom.gov.au/fwo/IDQ60901/IDQ60901.95566.json"; 12 | // Nambour http://www.bom.gov.au/products/IDQ60901/IDQ60901.95572.shtml 13 | // const OBSERVATIONS_URL: &str = "http://www.bom.gov.au/fwo/IDQ60901/IDQ60901.95572.json"; 14 | 15 | pub struct Client {} 16 | 17 | #[derive(Debug, Deserialize)] 18 | struct ObservationsRaw { 19 | observations: Observations, 20 | } 21 | 22 | #[derive(Debug, Deserialize)] 23 | struct Observations { 24 | data: Vec, 25 | } 26 | 27 | #[derive(Debug, Deserialize)] 28 | pub enum WindDirection { 29 | CALM, 30 | N, 31 | NE, 32 | E, 33 | SE, 34 | S, 35 | SW, 36 | W, 37 | NW, 38 | NNE, 39 | ENE, 40 | ESE, 41 | SSE, 42 | SSW, 43 | WSW, 44 | WNW, 45 | NNW, 46 | } 47 | 48 | #[derive(Debug, Deserialize)] 49 | pub struct Observation { 50 | pub sort_order: u32, 51 | pub name: String, 52 | pub history_product: String, 53 | pub local_date_time: String, //"11/01:30pm", 54 | pub local_date_time_full: String, // "20180811133000", 55 | pub aifstime_utc: String, // "20180811033000", 56 | pub lat: f64, 57 | pub lon: f64, 58 | pub apparent_t: f64, 59 | pub delta_t: f64, 60 | pub gust_kmh: u32, 61 | pub gust_kt: u32, 62 | pub air_temp: f64, 63 | pub dewpt: f64, 64 | pub press: Option, 65 | pub press_qnh: Option, 66 | pub press_msl: Option, 67 | pub press_tend: String, 68 | pub rain_trace: String, // Rain since 9am, not sure why this is a string 69 | pub rel_hum: u32, 70 | pub wind_dir: WindDirection, 71 | pub wind_spd_kmh: u32, 72 | pub wind_spd_kt: u32, 73 | } 74 | 75 | #[derive(Debug)] 76 | pub enum WeatherError { 77 | HttpError, 78 | JsonError(io::Error), 79 | } 80 | 81 | //ftp://ftp.bom.gov.au/anon/gen/fwo/IDV10450.xml 82 | //http://reg.bom.gov.au/fwo/IDV60901/IDV60901.95936.json 83 | 84 | impl Client { 85 | pub fn new() -> Self { 86 | Client {} 87 | } 88 | 89 | pub fn current_conditions(&self) -> Result { 90 | let resp = ureq::get(OBSERVATIONS_URL) 91 | .timeout(std::time::Duration::from_secs(10)) 92 | .call(); 93 | 94 | resp.map_err(|_err| WeatherError::HttpError) 95 | .and_then(|resp| { 96 | resp.into_json::() 97 | .map_err(WeatherError::JsonError) 98 | .and_then(|obs| { 99 | obs.observations.data.into_iter().next().ok_or_else(|| { 100 | WeatherError::JsonError(io::Error::new( 101 | io::ErrorKind::Other, 102 | "first row missig", 103 | )) 104 | }) 105 | }) 106 | .and_then(|value| { 107 | serde_json::from_value::(value).map_err(|err| { 108 | WeatherError::JsonError(io::Error::new(io::ErrorKind::Other, err)) 109 | }) 110 | }) 111 | }) 112 | } 113 | } 114 | --------------------------------------------------------------------------------