Skip to content
A great Eye, lidless, wreathed in webcams.
Python HTML
Find file
Latest commit 1f1befe Jun 27, 2015 @eastein autopep8 of & make it so that if busy_percentage isn't def…
…ined yet, we don't crash trying to write a motion frame to the frame indexwq
Failed to load latest commit information.
flot @ 86c82e5 accept a parameter defining how many days of frame index / storage to… Jun 18, 2014
scripts forgot to document PIL dependence, a bit of incomplete work on #29 (h… Jan 24, 2012
.gitignore ignore db files, those are instance state Aug 21, 2011
.gitmodules add flot submodule Aug 21, 2011 only proxy runtime data dependent calls to the backends, this will ma… Jul 1, 2012
API.txt only proxy runtime data dependent calls to the backends, this will ma… Jul 1, 2012 english is hard Sep 6, 2011
CREDITS.txt english is hard Sep 7, 2011
LICENSE oops, license file had wrong project name Sep 15, 2011
LICENSE_GPL2 added license (gpl 2/3) Aug 7, 2011
LICENSE_GPL3 added license (gpl 2/3) Aug 8, 2011 doc update on snapshot feature Jun 18, 2014
README.txt doc update on snapshot feature Jun 19, 2014 some documentation Aug 13, 2011
TESTING.txt some documentation Aug 13, 2011 notes on zoneminder config suggested Aug 15, 2011
ZONEMINDER.txt notes on zoneminder config suggested Aug 15, 2011 #46 use store and store_thr options in camera stanzas to specify that… Feb 19, 2013 accept a parameter defining how many days of frame index / storage to… Jun 19, 2014 #13 role based multiprocessing. Oct 8, 2011
history_query #5 add in ZeroMQ publishing between the same percept in different pro… Oct 22, 2011
interface.html accept a parameter defining how many days of frame index / storage to… Jun 19, 2014
lidless accept a parameter defining how many days of frame index / storage to… Jun 19, 2014 swapping zmqsub over to zmqfan version & use zmqsub in all cases wher… Sep 14, 2014 swapping zmqsub over to zmqfan version & use zmqsub in all cases wher… Sep 14, 2014 swapping zmqsub over to zmqfan version & use zmqsub in all cases wher… Sep 14, 2014 autopep8 of & make it so that if busy_percentage isn't def… Jun 27, 2015
requirements.pip Merge branch 'master' of Sep 30, 2014
tz-test.html Eyeballed the graph percentages so that they look decent in this exam… Jan 29, 2012

What's This?

lidless is a program for monitoring motion-jpeg camera feeds and interfacing them to IRC and the web, allowing users to request info on how busy the view captured by the cameras are and view historical information about busyness.


