Package: elkm1-lib
Python ElkM1 libraryLibrary for interacting with ElkM1 alarm/automation panel.https://github.com/gwww/elkm1RequirementsPython 3.9 (or higher)DescriptionThis package is created as a library to interact with an ElkM1 alarm/automation
pattern. The motivation to write this was to use with the Home Assistant
automation platform. The library can be used for writing other ElkM1 integration
applications. The IO with the panel is asynchronous over TCP or over the
serial port.Installation$pipinstallelkm1_libOverviewBasic connection to the Elk panel:fromelkm1_libimportElkimportlogging# Print to STDOUTLOG=logging.getLogger(__name__)logging.basicConfig(level=logging.DEBUG,format='%(message)s')# Connect to elkelk=Elk({'url':'elk://192.168.1.100'})elk.connect()elk.run()The above will connect to the Elk panel at IP address 192.168.1.100. theelk://prefix specifies that the connect is plaintext. Alternatively,elks://will
connect over TLS. In this case a userid and password must be specified
and the call toElkchanges to:elk=Elk({'url':'elks://192.168.1.100','userid':'test','password':'pass'})The following ElkM1 connection protocols are supported:serial:// - Serial port;elk:// - Elk M1XEP Ethernet, non-secureelks:// - Elk M1XEP Ethernet, secure, TLS 1.0elksv1_0:// - Elk M1XEP Ethernet, secure, TLS 1.0, supported on M1XEP version < 2.0.46elksv1_2:// - Elk M1XEP Ethernet, secure, TLS 1.2, supported on M1XEP version = 2.0.46elksv1_3:// - Elk M1XEP Ethernet, secure, TLS 1.2, not yet supported on M1XEP, reserved for futureA username and password are required for any of the secure modes.To see working example code take a look at the scriptbin/simple.TheElkobject supports the concept ofElements. AnElementis the base class representation ofZones,Lights, etc. So, for
example there is a list of zones:elk.zonesand each zone can be
accessed byelk.zones[index]. Each element has a__str__representation so that it is easy to print its contents.AllElementsare referenced starting at 0. Even though the Elk panel
refers to, for example, zones 1-208, the library references them
as zones 0-207. All translation from base 0 to 1 and vice-versa is
handled internally in theelkm1_lib.messagemodule.After creating theElkobject and connecting to the panel the
library code will synchronize all the elements to the data from the Elk panel.Many Elk messages are handled by the library, caching their contents. When a
message causes a change to an attribute of anElement, registered
callbacks are called so that user use of the library can be notified
of changing elements. The following user code shows registering a callback:defcall_me(element,changeset):print(changeset)forzone_numberinrange(Max.ZONES.value):elk.zones[zone_number].add_callback(call_me)The library encodes, decodes, and processes messages to/from the
Elk panel. All the encoding and decoding is done inelkm1_lib.messagemodule.Messages received are handled with callbacks. The library
internally registers callbacks so that decoded messages
can be used to update anElement. The user of the
library may also register callbacks. Any particular message
may have multiple callbacks.When the message is received it is decoded
and some validation is done. The message handler is called
with the fields of from the decoded message. Each type of
message has parameters that match the message type. All handler parameters
are named parameters.Here is an example of a message handler being registered and how it is called:defzone_status_change_handler(zone_number,zone_status):print(zone_number,zone_status)elk.add_handler('ZC',zone_status_change_handler)The above code registers a callback for 'ZC' (Elk zone status change)
messages. When a ZC message is received the handler functions are called
with the zone_number and zone_status.There are a number of pseudo-handlers that act like the handlers. These are
called when events happen. The pseudo-handlers are:connect: When a successful connection to the ElkM1 is completed.disconnect: When a connection to a panel is disconnected.login: When a login is made to the panel (usingelks://connection mode.
A single boolean parameter is passedsucceeded.sync_complete: When the panel has completed synchonizing all its elements.timeout: When a send of a message to the ElkM1 times out (fails to send).unknown: When a message from the ElkM1 is received and the library does
not have a method to decode the message. The message is passed to this handler
and can be decoded outside of the library.UtilitiesThebindirectory of the library has one utility program and
a couple of example uses of the library.mkdocThe utilitymkdoccreates a Markdown table of the list of Elk
messages with a check mark for those messages have encoders/decoders
and an X for those messages are not planned to be implemented.
There are no parameters tomkdoc. It outputs to stdout.
The data for the report comes from the ElkM1 library code mostly.
A couple of things are hard coded in the mkdoc script, notably
the "no plans to implement" list.simpleThesimplePython script is a trivial use of the ElkM1 library.
It connects to the panel, syncs to internal memory, and continues
listening for any messages from the panel. The URL of the ElkM1 to
connect to is retrieved from an environment variable namedELKM1_URL.elkTheelkPython script is a bit of a command interpretor. It can run in
two modes. Non-interactive mode is the default. Just run theelkcommand.
The non-interactive mode is similar tosimpleexcept there are a
couple of message handlers (timeoutandunknownhandlers).Theelkcan also be run in interactive mode by invoking it byelk -i. In this mode is uses curses (full screen use of the terminal)
that has a command line and an output window.TABswitches between
the command line and output windows. In the output window the arrow keys
and scrollwheel scroll the contents of the window.In the command line when runningelk -ithere are a
number of commands. Start withhelp. Thenhelp <command>for
details on each command. In general there are commands to dump the internal
state of elements and to invoke any of the encoders to send a message
to the Elk panel.For example,light <4, 8, 12-14would invoke the__str__method
for the light element to print the cached info for lights 0-3, 8, and 12-14.Another example would bepf 3which issues the pf (Turn light off)
command for light number 3 (light 4 on the panel -- remember 0
versus 1 base).All of the commands that send messages to the panel are automatically
discovered and are all the XX_encode functions in theelkm1_lib.messagemodule. The docstring and the XX_encode's parameters are shown as part
of the help.DevelopmentThis project usespoetryfor development dependencies. Installation instructions are on their website.To get started developing:git clone https://github.com/gwww/elkm1.git
cd elkm1
poetry install
poetry shell # Or activate the created virtual environment
make test # to ensure everything installed properlyThere is aMakefilein the root directory as well. Themakecommand
followed by one of the targets in theMakefilecan be used. If you don't
have or wish to usemaketheMakefileserves as examples of common
commands that can be run.Reporting a BugNo problem ;) — report the bugs! But, logs are most often required. If you
are using Home Assistant, which is about the only use I'm aware of for
this library, then add the following to yourconfiguration.yaml:logger:
  default: info
  logs:
    custom_components.elkm1: debug
    elkm1_lib: debugDo everything in your power to trim to logs down to their smallest. One way is
to reproduce your problem quickly so that few other logs are not generated in
between. Another recommendation is to use the simplest configuration that you
can think of to reproduce the problem.Can you reproduce the problem in other ways? If this is a problem that is
being experienced while using Home Assistant try using theServicesinDeveloper Tools.Sometime logs may have sensitive information in them. You may want to
scan your logs for that info and "X" it out. In addition, you can send logs
directly to me. Support email is in thepyproject.tomlfile. You may also
send a link to somewhere you've stored/shared the file (DropBox for example).