Usage
Overview
pyluxa4
is mainly designed to be used from command line. When installed, it provides a command line tool called pyluxa4
. When installing the module, a tool will be added called pyluxa4
. Assuming your Python installation's bin/Script folder is added to your system's path, you will be able to access it from the command line:
$ pyluxa4 --version
pyluxa4 1.5
You can also access it via:
$ python3 -m pyluxa4 --version
pyluxa4 1.5
Starting the Server
Generally, pyluxa4
is designed to be used by running a server, and then executing commands:
-
Start the server:
$ pyluxa4 serve [2019-09-21 15:21:49] INFO: Starting Luxafor server...
-
Run a command:
$ pyluxa4 api {'error': '', 'path': '/pyluxa4/api/version', 'status': 'success', 'version': '1.5.1', 'version_path': '/pyluxa4/api/v1.5'}
If you have multiple devices connected, and you want to specify a specific one, you can run the list
command to see the connected devices. Devices are listed in the form index> path
.
$ pyluxa4 list
0> \\?\hid#vid_04d8&pid_f372#6&38a95344&1&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
Then we can then specify from the command line which device to use when we start the server. Using the index, it would be:
$ pyluxa4 serve --device-index 0
Using the path, it would be:
$ pyluxa4 serve --device-path "\\?\hid#vid_04d8&pid_f372#6&38a95344&1&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
Normally, the serve command will find the hidapi
library as long as its path is found in the systems appropriate environmental variable, but if it is not, or you'd like to explicitly specify the path to avoid any DLL hijacking, then you can specify the absolute path to the hidapi library with the --hidapi
.
$ python3 -m pyluxa4 serve --hidapi /usr/local/Cellar/hidapi/0.14.0/lib/libhidapi.dylib
Killing a Server
If the server is running in a console, you can always press Ctrl+C, but if your server is running in the background, you can kill the server with the kill
command.
$ pyluxa4 kill
Sending Commands
Once the server is up and running, you can send a variety of commands to set the LEDs to a specific color, to fade colors in or out, to strobe colors, to apply a wave effect to a color, or to simply run one of the built-in patterns.
More advanced commands are also available. The scheduler
command can send JSON content to the server with a list of commands to run at different times. The timer
command can initiate a timer to initiate a command after a set amount of time.
To run the commands, simply call pyluxa4
with the command, followed by the commands arguments:
To set a color, simply specify the color
command with the desired color:
$ pyluxa4 color red
{'code': 200, 'error': '', 'path': '/pyluxa4/api/v1.5/command/color', 'status': 'success'}
There are a variety of commands, check out Commands to learn more.
Scheduling Commands
pyluxa4
provides a command scheduler that allows you to specify a number of commands to run at different times.
For instance, if you wanted to automatically turn your light red at 3:00 PM for an hour, then turn it back green at 4:00 PM, we could construct a couple of scheduled events. Schedules are done as JSON files, the file should contain a list of events where each event is a hash of key value pairs that describes the event:
[
{
"cmd": "color",
"days": "wkd",
"times": ["15:00"],
"args": {
"color": "red"
}
},
{
"cmd": "color",
"days": "wkd",
"times": ["16:00"],
"args": {
"color": "green"
}
}
]
Then we can send the command to the server:
$ pyluxa4 scheduler --schedule myschedule.json
{'code': 200, 'error': '', 'path': '/pyluxa4/api/v1.5/command/scheduler', 'status': 'success'}
If we want to clear existing scheduling events while sending our new schedule, simply add the --clear
command.
$ pyluxa4 scheduler --schedule myschedule.json --clear
{'code': 200, 'error': '', 'path': '/pyluxa4/api/v1.5/command/scheduler', 'status': 'success'}
If desired, you can also just run --clear
without a schedule remove all scheduled events.
$ pyluxa4 scheduler --clear
{'code': 200, 'error': '', 'path': '/pyluxa4/api/v1.5/command/scheduler', 'status': 'success'}
To get an output of loaded events in the schedule (timers not included), we can run:
$ pyluxa4 get schedule
{'code': 200, 'error': '', 'path': '/pyluxa4/api/v1.5/scheduler/schedule', 'schedule': [{'args': {'color': 'red'}, 'cmd': 'color', 'days': ['wkd'], 'times': ['15:00']}, {'args': {'color': 'green'}, 'cmd': 'color', 'days': ['wkd'], 'times': ['16:00']}], 'status': 'success'}
Parameters | Description |
---|---|
cmd | Name of the command to run |
days | A list of days: mon , tue , wed , thu , fri , sat , or sun . You can also specify wkd for weekdays, wke for the weekend, and all for all days. |
times | A list of times that the even will be run on. Times are specified as 24 hour time format. |
args | Is a hash of key value pairs of arguments to pass the the specified command. |
Sending Schedule on Server Start
You can also load a schedule while starting the server via the --schedule
parameter:
$ pyluxa4 serve --schedule myschedule.json
[2019-09-22 14:05:10] INFO: Starting Luxafor server...
Setting Timers
pyluxa4
allows for setting timers. Timers are essentially a special kind of scheduled event. One that ignores days
and will destroy itself after the number of specified cycles has run to completion (unless it specified to run forever).
Additionally, timers are unique as the times
list does not contain specific times, but contains relative times in the form <number of hours>:<number of minutes>
. For instance, if we wanted to have the timer go off in 3 hours and 30 minutes, we would specify the time as 3:30
. This does not represent 3:30 AM
, but 3 hours and 30 minutes from the time the timer was added.
For instance, if we wanted to strobe a red light in an hour and 30 minutes, we could use the following command:
$ pyluxa4 timer --cmd strobe --color red --speed 10 --repeat 10 --times 1:30
If we wanted to do it at ten minutes from now followed by another 5 minutes after that:
$ pyluxa4 timer --cmd strobe --color red --speed 10 --repeat 10 --times 0:10,0:5
We could even repeat the cycle to flash to iterate through the timers twice, essentially flashing the red light at 10 minutes, 5 minutes, 10 minutes, and 5 minutes
$ pyluxa4 timer --cmd strobe --color red --speed 10 --repeat 10 --times 0:10,0:5 --cycle 2
We could even do it continuously every 30 minutes by specifying the cycle as 0 (meaning forever):
$ pyluxa4 timer --cmd strobe --color red --speed 10 --repeat 10 --times 0:30 --cycle 0
You can also delay when the times start by specifying a specific time to wait for before starting the timer. For instance, here we start flashing the light every 30 minutes starting at 9:00 AM:
$ pyluxa4 timer --cmd strobe --color red --speed 10 --repeat 10 --times 0:30 --cycle 0 --start 9:00
You could also terminate a timer after at a specific time, for example 5:00 PM:
$ pyluxa4 timer --cmd strobe --color red --speed 10 --repeat 10 --times 0:30 --cycle 0 --start 9:00 --end 17:00
As mentioned, times are just a special kind of scheduled event, you can actually put them in a schedule file and they will be recognized. You must add timer
with the number of times to cycle through the timers. You also must make times relative. The key days
will be ignored in timers and can be omitted. You can also use two one or both timer specific keys (start
and end
) to specify a respective start and end time for the timers.
For a simple example of a timer represented in a schedule file, consider a case where we'd like to turn off lights as soon as a schedule is loaded. We could specify a timer with a relative time of 0:0
, which means right away:
[
{
"cmd": "off",
"timer": 1,
"times": ["0:0"]
}
]
You can clear all running timers by calling the scheduler
command with the --cancel
parameter:
$ pyluxa4 scheduler --cancel
{'code': 200, 'error': '', 'path': '/pyluxa4/api/v1.5/command/scheduler', 'status': 'success'}
To get an output of loaded timers, we can run:
$ pyluxa4 get timers
{'code': 200, 'error': '', 'path': '/pyluxa4/api/v1.5/scheduler/timers', 'schedule': [{'args': {}, 'cmd': 'off', 'days': 'all', 'end': None, 'start': None, 'timer': 1, 'times': ['0:10']}], 'status': 'success'}
Enabling HTTPS
pyluxa4
is mainly meant to be used on a local network, so these instructions are from that perspective.
In order to enable HTTPS, we need to have a certificate. In our local network case, using a simple self signed certificate is more than sufficient.
To create a certificate, we will assume you have OpenSSL installed. If you are on Windows using Git Bash, it will likely be available in your Bash terminal. We use OpenSSL to generate a x509v3 certificate. You can create a simple configuration template like the one shown below which adds in the v3 parameters. Replace the IP with the one from your machine. We will call this file cert.conf
.
[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (eg, city)
organizationName = Organization Name (eg, company)
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (e.g. server FQDN or YOUR name)
emailAddress = Email Address
[ v3_req ]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = 127.0.0.1
IP.2 = 192.168.1.2
Afterwards, run the following command. Enter the information that you'd like:
$ openssl req -x509 -out pyluxa4.cer -newkey rsa:4096 -nodes -keyout private.key -extensions v3_req -days 3650 -config cert.conf
You should now have a certificate pyluxa4.cer
and a private key file private.key
.
Afterwards, you we can use the --ssl-cert
and --ssl-key
parameters to enable HTTPS in the server:
$ pyluxa4 serve --ssl-cert pyluxa4.cer --ssl-key private.key
Now the server will only accept commands over HTTPS.
$ pyluxa4 api
{'status': 'fail', 'code': 0, 'error': 'Server does not appear to be running'}
To send commands with over HTTPS to the server, simply use the --secure
parameter. If you send the command with 0
, it will ignore verifying the certificate:
$ pyluxa4 api --secure 0
c:\Python36\lib\site-packages\urllib3\connectionpool.py:851: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
{'error': '', 'path': '/pyluxa4/api/version', 'status': 'success', 'version': '1.5.1', 'version_path': '/pyluxa4/api/v1.5'}
If you provide the certificate instead, it will verify the certificate:
$ pyluxa4 api --secure pyluxa4.cer
{'error': '', 'path': '/pyluxa4/api/version', 'status': 'success', 'version': '1.5.1', 'version_path': '/pyluxa4/api/v1.5'}
Token Authentication
In addition to using SSL for HTTPS, using token authentication can help make it more difficult for anyone to send commands to your Luxafor device. Tokens should really only be used with SSL.
Simply specify your desired token using the the --token
parameter when initiating the server:
$ pyluxa4 serve --ssl-cert pyluxa4.cer --ssl-key private.key --token secret
Now the server will reject commands that require authentication if they are sent without the token.
$ pyluxa4 color red --secure pyluxa4.cer
{'status': 'fail', 'code': 401, 'error': 'Unauthorized Access'}
But when we provide the token, the command passes:
$ pyluxa4 color red --secure pyluxa4.cer --token secret
{'code': 200, 'error': '', 'path': '/pyluxa4/api/v1.5/command/color', 'status': 'success'}
Commands that Don't Require Authentication
api
is the one command that does not require authentication. It will accept commands with or without tokens.