Initial commit
commit
6e89c60a19
|
@ -0,0 +1 @@
|
|||
Cargo.lock -diff
|
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
/config.toml
|
|
@ -0,0 +1,674 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb41d85d92dfab96cb95ab023c265c5e4261bb956c0fb49ca06d90c570f1958"
|
||||
dependencies = [
|
||||
"argh_derive",
|
||||
"argh_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh_derive"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be69f70ef5497dd6ab331a50bd95c6ac6b8f7f17a7967838332743fbd58dc3b5"
|
||||
dependencies = [
|
||||
"argh_shared",
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh_shared"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6f8c380fa28aa1b36107cd97f0196474bb7241bb95a453c5c01a15ac74b2eac"
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cache-padded"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3"
|
||||
dependencies = [
|
||||
"cache-padded",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
|
||||
|
||||
[[package]]
|
||||
name = "figment"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "790b4292c72618abbab50f787a477014fe15634f96291de45672ce46afe122df"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
"serde",
|
||||
"toml",
|
||||
"uncased",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"match_cfg",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "match_cfg"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "mqttdpms"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"argh",
|
||||
"dirs",
|
||||
"env_logger",
|
||||
"figment",
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"hostname",
|
||||
"log",
|
||||
"paho-mqtt",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"x11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paho-mqtt"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fac58bae33ba9679bb4908ffa7c3950114345860d3f9b98340c4943f18ff324"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"crossbeam-channel",
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"libc",
|
||||
"log",
|
||||
"paho-mqtt-sys",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paho-mqtt-sys"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10e6244f27644eed5709e318a3ad7f785906fbb6030f0a9b9ba50923b456c0c5"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.137"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uncased"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "x11"
|
||||
version = "2.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dd0565fa8bfba8c5efe02725b14dff114c866724eff2cfd44d76cea74bcd87a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
|
@ -0,0 +1,27 @@
|
|||
[package]
|
||||
name = "mqttdpms"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
argh = "^0.1"
|
||||
dirs = "^4.0"
|
||||
env_logger = "^0.9.0"
|
||||
futures = "^0.3.21"
|
||||
futures-timer = "^3.0.2"
|
||||
hostname = "^0.3.1"
|
||||
log = "^0.4.17"
|
||||
paho-mqtt = "^0.11.1"
|
||||
serde_json = "^1.0"
|
||||
|
||||
[dependencies.figment]
|
||||
version = "^0.10.6"
|
||||
features = ["toml"]
|
||||
|
||||
[dependencies.serde]
|
||||
version = "^1.0"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.x11]
|
||||
version = "^2.19.1"
|
||||
features = ["dpms", "xlib"]
|
|
@ -0,0 +1 @@
|
|||
max_width = 79
|
|
@ -0,0 +1,139 @@
|
|||
use std::fmt;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use figment::providers::Format;
|
||||
use figment::Figment;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::util;
|
||||
|
||||
const TLS_CA_BUNDLE: &str =
|
||||
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ConfigError {
|
||||
Io(io::Error),
|
||||
Invalid(figment::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for ConfigError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Io(e) => write!(f, "{}", e),
|
||||
Self::Invalid(e) => write!(f, "{}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for ConfigError {
|
||||
fn from(error: io::Error) -> Self {
|
||||
Self::Io(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<figment::Error> for ConfigError {
|
||||
fn from(error: figment::Error) -> Self {
|
||||
Self::Invalid(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct MqttTopicConfig {
|
||||
pub availability: String,
|
||||
pub config: String,
|
||||
pub state: String,
|
||||
pub command: String,
|
||||
}
|
||||
|
||||
impl Default for MqttTopicConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
availability: default_availability_topic(),
|
||||
config: default_config_topic(),
|
||||
state: default_state_topic(),
|
||||
command: default_command_topic(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct MqttConfiguration {
|
||||
#[serde(default = "default_mqtt_host")]
|
||||
pub host: String,
|
||||
#[serde(default = "default_mqtt_port")]
|
||||
pub port: u16,
|
||||
#[serde(default)]
|
||||
pub tls: bool,
|
||||
#[serde(default = "default_mqtt_ca_file")]
|
||||
pub ca_file: String,
|
||||
#[serde(default)]
|
||||
pub username: Option<String>,
|
||||
#[serde(default)]
|
||||
pub password: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for MqttConfiguration {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
host: default_mqtt_host(),
|
||||
port: default_mqtt_port(),
|
||||
tls: false,
|
||||
ca_file: default_mqtt_ca_file(),
|
||||
username: None,
|
||||
password: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Configuration {
|
||||
#[serde(default = "default_unique_id")]
|
||||
pub name: String,
|
||||
#[serde(default = "default_unique_id")]
|
||||
pub unique_id: String,
|
||||
#[serde(default)]
|
||||
pub mqtt: MqttConfiguration,
|
||||
#[serde(default)]
|
||||
pub topics: MqttTopicConfig,
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, ConfigError> {
|
||||
let figment = Figment::new()
|
||||
.merge(figment::providers::Toml::file(path.as_ref()));
|
||||
Ok(figment.extract()?)
|
||||
}
|
||||
}
|
||||
|
||||
fn default_unique_id() -> String {
|
||||
util::hostname()
|
||||
}
|
||||
|
||||
fn default_mqtt_host() -> String {
|
||||
"localhost".into()
|
||||
}
|
||||
|
||||
fn default_mqtt_port() -> u16 {
|
||||
1883
|
||||
}
|
||||
|
||||
fn default_mqtt_ca_file() -> String {
|
||||
TLS_CA_BUNDLE.into()
|
||||
}
|
||||
|
||||
fn default_availability_topic() -> String {
|
||||
"mqttdpms/@UNIQUEID@/available".into()
|
||||
}
|
||||
|
||||
fn default_config_topic() -> String {
|
||||
"homeassistant/switch/dpms_@UNIQUEID@/config".into()
|
||||
}
|
||||
|
||||
fn default_state_topic() -> String {
|
||||
"mqttdpms/@UNIQUEID@/state".into()
|
||||
}
|
||||
|
||||
fn default_command_topic() -> String {
|
||||
"mqttdpms/@UNIQUEID@/command".into()
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
#![allow(dead_code)]
|
||||
use std::ffi::CStr;
|
||||
|
||||
use x11::dpms::{
|
||||
DPMSCapable, DPMSDisable, DPMSEnable, DPMSForceLevel, DPMSGetTimeouts,
|
||||
DPMSInfo, DPMSQueryExtension,
|
||||
};
|
||||
use x11::dpms::{DPMSModeOff, DPMSModeOn, DPMSModeStandby, DPMSModeSuspend};
|
||||
use x11::xlib::{XCloseDisplay, XDisplayName, XOpenDisplay, _XDisplay};
|
||||
use x11::xmd::{BOOL, CARD16};
|
||||
|
||||
/// Error returned if connecting to the X server fails
|
||||
#[derive(Debug)]
|
||||
pub struct OpenDisplayError;
|
||||
|
||||
/// Wrapper for an X display pointer
|
||||
pub struct Display {
|
||||
display: *mut _XDisplay,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
/// Open a connection to the X server
|
||||
///
|
||||
/// If the connection succeeds, a [`Display`] is returned. Otherwise, an
|
||||
/// [`OpenDisplayError`] is returned.
|
||||
pub fn open() -> Result<Self, OpenDisplayError> {
|
||||
let display = unsafe { XOpenDisplay(std::ptr::null()) };
|
||||
if display.is_null() {
|
||||
Err(OpenDisplayError)
|
||||
} else {
|
||||
Ok(Self { display })
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the name of the X server display
|
||||
///
|
||||
/// If the display name cannot be determined, an empty string is returned.
|
||||
pub fn name() -> String {
|
||||
let name = unsafe { CStr::from_ptr(XDisplayName(std::ptr::null())) };
|
||||
let name = name.to_str().unwrap_or("");
|
||||
String::from(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Display {
|
||||
fn drop(&mut self) {
|
||||
unsafe { XCloseDisplay(self.display) };
|
||||
}
|
||||
}
|
||||
|
||||
/// DPMS Power Level
|
||||
///
|
||||
/// There are four power levels specified by the Video Electronics Standards
|
||||
/// Association (VESA) Display Power Management Signaling (DPMS) standard.
|
||||
/// These are mapped onto the X DPMS Extension
|
||||
#[derive(PartialEq)]
|
||||
pub enum DpmsPowerLevel {
|
||||
/// In use
|
||||
On = DPMSModeOn as isize,
|
||||
/// Blanked, low power
|
||||
Standby = DPMSModeStandby as isize,
|
||||
/// Blanked, lower power
|
||||
Suspend = DPMSModeSuspend as isize,
|
||||
/// Shut off, awaiting activity
|
||||
Off = DPMSModeOff as isize,
|
||||
Unknown = -1,
|
||||
}
|
||||
|
||||
impl From<u16> for DpmsPowerLevel {
|
||||
fn from(v: u16) -> Self {
|
||||
#[allow(non_snake_case)]
|
||||
match v {
|
||||
x if x == DpmsPowerLevel::On as u16 => Self::On,
|
||||
x if x == DpmsPowerLevel::Standby as u16 => Self::Standby,
|
||||
x if x == DpmsPowerLevel::Suspend as u16 => Self::Suspend,
|
||||
x if x == DpmsPowerLevel::Off as u16 => Self::Off,
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Result from [`get_info`] function (`DPMSInfo`)
|
||||
pub struct DpmsInfo {
|
||||
/// Current power level
|
||||
pub power_level: DpmsPowerLevel,
|
||||
/// DPMS enabled/disabled state
|
||||
pub state: bool,
|
||||
}
|
||||
|
||||
/// Result from [`get_timeouts`] function (`DPMSGetTimeouts`)
|
||||
pub struct DpmsTimeouts {
|
||||
/// Amount of time of inactivity in seconds before standby mode is invoked
|
||||
pub standby: u16,
|
||||
/// Amount of time of inactivity in seconds before the second level of power
|
||||
/// savings is invoked
|
||||
pub suspend: u16,
|
||||
/// Amount of time of inactivity in seconds before the third and final level
|
||||
/// of power savings is invoked
|
||||
pub off: u16,
|
||||
}
|
||||
|
||||
/// Queries the X server to determine the availability of the DPMS Extension
|
||||
pub fn query_extension(display: &Display) -> bool {
|
||||
let mut event_base = 0;
|
||||
let mut error_base = 0;
|
||||
let r = unsafe {
|
||||
DPMSQueryExtension(display.display, &mut event_base, &mut error_base)
|
||||
};
|
||||
r != 0
|
||||
}
|
||||
|
||||
/// Returns the DPMS capability of the X server, either TRUE (capable of DPMS)
|
||||
/// or FALSE (incapable of DPMS)
|
||||
pub fn dpms_capable(display: &Display) -> bool {
|
||||
let r = unsafe { DPMSCapable(display.display) };
|
||||
r != 0
|
||||
}
|
||||
|
||||
/// Returns information about the current DPMS state
|
||||
pub fn get_info(display: &Display) -> DpmsInfo {
|
||||
let mut power_level: CARD16 = 0;
|
||||
let mut state: BOOL = 0;
|
||||
unsafe { DPMSInfo(display.display, &mut power_level, &mut state) };
|
||||
DpmsInfo {
|
||||
power_level: power_level.into(),
|
||||
state: state != 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves the timeout values used by the X server for DPMS timings
|
||||
pub fn get_timeouts(display: &Display) -> DpmsTimeouts {
|
||||
let mut standby: CARD16 = 0;
|
||||
let mut suspend: CARD16 = 0;
|
||||
let mut off: CARD16 = 0;
|
||||
unsafe {
|
||||
DPMSGetTimeouts(display.display, &mut standby, &mut suspend, &mut off)
|
||||
};
|
||||
DpmsTimeouts {
|
||||
standby,
|
||||
suspend,
|
||||
off,
|
||||
}
|
||||
}
|
||||
|
||||
/// Forces a DPMS capable display into the specified power level
|
||||
pub fn force_level(display: &Display, level: DpmsPowerLevel) -> bool {
|
||||
let r = unsafe { DPMSForceLevel(display.display, level as u16) };
|
||||
r != 0
|
||||
}
|
||||
|
||||
/// Enables DPMS on the specified display
|
||||
pub fn enable(display: &Display) -> bool {
|
||||
let r = unsafe { DPMSEnable(display.display) };
|
||||
r != 0
|
||||
}
|
||||
|
||||
/// Disables DPMS on the specified display
|
||||
pub fn disable(display: &Display) -> bool {
|
||||
let r = unsafe { DPMSDisable(display.display) };
|
||||
r != 0
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
use std::fmt;
|
||||
|
||||
use paho_mqtt as mqtt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MqttDpmsError {
|
||||
Mqtt(mqtt::Error),
|
||||
Json(serde_json::Error),
|
||||
}
|
||||
|
||||
impl From<serde_json::Error> for MqttDpmsError {
|
||||
fn from(e: serde_json::Error) -> Self {
|
||||
Self::Json(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<mqtt::Error> for MqttDpmsError {
|
||||
fn from(e: mqtt::Error) -> Self {
|
||||
Self::Mqtt(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MqttDpmsError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Mqtt(e) => write!(f, "MQTT error: {}", e),
|
||||
Self::Json(e) => write!(f, "JSON de/serialization error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
mod config;
|
||||
mod dpms;
|
||||
mod error;
|
||||
mod mqttdpms;
|
||||
mod util;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use argh::FromArgs;
|
||||
use env_logger;
|
||||
use futures::executor::block_on;
|
||||
use log::{debug, error};
|
||||
|
||||
#[derive(FromArgs)]
|
||||
#[argh(description = "MQTT DPMS")]
|
||||
struct Arguments {
|
||||
/// path to configuration
|
||||
#[argh(option, default = "default_config_path()")]
|
||||
config: PathBuf,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Arguments = argh::from_env();
|
||||
env_logger::init();
|
||||
let config = match config::Configuration::load(args.config) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
eprintln!("Failed to load configuration file: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
debug!("Configuration: {:?}", config);
|
||||
|
||||
let mqttdpms = mqttdpms::MqttDpms::new(config);
|
||||
|
||||
if let Err(e) = block_on(async move { mqttdpms.run().await }) {
|
||||
eprintln!("{}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn default_config_path() -> PathBuf {
|
||||
let mut path = match dirs::config_dir() {
|
||||
Some(mut d) => {
|
||||
d.push(env!("CARGO_PKG_NAME"));
|
||||
d
|
||||
}
|
||||
None => match std::env::current_dir() {
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
error!("Could not get current working directory: {}", e);
|
||||
"/".into()
|
||||
}
|
||||
},
|
||||
};
|
||||
path.push("config.toml");
|
||||
path
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
use futures::stream::StreamExt;
|
||||
use log::{debug, error, info, warn};
|
||||
use paho_mqtt as mqtt;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::config::Configuration;
|
||||
use crate::dpms;
|
||||
use crate::error::MqttDpmsError;
|
||||
use crate::util;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct HassDevice {
|
||||
identifiers: Vec<String>,
|
||||
manufacturer: String,
|
||||
model: String,
|
||||
name: String,
|
||||
sw_version: String,
|
||||
}
|
||||
|
||||
impl Default for HassDevice {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
identifiers: vec![util::hostname()],
|
||||
manufacturer: "Dustin C. Hatch".into(),
|
||||
model: env!("CARGO_PKG_VERSION").into(),
|
||||
name: "MQTT DPMS".into(),
|
||||
sw_version: env!("CARGO_PKG_VERSION").into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct HassConfig {
|
||||
availability_topic: String,
|
||||
command_topic: String,
|
||||
device: HassDevice,
|
||||
name: String,
|
||||
state_topic: String,
|
||||
unique_id: String,
|
||||
icon: String,
|
||||
}
|
||||
|
||||
impl HassConfig {
|
||||
pub fn from_config(config: &Configuration) -> Self {
|
||||
let unique_id = &config.unique_id;
|
||||
let availability_topic =
|
||||
config.topics.availability.replace("@UNIQUEID@", &unique_id);
|
||||
let command_topic =
|
||||
config.topics.command.replace("@UNIQUEID@", &unique_id);
|
||||
let state_topic =
|
||||
config.topics.state.replace("@UNIQUEID@", &unique_id);
|
||||
Self {
|
||||
availability_topic,
|
||||
command_topic,
|
||||
device: Default::default(),
|
||||
icon: "mdi:monitor".into(),
|
||||
name: config.name.clone(),
|
||||
state_topic,
|
||||
unique_id: format!("switch.dpms_{}", unique_id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MqttDpms {
|
||||
config: Configuration,
|
||||
}
|
||||
|
||||
impl MqttDpms {
|
||||
pub fn new(config: Configuration) -> Self {
|
||||
Self { config }
|
||||
}
|
||||
|
||||
pub async fn run(self) -> Result<(), MqttDpmsError> {
|
||||
let uri = format!(
|
||||
"{}://{}:{}",
|
||||
if self.config.mqtt.tls { "ssl" } else { "tcp" },
|
||||
self.config.mqtt.host,
|
||||
self.config.mqtt.port
|
||||
);
|
||||
info!("Connecting to MQTT server {}", uri);
|
||||
let client_opts =
|
||||
mqtt::CreateOptionsBuilder::new().server_uri(uri).finalize();
|
||||
let mut client = mqtt::AsyncClient::new(client_opts)?;
|
||||
let mut conn_opts = mqtt::ConnectOptionsBuilder::new();
|
||||
conn_opts.will_message(self.will_message());
|
||||
if self.config.mqtt.tls {
|
||||
let ssl_opts = mqtt::SslOptionsBuilder::new()
|
||||
.trust_store(&self.config.mqtt.ca_file)?
|
||||
.finalize();
|
||||
conn_opts.ssl_options(ssl_opts);
|
||||
}
|
||||
if let [Some(username), Some(password)] =
|
||||
[&self.config.mqtt.username, &self.config.mqtt.password]
|
||||
{
|
||||
conn_opts.user_name(username).password(password);
|
||||
}
|
||||
|
||||
let mut stream = client.get_stream(10);
|
||||
client.connect(conn_opts.finalize()).await?;
|
||||
info!("Successfully connected to MQTT broker");
|
||||
|
||||
let cmd_topic = self
|
||||
.config
|
||||
.topics
|
||||
.command
|
||||
.replace("@UNIQUEID@", &self.config.unique_id);
|
||||
info!("Subscribing to command topic {}", cmd_topic);
|
||||
client.subscribe(cmd_topic, 0).await?;
|
||||
self.publish_config(&client).await?;
|
||||
self.publish_online(&client).await?;
|
||||
self.publish_state(&client).await?;
|
||||
|
||||
while let Some(msg) = stream.next().await {
|
||||
if let Some(msg) = msg {
|
||||
debug!("Got message {:?}", msg);
|
||||
match msg.payload_str().as_ref() {
|
||||
"ON" => {
|
||||
self.turn_on();
|
||||
self.publish_state(&client).await?;
|
||||
}
|
||||
"OFF" => {
|
||||
self.turn_off();
|
||||
self.publish_state(&client).await?;
|
||||
}
|
||||
other => {
|
||||
warn!("Unexpected command message: {}", other);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn publish_config(
|
||||
&self,
|
||||
client: &mqtt::AsyncClient,
|
||||
) -> Result<(), MqttDpmsError> {
|
||||
let topic = self
|
||||
.config
|
||||
.topics
|
||||
.config
|
||||
.replace("@UNIQUEID@", &self.config.unique_id);
|
||||
let config = HassConfig::from_config(&self.config);
|
||||
let payload = serde_json::to_string(&config)?;
|
||||
let message = mqtt::Message::new_retained(topic, payload, 0);
|
||||
Ok(client.publish(message).await?)
|
||||
}
|
||||
|
||||
async fn publish_state(
|
||||
&self,
|
||||
client: &mqtt::AsyncClient,
|
||||
) -> Result<(), MqttDpmsError> {
|
||||
let topic = self
|
||||
.config
|
||||
.topics
|
||||
.state
|
||||
.replace("@UNIQUEID@", &self.config.unique_id);
|
||||
let state = if is_screen_on() { "ON" } else { "OFF" };
|
||||
let message = mqtt::Message::new_retained(topic, state, 0);
|
||||
Ok(client.publish(message).await?)
|
||||
}
|
||||
|
||||
async fn publish_online(
|
||||
&self,
|
||||
client: &mqtt::AsyncClient,
|
||||
) -> Result<(), MqttDpmsError> {
|
||||
let topic = self
|
||||
.config
|
||||
.topics
|
||||
.availability
|
||||
.replace("@UNIQUEID@", &self.config.unique_id);
|
||||
let message = mqtt::Message::new(topic, "online", 0);
|
||||
Ok(client.publish(message).await?)
|
||||
}
|
||||
|
||||
fn turn_off(&self) {
|
||||
info!("Turning off display");
|
||||
let display = match dpms::Display::open() {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
error!("unable to open display \"{}\"", dpms::Display::name());
|
||||
return;
|
||||
}
|
||||
};
|
||||
if !dpms::enable(&display) {
|
||||
error!(
|
||||
"Failed to enable DPMS on display \"{}\"",
|
||||
dpms::Display::name()
|
||||
);
|
||||
}
|
||||
if !dpms::force_level(&display, dpms::DpmsPowerLevel::Off) {
|
||||
error!("Failed to turn off display \"{}\"", dpms::Display::name());
|
||||
}
|
||||
}
|
||||
|
||||
fn turn_on(&self) {
|
||||
info!("Turning on display");
|
||||
let display = match dpms::Display::open() {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
error!("unable to open display \"{}\"", dpms::Display::name());
|
||||
return;
|
||||
}
|
||||
};
|
||||
if !dpms::force_level(&display, dpms::DpmsPowerLevel::On) {
|
||||
error!("Failed to turn on display \"{}\"", dpms::Display::name());
|
||||
}
|
||||
if !dpms::disable(&display) {
|
||||
error!(
|
||||
"Failed to disable DPMS on display \"{}\"",
|
||||
dpms::Display::name()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn will_message(&self) -> mqtt::Message {
|
||||
let avail_topic = self
|
||||
.config
|
||||
.topics
|
||||
.availability
|
||||
.replace("@UNIQUEID@", &self.config.unique_id);
|
||||
mqtt::Message::new_retained(avail_topic, "offline", 0)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_screen_on() -> bool {
|
||||
let display = match dpms::Display::open() {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
error!("unable to open display \"{}\"", dpms::Display::name());
|
||||
return false;
|
||||
}
|
||||
};
|
||||
if dpms::query_extension(&display) {
|
||||
if dpms::dpms_capable(&display) {
|
||||
let info = dpms::get_info(&display);
|
||||
if info.state {
|
||||
if info.power_level != dpms::DpmsPowerLevel::On {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
pub fn hostname() -> String {
|
||||
if let Ok(h) = hostname::get() {
|
||||
if let Some(h) = h.to_str() {
|
||||
if let Some((h, _)) = h.split_once('.') {
|
||||
return h.into();
|
||||
};
|
||||
};
|
||||
};
|
||||
"localhost".into()
|
||||
}
|
Loading…
Reference in New Issue