Is there any way to programmatically monitor the status (quality) of the IP Camera component’s video stream? Seems like there would be some response code attribute available to check if/when things go wrong.
There are two situations I need to catch if possible:
When the number of connect retries has been reached
When (for whatever reason) the stream ends inadvertently.
Is there any hidden properties that can be used in scripting (eg. property change scripts) to catch these events?
The IP camera component has an internally nested FrameProducer class on which you can call getState(). Getting to that is an exercise for the reader, but I’ll give two hints: 1. It’s not going to show up with a dir() call, and 2. it’s internally named parser.
Programmatically the IP Camera Viewer component’s only exposed interface would be the property-change event script. Any hint on what property to monitor? The component does not allow creation of custom properties. Normally property-change scripts only fire for changes of bindable properties.
Note: Rather than drinking MPEG, I am using a sequence of JPEG stills to reduce bandwidth / load on our already-over-taxed video servers. I have not tested the band-aid to see if it works with the full blown MPEG streaming.
After a little digging around I got this sorted out. Through the use of reflection I got hold of the parser object and then the getState method inside. The only oddity I found was when displaying the string in a label used for debugging purposes sometimes it was all upper case and other times it was first letter upper, rest lower case (RUNNING or Running).
The script below was attached to a mouseClicked event on the IP Cam viewer for testing but in prod we use a timer to run the check and issue the reconnect() call if need be
from com.inductiveautomation.factorypmi.application.components import PMIIPCamViewer
parserRef = PMIIPCamViewer().getClass().getDeclaredField('parser')
cam = event.source
parser = parserRef.get(cam)
# If the url property is blank, parser is None
if parser is not None:
stateRef = parser.getClass().getSuperclass().getDeclaredMethod('getState')
# Enum contents: CONNECTING, RUNNING, CANCELED, ERROR
state = stateRef.invoke(parser)
Looks familiar… If you look at the Usage Notes for my Image Streamer module, you’ll see a formal version of this as a script module, suited to use in a binding. Allows you to copy camera view instances around without needing a separate timer component.