From e603699e45e2c1498d6bf76492887a61c49f2656 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Fri, 31 Jul 2020 00:35:51 -0500 Subject: [PATCH 1/3] Implement get/set time during camera connect --- Cargo.lock | 266 ++++++++++++++++++++++++++++++++++++---- Cargo.toml | 1 + src/bc/model.rs | 2 + src/bc/xml.rs | 35 ++++++ src/bc_protocol.rs | 1 + src/bc_protocol/time.rs | 132 ++++++++++++++++++++ src/main.rs | 27 +++- 7 files changed, 438 insertions(+), 26 deletions(-) create mode 100644 src/bc_protocol/time.rs diff --git a/Cargo.lock b/Cargo.lock index 9a3ec9bc..5b07409f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,12 +41,24 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +[[package]] +name = "base-x" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bumpalo" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" + [[package]] name = "cfg-if" version = "0.1.10" @@ -90,12 +102,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" +checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" dependencies = [ + "cfg-if", "crossbeam-utils", - "maybe-uninit", ] [[package]] @@ -146,6 +158,18 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" + [[package]] name = "env_logger" version = "0.7.1" @@ -558,9 +582,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] @@ -614,6 +638,15 @@ dependencies = [ "unindent", ] +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.6" @@ -641,15 +674,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.71" +version = "0.2.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if", ] @@ -701,12 +734,14 @@ dependencies = [ "crossbeam", "env_logger", "err-derive", + "gio", "glib", "gstreamer", "gstreamer-app", "gstreamer-rtsp", "gstreamer-rtsp-server", "indoc", + "itertools", "lazy_static", "log", "md5", @@ -715,6 +750,7 @@ dependencies = [ "serde", "socket2", "structopt", + "time", "toml", "validator", "validator_derive", @@ -797,18 +833,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" +checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" +checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" dependencies = [ "proc-macro2", "quote", @@ -823,9 +859,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" [[package]] name = "proc-macro-error" @@ -855,9 +891,9 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.16" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" +checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" [[package]] name = "proc-macro-nested" @@ -867,9 +903,9 @@ checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" dependencies = [ "unicode-xid", ] @@ -891,9 +927,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "regex" @@ -913,6 +949,15 @@ version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.3" @@ -936,6 +981,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + [[package]] name = "serde" version = "1.0.114" @@ -958,15 +1018,21 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + [[package]] name = "slab" version = "0.4.2" @@ -985,12 +1051,70 @@ dependencies = [ "winapi", ] +[[package]] +name = "standback" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0437cfb83762844799a60e1e3b489d5ceb6a650fbacb86437badc1b6d87b246" +dependencies = [ + "version_check", +] + [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + [[package]] name = "strsim" version = "0.8.0" @@ -1023,9 +1147,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" +checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" dependencies = [ "proc-macro2", "quote", @@ -1082,6 +1206,44 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "time" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a51cadc5b1eec673a685ff7c33192ff7b7603d0b75446fb354939ee615acb15" +dependencies = [ + "cfg-if", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9b6e9f095bc105e183e3cd493d72579be3181ad4004fceb01adbe9eecab2d" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + [[package]] name = "tinyvec" version = "0.3.3" @@ -1192,6 +1354,60 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +[[package]] +name = "wasm-bindgen" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 66100623..ff4a3f73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ regex = "1" serde = { version = "1.0", features = ["derive"] } socket2 = "0.3" structopt = "0.3" +time = "0.2" toml = "0.5" yaserde = "0.3.16" yaserde_derive = "0.3.16" diff --git a/src/bc/model.rs b/src/bc/model.rs index e6c31155..a94da36a 100644 --- a/src/bc/model.rs +++ b/src/bc/model.rs @@ -6,6 +6,8 @@ pub(super) const MAGIC_HEADER: u32 = 0xabcdef0; pub const MSG_ID_LOGIN: u32 = 1; pub const MSG_ID_VIDEO: u32 = 3; pub const MSG_ID_PING: u32 = 93; +pub const MSG_ID_GET_GENERAL: u32 = 104; +pub const MSG_ID_SET_GENERAL: u32 = 105; pub const EMPTY_LEGACY_PASSWORD: &str = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; diff --git a/src/bc/xml.rs b/src/bc/xml.rs index d1fc0150..727ae685 100644 --- a/src/bc/xml.rs +++ b/src/bc/xml.rs @@ -37,6 +37,10 @@ pub struct BcXml { pub device_info: Option, #[yaserde(rename = "Preview")] pub preview: Option, + #[yaserde(rename = "SystemGeneral")] + pub system_general: Option, + #[yaserde(rename = "Norm")] + pub norm: Option, } impl AllTopXmls { @@ -125,6 +129,37 @@ pub struct Extension { pub binary_data: u32, } +#[derive(PartialEq, Eq, Default, Debug, YaDeserialize, YaSerialize)] +pub struct SystemGeneral { + #[yaserde(attribute)] + pub version: String, + + #[yaserde(rename = "timeZone")] + pub time_zone: Option, + pub year: Option, + pub month: Option, + pub day: Option, + pub hour: Option, + pub minute: Option, + pub second: Option, + + #[yaserde(rename = "osdFormat")] + pub osd_format: Option, + #[yaserde(rename = "timeFormat")] + pub time_format: Option, + + pub language: Option, + #[yaserde(rename = "deviceName")] + pub device_name: Option, +} + +#[derive(PartialEq, Eq, Default, Debug, YaDeserialize, YaSerialize)] +pub struct Norm { + #[yaserde(attribute)] + pub version: String, + norm: String, +} + pub fn xml_ver() -> String { "1.1".to_string() } diff --git a/src/bc_protocol.rs b/src/bc_protocol.rs index ed2029bb..2c53659d 100644 --- a/src/bc_protocol.rs +++ b/src/bc_protocol.rs @@ -11,6 +11,7 @@ use std::time::Duration; use Md5Trunc::*; mod connection; +mod time; pub struct BcCamera { address: SocketAddr, diff --git a/src/bc_protocol/time.rs b/src/bc_protocol/time.rs new file mode 100644 index 00000000..32e98702 --- /dev/null +++ b/src/bc_protocol/time.rs @@ -0,0 +1,132 @@ +use super::{BcCamera, Error, Result}; +use crate::bc::{model::*, xml::*}; +use time::{date, Date, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset}; + +impl BcCamera { + pub fn get_time(&self) -> Result> { + let connection = self + .connection + .as_ref() + .expect("Must be connected to get time"); + let sub_get_general = connection.subscribe(MSG_ID_GET_GENERAL)?; + let get = Bc { + meta: BcMeta { + msg_id: MSG_ID_GET_GENERAL, + client_idx: 0, + encrypted: true, + class: 0x6414, + }, + body: BcBody::ModernMsg(ModernMsg::default()), + }; + + sub_get_general.send(get)?; + let msg = sub_get_general.rx.recv_timeout(self.rx_timeout)?; + + if let BcBody::ModernMsg(ModernMsg { + xml: + Some(BcXml { + system_general: + Some(SystemGeneral { + time_zone: Some(time_zone), + year: Some(year), + month: Some(month), + day: Some(day), + hour: Some(hour), + minute: Some(minute), + second: Some(second), + .. + }), + .. + }), + .. + }) = msg.body + { + let datetime = match try_build_timestamp( + time_zone, year, month, day, hour, minute, second + ) { + Ok(dt) => dt, + Err(e) => return Err(Error::UnintelligibleReply { + reply: msg, + why: "Could not parse date", + }) + }; + + // This code was written in 2020; I'm trying to catch all the possible epochs that + // cameras might reset themselves to. My B800 resets to Jan 1, 1999, but I can't + // guarantee that Reolink won't pick some newer date. Therefore, last year ought + // to be new enough, yet still distant enough that it won't interfere with anything + const BOUNDARY: Date = date!(2019-01-01); + + // detect if no time is actually set, and return Ok(None): that is, operation + // succeeded, and there is no time set + if datetime.date() < BOUNDARY { + Ok(None) + } else { + Ok(Some(datetime)) + } + } else { + Err(Error::UnintelligibleReply { + reply: msg, + why: "Reply did not contain SystemGeneral with all time fields filled out", + }) + } + } + + pub fn set_time(&self, timestamp: OffsetDateTime) -> Result<()> { + let connection = self + .connection + .as_ref() + .expect("Must be connected to set time"); + let sub_set_general = connection.subscribe(MSG_ID_SET_GENERAL)?; + let set = Bc::new_from_xml( + BcMeta { + msg_id: MSG_ID_SET_GENERAL, + client_idx: 0, + encrypted: true, + class: 0x6414, + }, + BcXml { + system_general: Some(SystemGeneral { + version: xml_ver(), + //osd_format: Some("MDY".to_string()), + time_format: Some(0), + // Reolink uses positive seconds to indicate a negative UTC offset: + time_zone: Some(-timestamp.offset().as_seconds()), + year: Some(timestamp.year()), + month: Some(timestamp.month()), + day: Some(timestamp.day()), + hour: Some(timestamp.hour()), + minute: Some(timestamp.minute()), + second: Some(timestamp.second()), + ..Default::default() + }), + ..Default::default() + }, + ); + + sub_set_general.send(set)?; + let msg = sub_set_general.rx.recv_timeout(self.rx_timeout)?; + + Ok(()) + } +} + +fn try_build_timestamp( + timezone: i32, + year: i32, + month: u8, + day: u8, + hour: u8, + minute: u8, + second: u8, +) -> std::result::Result { + let date = Date::try_from_ymd(year, month, day)?; + let time = Time::try_from_hms(hour, minute, second)?; + let offset = if timezone > 0 { + UtcOffset::west_seconds(timezone as u32) + } else { + UtcOffset::east_seconds(-timezone as u32) + }; + + Ok(PrimitiveDateTime::new(date, time).assume_offset(offset)) +} diff --git a/src/main.rs b/src/main.rs index 453f1f38..5ddae65c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -208,9 +208,34 @@ fn camera_main( camera.login(&camera_config.username, camera_config.password.as_deref())?; connected = true; + info!("{}: Connected and logged in", camera_config.name); + + let cam_time = camera.get_time()?; + if let Some(time) = cam_time { + info!( + "{}: Camera time is already set: {}", + camera_config.name, time + ); + } else { + let new_time = time::OffsetDateTime::now_local(); + warn!( + "{}: Camera has no time set, setting to {}", + camera_config.name, new_time + ); + camera.set_time(new_time)?; + let cam_time = camera.get_time()?; + if let Some(time) = cam_time { + info!( + "{}: Camera time is now set: {}", + camera_config.name, time + ); + } else { + error!("{}: Camera did not accept new time", camera_config.name); + } + } info!( - "{}: Connected to camera, starting video stream {}", + "{}: Starting video stream {}", camera_config.name, stream_name ); camera.start_video(output, stream_name) From 051887a7c37ff730f17605e23cdc102f1373bcd3 Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Fri, 31 Jul 2020 00:40:43 -0500 Subject: [PATCH 2/3] Bump timeout to 5 seconds and remove config option This, combined with auto time set, should completely fix #14. --- ...etting Up Neolink For Use With Blue Iris.md | 12 +----------- src/bc_protocol.rs | 18 +++++++----------- src/bc_protocol/time.rs | 6 +++--- src/config.rs | 1 + src/main.rs | 5 +++-- 5 files changed, 15 insertions(+), 27 deletions(-) diff --git a/docs/Setting Up Neolink For Use With Blue Iris.md b/docs/Setting Up Neolink For Use With Blue Iris.md index da9fe39c..f029eddf 100644 --- a/docs/Setting Up Neolink For Use With Blue Iris.md +++ b/docs/Setting Up Neolink For Use With Blue Iris.md @@ -31,17 +31,7 @@ _This is the most reliable setup since Neolink cannot autodetect when a camera's _You will have to reconnect to the camera once you have changed the IP address_ -### 3. Set the camera's time to your local network time and disable Auto Reboot -_When a camera reboots, it loses its date and time settings. If the camera's time is not set, Neolink will recursively "time out" every one second and will not stream video. Setting the time and disabling auto reboot on the camera is a workaround for [issue #14](https://github.com/thirtythreeforty/neolink/issues/14)._ -1. In the Reolink PC app, login to your camera. -2. Click "Device Settings" -> "System General" -> "Synchronize Local Time." -3. Click "Ok." - -4. Click "Device Settings" -> "Maintenance." - -5. Uncheck "Enable Auto Reboot." - -### 4. Set a Password +### 3. Set a Password _It's recommended that you set a password for each of your cameras. If you want to use the Reolink Mobile App, it makes you set a password for each camera anyway._ 1. In the Reolink PC app, login to your camera. 2. Click "Device Settings" -> "Manage User." diff --git a/src/bc_protocol.rs b/src/bc_protocol.rs index 2c53659d..6803b3fb 100644 --- a/src/bc_protocol.rs +++ b/src/bc_protocol.rs @@ -17,13 +17,14 @@ pub struct BcCamera { address: SocketAddr, connection: Option, logged_in: bool, - rx_timeout: Duration, } use crate::Never; type Result = std::result::Result; +const RX_TIMEOUT: Duration = Duration::from_secs(5); + #[derive(Debug, Error)] pub enum Error { #[error(display = "Communication error")] @@ -71,16 +72,11 @@ impl BcCamera { address, connection: None, logged_in: false, - rx_timeout: Duration::from_secs(1), }) } - pub fn set_rx_timeout(&mut self, timeout: Duration) { - self.rx_timeout = timeout; - } - pub fn connect(&mut self) -> Result<()> { - self.connection = Some(BcConnection::new(self.address, self.rx_timeout)?); + self.connection = Some(BcConnection::new(self.address, RX_TIMEOUT)?); Ok(()) } @@ -127,7 +123,7 @@ impl BcCamera { sub_login.send(legacy_login)?; - let legacy_reply = sub_login.rx.recv_timeout(self.rx_timeout)?; + let legacy_reply = sub_login.rx.recv_timeout(RX_TIMEOUT)?; let nonce; match legacy_reply.body { BcBody::ModernMsg(ModernMsg { @@ -181,7 +177,7 @@ impl BcCamera { ); sub_login.send(modern_login)?; - let modern_reply = sub_login.rx.recv_timeout(self.rx_timeout)?; + let modern_reply = sub_login.rx.recv_timeout(RX_TIMEOUT)?; let device_info; match modern_reply.body { @@ -238,7 +234,7 @@ impl BcCamera { sub_ping.send(ping)?; - sub_ping.rx.recv_timeout(self.rx_timeout)?; + sub_ping.rx.recv_timeout(RX_TIMEOUT)?; Ok(()) } @@ -272,7 +268,7 @@ impl BcCamera { loop { trace!("Getting video message..."); - let msg = sub_video.rx.recv_timeout(self.rx_timeout)?; + let msg = sub_video.rx.recv_timeout(RX_TIMEOUT)?; if let BcBody::ModernMsg(ModernMsg { binary: Some(binary), .. diff --git a/src/bc_protocol/time.rs b/src/bc_protocol/time.rs index 32e98702..7b97c20e 100644 --- a/src/bc_protocol/time.rs +++ b/src/bc_protocol/time.rs @@ -1,4 +1,4 @@ -use super::{BcCamera, Error, Result}; +use super::{BcCamera, Error, Result, RX_TIMEOUT}; use crate::bc::{model::*, xml::*}; use time::{date, Date, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset}; @@ -20,7 +20,7 @@ impl BcCamera { }; sub_get_general.send(get)?; - let msg = sub_get_general.rx.recv_timeout(self.rx_timeout)?; + let msg = sub_get_general.rx.recv_timeout(RX_TIMEOUT)?; if let BcBody::ModernMsg(ModernMsg { xml: @@ -105,7 +105,7 @@ impl BcCamera { ); sub_set_general.send(set)?; - let msg = sub_set_general.rx.recv_timeout(self.rx_timeout)?; + let msg = sub_set_general.rx.recv_timeout(RX_TIMEOUT)?; Ok(()) } diff --git a/src/config.rs b/src/config.rs index af9bb60b..293be361 100644 --- a/src/config.rs +++ b/src/config.rs @@ -51,6 +51,7 @@ pub struct CameraConfig { pub username: String, pub password: Option, + // no longer used, but still here so we can warn users: pub timeout: Option, #[validate(regex( diff --git a/src/main.rs b/src/main.rs index 5ddae65c..6e79a71e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -195,8 +195,9 @@ fn camera_main( let mut connected = false; (|| { let mut camera = BcCamera::new_with_addr(camera_config.camera_addr)?; - if let Some(timeout) = camera_config.timeout { - camera.set_rx_timeout(timeout); + if let Some(_) = camera_config.timeout { + warn!("The undocumented `timeout` config option has been removed and is no longer needed."); + warn!("Please update your config file."); } info!( From 8ab4ba3b3316160106ac5bea06c738e671c4ae3d Mon Sep 17 00:00:00 2001 From: George Hilliard Date: Sun, 2 Aug 2020 12:31:47 -0500 Subject: [PATCH 3/3] Add possible reason for failure to set time --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 6e79a71e..abf8dfca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -231,7 +231,7 @@ fn camera_main( camera_config.name, time ); } else { - error!("{}: Camera did not accept new time", camera_config.name); + error!("{}: Camera did not accept new time (is {} an admin?)", camera_config.name, camera_config.username); } }