Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/optional MQTT discovery #95

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fc8adf2
Feature/optional MQTT discovery
May 27, 2023
fd3fffc
Attempting to reduce `.clone()` usage
May 29, 2023
2d37807
Don't get clever trying to reuse device/availability
Jun 4, 2023
b5136ed
Document MQTT Discovery in README.md
Jun 4, 2023
5c3cae5
Merge branch 'master' of https://github.com/QuantumEntangledAndy/neol…
QuantumEntangledAndy Jun 6, 2023
48f385e
Add camera preview auto discovery
QuantumEntangledAndy Jun 6, 2023
10956e8
Add camera preview into mqtt via snap shot command
QuantumEntangledAndy Jun 7, 2023
b221fe6
Actually add the new .rs
QuantumEntangledAndy Jun 7, 2023
c2e613d
fmt
QuantumEntangledAndy Jun 7, 2023
2b3ae0e
Add snap.rs
QuantumEntangledAndy Jun 7, 2023
dba2f24
Add all the mqtt controls to auto discovery
QuantumEntangledAndy Jun 7, 2023
00f30b8
Use enum for config
QuantumEntangledAndy Jun 7, 2023
9eb892a
fmt
QuantumEntangledAndy Jun 7, 2023
3467951
Handle message that don't reply on success
QuantumEntangledAndy Jun 7, 2023
c30725b
Update readme
QuantumEntangledAndy Jun 7, 2023
56476bc
Add simple battery level
QuantumEntangledAndy Jun 7, 2023
a449666
Add battery sensor to discovery
QuantumEntangledAndy Jun 7, 2023
83dc6cc
Add battery sensor to discovery README
QuantumEntangledAndy Jun 7, 2023
c7bd565
Handle off byte endian and handle ServieUnavalible in mqtt
QuantumEntangledAndy Jun 8, 2023
f7b5e89
Handle messages and IDs to better replicate offical messaging system
QuantumEntangledAndy Jun 8, 2023
fbbfdda
Handle closing and upgrade message numbers and IDs more cleanly
QuantumEntangledAndy Jun 8, 2023
15bf7cf
Merge remote-tracking branch 'upstream/master' into discovery
QuantumEntangledAndy Jun 8, 2023
4f0169e
fmt
QuantumEntangledAndy Jun 8, 2023
c650595
Add config options for mqtt threads
QuantumEntangledAndy Jun 8, 2023
f73dbac
fmt
QuantumEntangledAndy Jun 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ members = [

[dependencies]
anyhow = "1.0.70"
base64 = "0.21.2"
byte-slice-cast = "1.2.2"
clap = { version = "4.2.2", features = ["derive", "cargo"] }
console-subscriber = "0.1.8"
Expand All @@ -23,6 +24,7 @@ gstreamer = "0.20.3"
gstreamer-app = "0.20.0"
gstreamer-rtsp = "0.20.0"
gstreamer-rtsp-server = { version = "0.20.3", features = ["v1_16"] }
heck = "0.4.1"
is_sorted = "0.1.1"
itertools = "0.10.5"
lazy_static = "1.4.0"
Expand All @@ -31,6 +33,7 @@ neolink_core = { path = "crates/core", version = "0.5.12" }
regex = "1.7.3"
rumqttc = "0.20.0"
serde = { version = "1.0.160", features = ["derive"] }
serde_json = "1.0.96"
time = "0.3.20"
tokio = { version = "1.27.0", features = ["rt-multi-thread", "macros", "io-util", "tracing"] }
tokio-stream = "0.1.12"
Expand Down
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ Cellular cameras should select `"cellular"` which only enables `map` and
discovery = "cellular"
```

See the sample config file for more details.

### MQTT

To use mqtt you will to adjust your config file as such:
Expand Down Expand Up @@ -201,17 +203,67 @@ Status Messages:
- `/status disconnected` Sent when the camera goes offline
- `/status/battery` Sent in reply to a `/query/battery` an XML encoded version
of the battery status
- `/status/battery_level` A simple % value of current battery level
- `/status/pir` Sent in reply to a `/query/pir` an XML encoded version of the
pir status
- `/status/motion` Contains the motion detection alarm status. `on` for motion and `off` for still
- `/status/ptz/preset` Sent in reply to a `/query/ptz/preset` an XML encoded version of the
PTZ presets
- `/status/preview` a base64 encoded camera image updated every 0.5s

Query Messages:

- `/query/battery` Request that the camera reports its battery level
- `/query/pir` Request that the camera reports its pir status
- `/query/ptz/preset` Request that the camera reports its PTZ presets

### MQTT Disable Features

Certain features like preview and motion detection may not be desired
you can disable them by them with the following config options.
Disabling these may help to conserve battery

```toml
enable_motion = false # motion detection
# (limited battery drain since it
# is a passive listening connection)

enable_pings = false # keep alive pings that keep the camera connected

enable_light = false # flood lights only avaliable on some camera
# (limited battery drain since it
# is a passive listening connection)

enable_battery = false # battery updates in `/status/battery_level`

enable_preview = false # preview image in `/status/preview`
```

#### MQTT Discovery

[MQTT Discovery](https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery) is partially supported.
Currently, discovery is opt-in and camera features must be manually specified.

```toml
[cameras.mqtt]
# <see above>
[cameras.mqtt.discovery]
topic = "homeassistant"
features = ["floodlight"]
```

Avaliable features are:

- `floodlight`: This adds a light control to home assistant
- `camera`: This adds a camera preview to home assistant. It is only updated every 0.5s and cannot be much more than that since it is updated over mqtt not over RTSP
- `led`: This adds a switch to chage the LED status light on/off to home assistant
- `ir`: This adds a selection switch to chage the IR light on/off/auto to home assistant
- `motion`: This adds a motion detection binary sensor to home assistant
- `reboot`: This adds a reboot button to home assistant
- `pt`: This adds a selection of buttons to control the pan and tilt of the camera
- `battery`: This adds a battery level sensor to home assistant


### Pause

To use the pause feature you will need to adjust your config file as such:
Expand Down
6 changes: 4 additions & 2 deletions crates/core/src/bc/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,10 @@ fn bc_modern_msg<'a>(
}

fn bc_header(buf: &[u8]) -> IResult<&[u8], BcHeader> {
let (buf, _magic) =
error_context("Magic invalid", verify(le_u32, |x| *x == MAGIC_HEADER))(buf)?;
let (buf, _magic) = error_context(
"Magic invalid",
verify(le_u32, |x| *x == MAGIC_HEADER || *x == MAGIC_HEADER_REV),
)(buf)?;
let (buf, msg_id) = error_context("MsgID missing", le_u32)(buf)?;
let (buf, body_len) = error_context("BodyLen missing", le_u32)(buf)?;
let (buf, channel_id) = error_context("ChannelID missing", le_u8)(buf)?;
Expand Down
8 changes: 7 additions & 1 deletion crates/core/src/bc/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ use crate::Credentials;
pub use super::xml::{BcPayloads, BcXml, Extension};
use std::collections::HashSet;

pub(super) const MAGIC_HEADER: u32 = 0xabcdef0;
pub(super) const MAGIC_HEADER: u32 = 0x0abcdef0;
/// Sometimes will get the BE magic header even though all other numbers are LE?
/// Seems to happens with certain messages like snap that produce jpegs, so perhaps it
/// it is meant to be a hint as to the endianess of the binary payload
pub(super) const MAGIC_HEADER_REV: u32 = 0x0fedcba0;

/// Login messages have this ID
pub const MSG_ID_LOGIN: u32 = 1;
Expand Down Expand Up @@ -33,6 +37,8 @@ pub const MSG_ID_VERSION: u32 = 80;
pub const MSG_ID_PING: u32 = 93;
/// General system info messages have this ID
pub const MSG_ID_GET_GENERAL: u32 = 104;
/// Snapshot to get a jpeg image
pub const MSG_ID_SNAP: u32 = 109;
/// Used to get the abilities of a user
pub const MSG_ID_ABILITY_INFO: u32 = 151;
/// Setting general system info (clock mostly) messages have this ID
Expand Down
35 changes: 34 additions & 1 deletion crates/core/src/bc/xml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ pub struct BcXml {
/// Recieved on request for a link type
#[yaserde(rename = "LinkType")]
pub link_type: Option<LinkType>,
/// Recieved AND send for the snap message
#[yaserde(rename = "Snap")]
pub snap: Option<Snap>,
}

impl BcXml {
Expand Down Expand Up @@ -700,7 +703,37 @@ pub struct AbilityInfoSubModule {
pub struct LinkType {
#[yaserde(rename = "type")]
/// Type of connection known values `"LAN"`
link_type: String,
pub link_type: String,
}

/// The Link Type contains the type of connection present
#[derive(PartialEq, Eq, Default, Debug, YaDeserialize, YaSerialize)]
pub struct Snap {
#[yaserde(rename = "channelId")]
/// The channel id to get the snapshot from
pub channel_id: u8,
/// Unknown, observed values: 0
/// value is only set on request
#[yaserde(rename = "logicChannel")]
pub logic_channel: Option<u8>,
/// Time of snapshot, zero when requesting
pub time: u32,
/// Request a full frame, observed values: 0
/// value is only set on request
#[yaserde(rename = "fullFrame")]
pub full_frame: Option<u32>,
/// Stream name, observed values: `main`, `sub`
/// value is only set on request
#[yaserde(rename = "streamType")]
pub stream_type: Option<String>,
/// File name, usually of the form `01_20230518140240.jpg`
/// value is only set on recieve
#[yaserde(rename = "fileName")]
pub file_name: Option<String>,
/// Size in bytes of the picture
/// value is only set on recieve
#[yaserde(rename = "pictureSize")]
pub picture_size: Option<u32>,
}

/// Convience function to return the xml version used throughout the library
Expand Down
1 change: 1 addition & 0 deletions crates/core/src/bc_protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ mod pirstate;
mod ptz;
mod reboot;
mod resolution;
mod snap;
mod stream;
mod talk;
mod time;
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/bc_protocol/abilityinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ impl BcCamera {
pub async fn get_abilityinfo(&self) -> Result<AbilityInfo> {
let connection = self.get_connection();
let msg_num = self.new_message_num();
let mut sub_get = connection.subscribe(msg_num).await?;
let mut sub_get = connection.subscribe(MSG_ID_ABILITY_INFO, msg_num).await?;
let get = Bc {
meta: BcMeta {
msg_id: MSG_ID_ABILITY_INFO,
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/bc_protocol/battery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ impl BcCamera {
let connection = self.get_connection();

let msg_num = self.new_message_num();
let mut sub = connection.subscribe(msg_num).await?;
let mut sub = connection.subscribe(MSG_ID_BATTERY_INFO, msg_num).await?;

let msg = Bc {
meta: BcMeta {
Expand Down
Loading