It's strongly advised to look up the best way to install OpenCV and numpy for your distribution. Their packaging is basically like a medieval dungeon where they don't even know which side of the place setting to put the lobster fork on. Shocking.

  • OpenCV with python support, 2.1 or 2.2 work. 2.3 may work, but has not been tested successfully.
  • CPython 2.6 or 2.7 (other pythons may work as well)
  • python-irclib
  • tornado (

Anything under should be pulled/updated from github at the same time; from time to time, I change the way modules and their users work in fundamental ways. I should probably switch to submodules, admittedly.

You'll want a ZoneMinder server for this to be useful for a wide variety of camera streams, or if you have a motion jpeg http streaming camera, you will probably be able to use it directly.

Video Sources

Please see the README for the version of zmstream you are using to determine what cameras and video sources will be supported by your install.

PTZ Cameras

Be aware that if you are using a pan/tilt/zoom camera, lidless's motion data will produce bad data around the periods when you move the camera. The algorithms for motion detection depend on the camera's view being of the same field of view at all times.


You'll want to write a config file in JSON.

Here is an example:

  "type" : "camera",
  "name" : "warehouse",
  "url" : "",
  "username" : "john",
  "password" : "doe"
  "type" : "irc",
  "server" : "",
  "nick" : "someguy",
  "channel" : "#irc"
  "type" : "web",
  "port" : 8000

The username and password options work with HTTP basic authentication or ZoneMinder's time based authentication session at this time. They are optional. HTTPS does not work for camera sources. If you want to go through ZoneMinder, the URL must end with auth= (the GET parameter for auth must be at the end), the zm_auth_hash_secret parameter must be added into the camera JSON stanza, and the username/password should be a valid user in the ZoneMinder instance.


These only make sense if you have an irc or announced stanza. See the roles section for more about making an alert go to more than one output.

  "role" : ["announcer", "frontend"],
  "type" : "alert",
  "mode" : "sustain",
  "high_level" : 0,
  "duration" : 73200,
  "message" : "I've been sitting here in the woodshop alone for like a day. I really need to get lathed.",
  "camera" : "woodshop",
  "throttle" : 86400

How the high_level, low_level and mode settings here work will be documented later; for now, refer to the code in that concerns alerts. The throttle parameter will prevent the alert from firing more often than every that-many seconds.


The program announced is a simple system for recieving textual commands that are spoken via text to speech. If you have one running and would like to make alerts be sent over it, you can create an announced stanza, like so:

  "role" : "announcer",
  "type" : "announced",
  "zmq_url" : "tcp://"

See the roles section on alert routing considerations.


The snapshot feature's purpose is to allow IRC users to request snapshots of specific cameras; each camera can turn the feature on independently, and throttle the usage independently. Usage:

!snapshot frontdoor snapshot taken of frontdoor

This URL is available for a short time (for now, until restart).

This feature is in beta.

The settings on a camera stanza to enable it are:

  • snapshot, boolean. Defaults to False. Set it to True to enable snapshots.
  • snapshot_base_url, string. Defaults to http://localhost:8000 - the URL users using IRC should use to reach the main web instance in lidless. No trailing slash.


This feature was not originally intended to be available, so its implementation and configuration have a few more concerns than some of the other features.



If you have access to a stream that ffmpeg can open and does not require authentication you can add the setting mode = ffmpeg to a camera stanza. Doing so will use pyffmpeg to input the stream. This is experimental and does not work very well yet, if at all. Use at your own risk (even more so than the rest of this application, which is also at your own risk of course).


  • pyffmpeg segfaults if you point it at a motion-jpeg stream that requires authentication, at the very least. I don't know what else it crashes on or the origin of this crash.
  • if your CPU can't keep up, non-key frames may end up skipped and cause the video picture to get corrupted; you have probably seen this running HD video on an old computer. This is easy to discount when watching video with your eyes, but less easy for lidless to discard and account for. There may be a way to work around this. I expect that these scenarios will result in falsely high busyness information or potentially falsely low busyness information.


Different parts of the system can be run in separate processes to avoid contention and performance issues. Roles are settings in a stanza that specify what role name a process must be running as in order to execute the work related to the stanza.

For a camera instance, this is reading the video stream, doing perceptual computations on it, and recording the data periodically.

For a web instance not using proxying (see below), the work is doing read operations on databases for historical data and shared memory access for the ratio data (there are issues currently with a web instance or irc instance accessing the current ratio of a camera not running in the same role, as it must use the database to access this information at this time). A process can only have one role: the default role is called default.

An IRC instance will consume all alerts produced in its role, as will an announced instance. You must run IRC and announced in separate processes (and hence, roles). If you want alerts to go to more to than one, set the role on the alert stanza to a list of roles containing the consumers of alerts that you are targetting. This has the added bonus feature (it's not a bug, really!) that you can send alerts to a specific subset of alert transmitting mediums.


If you are having web interface or API performance issues, it's suggested to add a second web stanza with the proxy_endpoint set to the base url of the other web stanza; in the above example such a proxy_endpoint setting would be "http://localhost:8000". A stanza that works for proxying is:

  "role" : "webserver",
  "type" : "web",
  "proxy_mode" : "auto",
  "port" : 8000

This proxying web instance has some special settings in play. It is using the webserver role, which means it will not run in the default process: you must run another process with a role argument of webserver in order to execute it, using the same configuration file as the other processes. It depends on every other process/role that services camera stanzas to also include a non-proxied web instance to do the actual data access. The usage of the proxy_mode = auto setting will direct the proxy to load balance non-camera-specific requests and direct the camera-specific requests to the other web instance running on the local machine that is in the same role as the camera that the request is in reference to. However, proxy_mode = auto does not currently work except over localhost. If your worker processes are on a different machine than the proxy process, you will need to use proxy_endpoint = http://ip:port instead, and proxy_mode = auto isn't smart enough to automatically proxy between mid-layer proxies, so at this time proxying is not a solution for multi-machine scalability.

Interchange in a Multi-role System

If not all of the stanzas have the same role, sometimes information is required in one stanza that is generated in a different stanza; for instance, current ratio information. There are 3 ways that this information can be acquired: direct memory access (if the stanza needing the information is in the same python process), ZeroMQ PUB/SUB (this should work inter-machine), HTTP proxy.

Direct Access

This one is the simplest; if the stanza (either irc or web that's doing serving and has no proxy settings configured) is in the same role, it will just access the data from the camera via the Python object that represents the camera processing work.


Setting the zmq_url parameter on a camera will set up a ZMQ PUB/SUB socket set internal to the camera that allows the inactive instances of the camera in the out-of-role processes to receive realtime updates on the current ratio. This connects with the Direct Access system at that time such that other stanzas will just directly access the latest PUB/SUB interchanged ratio state. For details of the messages sent over the zmq_url, see API.txt.

HTTP Proxy

Using either proxy_endpoint = or proxy_mode = auto, one web stanza can directly request the ratio data for API serving from a different web stanza that uses one of the other 2 methods of access.


See API document for details of the API.

See Also

See CREDITS for props to people who helped out.

Something went wrong with that request. Please try again.