Better redis doc

This commit is contained in:
sam 2020-09-22 12:00:02 +02:00
parent 56e95c4c4b
commit c5c7051ddc
3 changed files with 566 additions and 6 deletions

View File

@ -172,18 +172,18 @@ A "plugin" is a software that send any number of pointlist(s). LJ comes with dif
# Client Side : Program your own "plugin"
#
The server approach is based on redis, so you can write and run your laser client software in any redis capable programming langage (50+ : https://redis.io/clients). An external program that just send pointlists is a "client". If you want some interactions from the webUI, like text status area support, crash detection, launch,... it's a "plugin" and some default code is needed. See custom1.py, a basic plugin you can modiffy. LJ and plugins signaling is mainly over OSC.
The server approach is based on redis, so you can write and run your laser client software in any redis capable programming langage (50+ : https://redis.io/clients). An external program that just send pointlists to redis is a "client". If you want some interactions from the webUI, like text status area support, crash detection, autostart,... it's a "plugin" and some default code is needed. LJ and plugins signaling is over OSC.
- Read all this readme ;-)
- Generate at least one pointlist array (say a square) with *enough points*, one point is likely to fail for buffering reason. See command reference below for more.
- Feed your point list array in string format to redis server. i.e use "/pl/0/1" redis key to feed scene 0, laser 1.
- Generate at least one pointlist array (say a square) with *enough points*, one point is likely to fail for buffering reason.
- Feed your point list array in string format to redis server. i.e use "/pl/0/1" redis key to feed scene 0, laser 1. See /pl/ command in command reference below how to send your pointlist to i.e /pl/0/1 redis key.
- Tell LJ.conf your plugin configuration : OSC port and command line to start it.
- At least a plugin must reply /pong to OSC request /ping.
Currently the WebUI (www/index.html) is static.
#
# Client side dope mode : How to use lj23 (python3)
# Client side dope mode for python 3 generators : How to use lj23
#
lj23 have many very useful functions to not reinvent the wheel for advanced points generation "client" side : layers, sprites, built in rotations,..
@ -191,7 +191,7 @@ lj23 have many very useful functions to not reinvent the wheel for advanced poin
4 Great TRICKS with lj23 :
First open square.py and learn how to declare different objects. square.py is a 2D shape example in 3D rotation (red/green anaglyph rendering) that use 2 layers : one for left eye and one for right eye.
First open custom1.py and learn how to declare different objects. custom1.py is a 2D shape example in 3D rotation (red/green anaglyph rendering) that use 2 layers : one for left eye and one for right eye. custom1 is a copy of square.py
1/ How to have another laser drawing the same thing ?
@ -370,12 +370,16 @@ Generic :
# LJ commands reference
#
All commands are available via OSC (port 8002) or websocket (port 9001)
All these commands are available via OSC (port 8002) or websocket (port 9001)
/pl/scenenumber/lasernumber value : value is the pointlist to draw as string. Example :
/pl/0/0 "[(150.0, 230.0, 65280), (170.0, 170.0, 65280), (230.0, 170.0, 65280), (210.0, 230.0, 65280), (150.0, 230.0, 65280)]"
Use the same syntax if you send your pointlist directly in redis : "/pl/0/0" is the key and value is "[(150.0,..."
Every point must be : (x,y,color). Color is the hex color #FFFFFF in decimal.
/scale/X/lasernumber value

277
plugins/custom1.py Normal file
View File

@ -0,0 +1,277 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
custom1
v0.1.0
A copy of square.py you can modify to code your plugin.
custom1 has necessary hooks in LJ.conf, webui and so on.
LICENCE : CC
by Sam Neurohack
'''
import sys
import os
print()
ljpath = r'%s' % os.getcwd().replace('\\','/')
# import from shell
sys.path.append(ljpath +'/../libs/')
#import from LJ
sys.path.append(ljpath +'/libs/')
print(ljpath+'/../libs/')
import lj23layers as lj
sys.path.append('../libs')
from OSC3 import OSCServer, OSCClient, OSCMessage
import redis
import math
import time
import argparse
OSCinPort = 8014
print ("")
print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="Custom1 example for LJ")
argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str)
argsparser.add_argument("-s","--scene",help="LJ scene number (0 by default)",type=int)
#argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int)
argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int)
argsparser.add_argument("-m","--myIP",help="Local IP (127.0.0.1 by default) ",type=str)
args = argsparser.parse_args()
if args.scene:
ljscene = args.scene
else:
ljscene = 0
'''
if args.laser:
plnumber = args.laser
else:
plnumber = 0
'''
# Redis Computer IP
if args.redisIP != None:
redisIP = args.redisIP
else:
redisIP = '127.0.0.1'
print("redisIP",redisIP)
# myIP
if args.myIP != None:
myIP = args.myIP
else:
myIP = '127.0.0.1'
print("myIP",myIP)
if args.verbose:
debug = args.verbose
else:
debug = 0
# Useful variables init.
white = lj.rgb2int(255,255,255)
red = lj.rgb2int(255,0,0)
blue = lj.rgb2int(0,0,255)
green = lj.rgb2int(0,255,0)
width = 800
height = 600
centerX = width / 2
centerY = height / 2
# 3D to 2D projection parameters
fov = 256
viewer_distance = 2.2
# Anaglyph computation parameters for right and left eyes.
# algorythm come from anaglyph geo maps
eye_spacing = 100
nadir = 0.5
observer_altitude = 30000
map_layerane_altitude = 0.0
# square coordinates : vertices that compose each of the square.
vertices = [
(- 1.0, 1.0,- 1.0),
( 1.0, 1.0,- 1.0),
( 1.0,- 1.0,- 1.0),
(- 1.0,- 1.0,- 1.0)
]
face = [0,1,2,3]
#
# LJ inits
#
layer = 0
# Setup LJ library mandatory properties for this plugin
lj.Config(redisIP, ljscene, "custom1")
# Define properties for each drawn "element" : name, intensity, active, xy, color, red, green, blue, layer , closed
Leftsquare = lj.FixedObject('Leftsquare', True, 255, [], red, 255, 0, 0, layer , True)
Rightsquare = lj.FixedObject('Rightsquare', True, 255, [], green, 0, 255, 0, layer , True)
# 'Destination' for given layer : name, number, active, layer , scene, laser
Dest0 = lj.DestObject('0', 0, True, 0 , 0, 0) # Dest0 will send layer 0 points to scene 0, laser 0
#
# Anaglyph computation : different X coordinate for each eye
#
def LeftShift(elevation):
diff = elevation - map_layerane_altitude
return nadir * eye_spacing * diff / (observer_altitude - elevation)
def RightShift(elevation):
diff = map_layerane_altitude - elevation
return (1 - nadir) * eye_spacing * diff / (observer_altitude - elevation)
#
# OSC
#
oscserver = OSCServer( (myIP, OSCinPort) )
oscserver.timeout = 0
# this method of reporting timeouts only works by convention
# that before calling handle_request() field .timed_out is
# set to False
def handle_timeout(self):
self.timed_out = True
# funny python's way to add a method to an instance of a class
import types
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
# OSC callbacks
# /custom1/ljscene
def OSCljscene(path, tags, args, source):
print("Got /custom1/ljscene with value", args[0])
lj.WebStatus("custom1 to virtual "+ str(args[0]))
ljscene = args[0]
lj.Ljscene(ljscene)
def Proj(x,y,z,angleX,angleY,angleZ):
rad = angleX * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
y2 = y
y = y2 * cosa - z * sina
z = y2 * sina + z * cosa
rad = angleY * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
z2 = z
z = z2 * cosa - x * sina
x = z2 * sina + x * cosa
rad = angleZ * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
x2 = x
x = x2 * cosa - y * sina
y = x2 * sina + y * cosa
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + z)
x = x * factor + centerX
y = - y * factor + centerY
return (x,y)
#
# Main
#
def Run():
Left = []
Right = []
counter =0
#lj.SendLJ("/custom1/start 1")
# OSC Server callbacks
print("Starting OSC server at",myIP," port",OSCinPort,"...")
oscserver.addMsgHandler( "/custom1/ljscene", OSCljscene )
# Add OSC generic plugins commands : 'default", /ping, /quit, /pluginame/obj, /pluginame/var, /pluginame/adddest, /pluginame/deldest
lj.addOSCdefaults(oscserver)
try:
while lj.oscrun:
lj.OSCframe()
Left = []
Right = []
x = vertices[0][0]
y = vertices[0][1]
z = vertices[0][2]
# LJ tracers will "move" the laser to this first point in black, then move to the next with second point color.
# For more accuracy in dac emulator, repeat this first point.
# Generate all points in square.
for point in face:
x = vertices[point][0]
y = vertices[point][1]
z = vertices[point][2]
Left.append(Proj(x+LeftShift(z*25),y,z,0,counter,0))
Right.append(Proj(x+RightShift(z*25),y,z,0,counter,0))
lj.PolyLineOneColor(Left, c = Leftsquare.color , layer = Leftsquare.layer, closed = Leftsquare.closed)
lj.PolyLineOneColor(Right, c = Rightsquare.color , layer = Rightsquare.layer, closed = Rightsquare.closed)
lj.DrawDests()
time.sleep(0.1)
counter += 1
if counter > 360:
counter = 0
except KeyboardInterrupt:
pass
# Gently stop on CTRL C
finally:
lj.ClosePlugin()
Run()

279
plugins/square.py Normal file
View File

@ -0,0 +1,279 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
'''
Square
v0.1.0
Anaglyphed rotating square (for red and green glasses)
This scene uses the drawing functions provided by LJ in lj23.py
LICENCE : CC
by Sam Neurohack
'''
import sys
import os
print()
ljpath = r'%s' % os.getcwd().replace('\\','/')
# import from shell
sys.path.append(ljpath +'/../libs/')
#import from LJ
sys.path.append(ljpath +'/libs/')
print(ljpath+'/../libs/')
import lj23layers as lj
sys.path.append('../libs')
from OSC3 import OSCServer, OSCClient, OSCMessage
import redis
import math
import time
import argparse
OSCinPort = 8013
print ("")
print ("Arguments parsing if needed...")
argsparser = argparse.ArgumentParser(description="Square example for LJ")
argsparser.add_argument("-r","--redisIP",help="IP of the Redis server used by LJ (127.0.0.1 by default) ",type=str)
argsparser.add_argument("-s","--scene",help="LJ scene number (0 by default)",type=int)
#argsparser.add_argument("-l","--laser",help="Laser number to be displayed (0 by default)",type=int)
argsparser.add_argument("-v","--verbose",help="Verbosity level (0 by default)",type=int)
argsparser.add_argument("-m","--myIP",help="Local IP (127.0.0.1 by default) ",type=str)
args = argsparser.parse_args()
if args.scene:
ljscene = args.scene
else:
ljscene = 0
'''
if args.laser:
plnumber = args.laser
else:
plnumber = 0
'''
# Redis Computer IP
if args.redisIP != None:
redisIP = args.redisIP
else:
redisIP = '127.0.0.1'
print("redisIP",redisIP)
# myIP
if args.myIP != None:
myIP = args.myIP
else:
myIP = '127.0.0.1'
print("myIP",myIP)
if args.verbose:
debug = args.verbose
else:
debug = 0
# Useful variables init.
white = lj.rgb2int(255,255,255)
red = lj.rgb2int(255,0,0)
blue = lj.rgb2int(0,0,255)
green = lj.rgb2int(0,255,0)
width = 800
height = 600
centerX = width / 2
centerY = height / 2
# 3D to 2D projection parameters
fov = 256
viewer_distance = 2.2
# Anaglyph computation parameters for right and left eyes.
# algorythm come from anaglyph geo maps
eye_spacing = 100
nadir = 0.5
observer_altitude = 30000
map_layerane_altitude = 0.0
# square coordinates : vertices that compose each of the square.
vertices = [
(- 1.0, 1.0,- 1.0),
( 1.0, 1.0,- 1.0),
( 1.0,- 1.0,- 1.0),
(- 1.0,- 1.0,- 1.0)
]
face = [0,1,2,3]
#
# LJ inits
#
layer = 0
# Setup LJ library mandatory properties.
lj.Config(redisIP, ljscene, "square")
# You can define properties for each drawn "element" : name, intensity, active, xy, color, red, green, blue, layer , closed
Leftsquare = lj.FixedObject('Leftsquare', True, 255, [], red, 255, 0, 0, layer , True)
Rightsquare = lj.FixedObject('Rightsquare', True, 255, [], blue, 0, 255, 0, layer , True)
# 'Destination' for given layer : name, number, active, layer , scene, laser
Dest0 = lj.DestObject('0', 0, True, 0 , 0, 0) # Dest0 will send layer 0 points to scene 0, laser 0
#
# Anaglyph computation : different X coordinate for each eye
#
def LeftShift(elevation):
diff = elevation - map_layerane_altitude
return nadir * eye_spacing * diff / (observer_altitude - elevation)
def RightShift(elevation):
diff = map_layerane_altitude - elevation
return (1 - nadir) * eye_spacing * diff / (observer_altitude - elevation)
#
# OSC
#
oscserver = OSCServer( (myIP, OSCinPort) )
oscserver.timeout = 0
# this method of reporting timeouts only works by convention
# that before calling handle_request() field .timed_out is
# set to False
def handle_timeout(self):
self.timed_out = True
# funny python's way to add a method to an instance of a class
import types
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
# OSC callbacks
# /square/ljscene
def OSCljscene(path, tags, args, source):
print("Got /square/ljscene with value", args[0])
lj.WebStatus("square to virtual "+ str(args[0]))
ljscene = args[0]
lj.Ljscene(ljscene)
def Proj(x,y,z,angleX,angleY,angleZ):
rad = angleX * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
y2 = y
y = y2 * cosa - z * sina
z = y2 * sina + z * cosa
rad = angleY * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
z2 = z
z = z2 * cosa - x * sina
x = z2 * sina + x * cosa
rad = angleZ * math.pi / 180
cosa = math.cos(rad)
sina = math.sin(rad)
x2 = x
x = x2 * cosa - y * sina
y = x2 * sina + y * cosa
""" Transforms this 3D point to 2D using a perspective projection. """
factor = fov / (viewer_distance + z)
x = x * factor + centerX
y = - y * factor + centerY
return (x,y)
#
# Main
#
def Run():
Left = []
Right = []
counter =0
lj.WebStatus("Square")
lj.SendLJ("/square/start 1")
# OSC Server callbacks
print("Starting OSC server at",myIP," port",OSCinPort,"...")
oscserver.addMsgHandler( "/square/ljscene", OSCljscene )
# Add OSC generic plugins commands : 'default", /ping, /quit, /pluginame/obj, /pluginame/var, /pluginame/adddest, /pluginame/deldest
lj.addOSCdefaults(oscserver)
try:
while lj.oscrun:
lj.OSCframe()
Left = []
Right = []
x = vertices[0][0]
y = vertices[0][1]
z = vertices[0][2]
# LJ tracers will "move" the laser to this first point in black, then move to the next with second point color.
# For more accuracy in dac emulator, repeat this first point.
# Generate all points in square.
for point in face:
x = vertices[point][0]
y = vertices[point][1]
z = vertices[point][2]
Left.append(Proj(x+LeftShift(z*25),y,z,0,counter,0))
Right.append(Proj(x+RightShift(z*25),y,z,0,counter,0))
lj.PolyLineOneColor(Left, c = Leftsquare.color , layer = Leftsquare.layer, closed = Leftsquare.closed)
lj.PolyLineOneColor(Right, c = Rightsquare.color , layer = Rightsquare.layer, closed = Rightsquare.closed)
lj.DrawDests()
time.sleep(0.1)
counter += 1
if counter > 360:
counter = 0
except KeyboardInterrupt:
pass
# Gently stop on CTRL C
finally:
lj.ClosePlugin()
Run()