Closed dkerr64 closed 1 year ago
You can react to a message in the same way as in the keepalive.rs. Where we register a callback. If you post the xml here and the header details I can work it up
Ah here it is. Just captured it easier to spot when you know the ID number
Magic | Message ID | Message Length | Encryption Offset | Status Code | Message Class | Payload Offset |
---|---|---|---|---|---|---|
f0 de bc 0a | fc 00 00 00 | 16 02 00 00 | 00 00 00 00 | c8 00 | 00 00 | 00 00 00 00 |
<?xml version="1.0" encoding="UTF-8" ?>
<body>
<BatteryList version="1.1">
<BatteryInfo>
<channelId>0</channelId>
<chargeStatus>charging</chargeStatus>
<adapterStatus>solarPanel</adapterStatus>
<voltage>3998</voltage>
<current>0</current>
<temperature>37</temperature>
<batteryPercent>100</batteryPercent>
<lowPower>0</lowPower>
<batteryVersion>2</batteryVersion>
</BatteryInfo>
</BatteryList>
</body>
I'm only seeing one message at the start of the stream though. It's not continous
Should also be able to extract the graph of battery in last 30 days too somehow
I'm only seeing one message at the start of the stream though. It's not continous
I am seeing it midstream -- but that may be because of the disconnect/reconnects that are going on. It is also possible that it only sends on status change. Try unplugging the solar panel and see if that triggers it.
I don't know whether to be envious of your 37 degree ambient temperature, or grateful. I am -3 and snowing right now!!
I see you have "charging" and "solarPanel". When not charging the first field looks to be empty. When connected to power adapter the second one is "adapter". When discharging the first field also is empty, but current shows a negative value. I assume milliamps. And voltage I assume is millivolts. I think it refuses to charge when the temperature gets too cold, I don't know what the threshold is, but my camera has not charged for the last couple of days.
One of the joys of living in Thailand is its always sunny. One of the woes of living in Thailand it's always sunny. It's the same thing really only now it's too hot to go outside most of the time instead of too cold.
I'm not home at the moment so can't really tinker with the cable atm. Tried to get the battery graph to show up in wireshark like it does on the new app. But ran into a snag, when I use my legacy reolink client I can see all the packets coz there is not AES encyption. But the legacy client dosent support the graph. When I use the newer client I get only AES in wireshark... I'm going to have to decode this one packet at a time outside wireshark
Going to post this here for reference
chargeStatus changes to chargeComplete when full <chargeStatus>chargeComplete</chargeStatus>
<body>
<BatteryInfo>
<channelId>0</channelId>
<chargeStatus>chargeComplete</chargeStatus>
<adapterStatus>solarPanel</adapterStatus>
<voltage>3999</voltage>
<current>0</current>
<temperature>39</temperature>
<batteryPercent>100</batteryPercent>
<lowPower>0</lowPower>
<batteryVersion>2</batteryVersion>
</BatteryInfo>
</body>
Ah this is not a message sent from the camera periodically but one requested on demand by the client.
This is the request:
Magic | Message ID | Message Length | Encryption Offset | Status Code | Message Class | Payload Offset |
---|---|---|---|---|---|---|
f0 de bc 0a | fd 00 00 00 | 68 00 00 00 | 00000009 | 00 00 | 14 64 | 68 00 00 00 |
Extension:
<Extension version="1.1">
<channelId>0</channelId>
</Extension>
Payload: None
Reply
Magic | Message ID | Message Length | Encryption Offset | Status Code | Message Class | Payload Offset |
---|---|---|---|---|---|---|
f0 de bc 0a | fd 00 00 00 | 6d 01 00 00 | 00000009 | c8 00 | 00 00 | 00 00 00 00 |
Extention: none
Payload:
<body>
<BatteryInfo>
<channelId>0</channelId>
<chargeStatus>chargeComplete</chargeStatus>
<adapterStatus>solarPanel</adapterStatus>
<voltage>3999</voltage>
<current>0</current>
<temperature>39</temperature>
<batteryPercent>100</batteryPercent>
<lowPower>0</lowPower>
<batteryVersion>2</batteryVersion>
</BatteryInfo>
</body>
So summary:
ID: 252 sent by the camera after login. Contains a LIST of batteries
ID: 253 request for battery level from client to camera
Humm... so if we send a 253 request we get a 253 reply. But during login the information comes in a 252 message. So requesting can be same as anything else neolink requests, but we also need to accept messages that come in unsolicited, like during login.
David.
Excellent detective work btw.
Yes I am working up the code for both on demand and accepting these events (I'm assuming the camera will send it when low as a kinda event). It's almost done but it's getting late now so I'll finish tomorrow
So, for the last 12 hours I have been pulling a jpeg from my camera every 20 minutes. Camera has been disconnected from adapter, and it is zero Celsius. Battery has dropped from 90% to 88%. I think I will reduce the interval to every 10 minutes. What would be really cool is to be able to monitor the battery level, so if it drops below say 50% then I increase the interval.
I'm doing this all in a bash script on linux. It would be nice to be able to tell neolink to return raw data in XML or JSON format that can then be processed by the calling script.
We do have a mqtt interface. We could add your functions to that and then your script would have control over neolink and could get the results from that too
Current implementation here #42
Posted also in the comment thread for the PR...
I get a panic when parsing battery info. I am guessing it's because the "current" field is a negative number?
[2023-03-01T13:19:21Z DEBUG neolink_core::bc::xml] Struct: start to parse "body"
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched StartElement(body, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"})
[2023-03-01T13:19:21Z DEBUG neolink_core::bc::xml] Struct: start to parse "BatteryList"
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched StartElement(BatteryList, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"}, [version -> 1.1])
[2023-03-01T13:19:21Z DEBUG neolink_core::bc::xml] Struct: start to parse "BatteryInfo"
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched StartElement(BatteryInfo, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"})
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched StartElement(channelId, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"})
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched Characters(0)
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched EndElement(channelId)
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched StartElement(chargeStatus, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"})
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched Characters(none)
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched EndElement(chargeStatus)
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched StartElement(adapterStatus, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"})
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched Characters(none)
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched EndElement(adapterStatus)
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched StartElement(voltage, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"})
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched Characters(4029)
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched EndElement(voltage)
[2023-03-01T13:19:21Z DEBUG yaserde::de] Fetched StartElement(current, {"": "", "xml": "http://www.w3.org/XML/1998/namespace", "xmlns": "http://www.w3.org/2000/xmlns/"})
thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', crates/core/src/bc/xml.rs:485:41
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
I see you declared current as u32
which is probably the problem. Current is negative while discharging.
temperature also needs to be declared as i32
to allow for negative temperatures. And in addition to 'solarPanel' the adapter status can also be 'adapter' and none.
I changed both current and temperature to i32
and it works.
Is there a reason that you are not printing voltage and current in the INFO message?
It would also be helpful to have the battery info printed on stdout
rather than just stderr
. Right now I have to2>&1
redirect before pipe into grep to find "Charge:". When I capture a jpeg I'd like to capture the charge info at the same time so that I can manage how frequently I hit the camera for a new image.
Providing some easily parsable output would be best (ie, no percentage or degree C symbols).
Not a huge issue, just an observation. I'm sure I can work with what is does now.
I'm really liking this. I have my JPEG capture running in a loop, grabs image every 10 minutes. I extract the charge and temperature from the stderr then use ffmpeg to superimpose battery charge and temperature onto the image. ffmpeg also pads the image to 4x3 aspect ratio (to match that coming from other cameras) and compresses the image more, so browser page loads much faster. Now when I go to the web page for my cameras, all six images appear instantly (because I am caching a recent image on the web server). Five of the cameras are PoE wired, so I pull an image (with curl) once a minute, for the battery WiFi camera the image could be 10 minutes old... but the act of opening the web page fires of an immediate refresh with neolink.
Really really cool.
btw... for temperature, which could be negative, it may be safest to declare it as floats rather than integers. They are signed integers right now, but who knows if in the future temperature could be reported with decimals.
Ah right negative temperatures, I've been working in Kelvin too much for my work :). I'm going to put them as i32 until we actually see a float though.
If you have a gstreamer pipeline that adds the OSD to the image we can put that into neolink if you want.
What do you want in parseability. I can encode to xml without too much trouble. But if you want to encode to anything else then I'll need to restructure the library to use serde rather than yaserde libraries (yaserde is the one we use and is xml focused)
Ok so I went ahead and made the printing of status messages configurable.
In the config you can add
[[cameras]]
# Usual cam stuff
print_format = "Xml"
Valid values are None
(default), Human
and Xml
This is great, thank you. Xml to stdout is perfect, it is working well.
If you have a gstreamer pipeline that adds the OSD to the image we can put that into neolink if you want.
I think I prefer to keep it outside of neolink. I am using ffmpeg for a couple of processes and printing information like battery and temperature is easy to add... and gives me lot of flexibility on positioning.
Thanks.
Meged it into master so I'll close this
The camera is regularly sending battery status info...
Neolink should catch these and keep track of status. On startup it could print an INFO message. On low battery level can print a WARN message.
I made a start on this and added structs to xml.rs, but stopped work when I realized that I did not know how to catch the '252' messages. https://github.com/QuantumEntangledAndy/neolink/commit/1e7ee1d43d405879e4bdaf5d9c67c0fe674dbb4e