LJ/main.py

453 lines
12 KiB
Python
Raw Normal View History

2019-01-16 00:50:24 +00:00
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
# -*- mode: Python -*-
2018-12-13 11:05:32 +00:00
'''
2019-03-10 22:06:04 +00:00
LJ Laser Server v0.8.1
2018-12-13 11:05:32 +00:00
2019-08-06 01:08:54 +00:00
Inspiration for new WebUI icon menu :
https://codepen.io/AlbertFeynman/pen/mjXeMV
2018-12-13 11:05:32 +00:00
Laser server + webUI servers (ws + OSC)
- get point list to draw : /pl/lasernumber
- for report /lstt/lasernumber /lack/lasernumber /cap/lasernumber
2019-02-10 15:53:51 +00:00
- A nice ws debug tool : websocat
2019-08-06 01:08:54 +00:00
- a "plugin" is a generator that send points to LJ. Plugins if they have an open OSC port can be checked and restart if in the same computer.
2018-12-13 11:05:32 +00:00
2019-03-10 22:06:04 +00:00
Todo :
2018-12-13 11:05:32 +00:00
2019-03-10 22:06:04 +00:00
- If no plugin ping is not received, restart the plugin.
- upgrade to python3
All used ports:
8002 OSC incoming
9001 WS communication with WebGUI
2019-08-06 01:08:54 +00:00
Plugins OSC Ports (see LJ.conf)
2018-12-13 11:05:32 +00:00
'''
2019-02-26 10:10:57 +00:00
2018-12-13 11:05:32 +00:00
print ""
print ""
2019-03-10 22:06:04 +00:00
print "LJ Laser Server"
2019-08-06 01:08:54 +00:00
print "v0.8.2"
2018-12-13 11:05:32 +00:00
print ""
2019-08-06 01:08:54 +00:00
import redis
from libs import gstt, settings
2018-12-13 11:05:32 +00:00
settings.Read()
2019-08-06 01:08:54 +00:00
# Arguments may alter .conf file so import settings first then cli
from libs import cli
settings.Write()
2019-08-06 01:08:54 +00:00
2018-12-13 11:05:32 +00:00
from multiprocessing import Process, Queue, TimeoutError
import random, ast
2019-08-06 01:08:54 +00:00
from libs import plugins, tracer, homographyp, commands, font1
2018-12-13 11:05:32 +00:00
2019-03-10 22:06:04 +00:00
import subprocess
import sys
import os
2019-08-06 01:08:54 +00:00
#import midi
2018-12-13 11:05:32 +00:00
from OSC import OSCServer, OSCClient, OSCMessage
from websocket_server import WebsocketServer
#import socket
import types, thread, time
2019-08-06 01:08:54 +00:00
2018-12-13 11:05:32 +00:00
r = redis.StrictRedis(host=gstt.LjayServerIP , port=6379, db=0)
2018-12-15 19:03:32 +00:00
args =[0,0]
2018-12-13 11:05:32 +00:00
2018-12-18 01:45:23 +00:00
2018-12-13 11:05:32 +00:00
def dac_process(number, pl):
while True:
try:
2018-12-21 16:23:43 +00:00
d = tracer.DAC(number,pl)
2018-12-13 11:05:32 +00:00
d.play_stream()
except Exception as e:
import sys, traceback
if gstt.debug == 2:
print '\n---------------------'
print 'Exception: %s' % e
print '- - - - - - - - - - -'
traceback.print_tb(sys.exc_info()[2])
print "\n"
pass
except KeyboardInterrupt:
sys.exit(0)
#
# webUI server
#
2019-08-06 01:08:54 +00:00
print "Laser client number :",gstt.SceneNumber
2018-12-13 11:05:32 +00:00
serverIP = gstt.LjayServerIP
print "Redis IP :", serverIP
oscserverIP = gstt.oscIPin
print "OSCserver IP :", oscserverIP
2018-12-13 11:05:32 +00:00
nozoscIP = gstt.nozoscip
print "Nozosc IP :", nozoscIP
debug = gstt.debug
print "Debug :", debug
lasernumber = gstt.LaserNumber -1
print "Lasers requested :", gstt.LaserNumber
# Websocket listening port
wsPORT = 9001
# oscserver
2019-01-16 00:50:24 +00:00
# OSC Server : accept OSC message on port 8002
2018-12-15 19:03:32 +00:00
#oscIPin = "192.168.1.10"s
oscserverIPin = serverIP
2019-03-20 16:33:09 +00:00
print "oscserverIPin", oscserverIPin
oscserverPORTin = 8002
2018-12-13 11:05:32 +00:00
2019-01-16 00:50:24 +00:00
# OSC Client : to send OSC message to an IP port 8001
oscserverIPout = oscserverIP
oscserverPORTout = 8001
2018-12-13 11:05:32 +00:00
# Nozoid OSC Client : to send OSC message to Nozoid inport 8003
2018-12-13 11:05:32 +00:00
NozoscIPout = nozoscIP
2019-03-10 22:06:04 +00:00
NozoscPORTout = plugins.Port("nozoid")
2018-12-13 11:05:32 +00:00
2018-12-15 19:03:32 +00:00
# Planetarium OSC Client : to send OSC message to planetarium inport 8005
2019-02-26 10:10:57 +00:00
planetIPout = nozoscIP
2019-03-10 22:06:04 +00:00
planetPORTout = plugins.Port("planet")
2019-02-26 10:10:57 +00:00
# Bank0 OSC Client : to send OSC message to bank0 inport 8010
2019-03-10 22:06:04 +00:00
bank0IPout = nozoscIP
bank0PORTout = plugins.Port("bank0")
2019-02-26 10:10:57 +00:00
oscserver = OSCServer( (oscserverIPin, oscserverPORTin) )
2018-12-13 11:05:32 +00:00
oscserver.timeout = 0
OSCRunning = True
def handle_timeout(self):
self.timed_out = True
oscserver.handle_timeout = types.MethodType(handle_timeout, oscserver)
2019-03-10 22:06:04 +00:00
2019-01-16 00:50:24 +00:00
# OSC default path handler : send incoming OSC message to UI via websocket 9001
2018-12-13 11:05:32 +00:00
def handler(path, tags, args, source):
oscpath = path.split("/")
2019-08-06 01:08:54 +00:00
if gstt.debug > 0:
print ""
print "OSC handler in main said : path", path," oscpath ", oscpath," args", args
if oscpath[1] != "pong":
sendWSall(path + " " + str(args[0]))
2018-12-21 16:23:43 +00:00
commands.handler(oscpath,args)
2018-12-13 11:05:32 +00:00
# RAW OSC Frame available ?
def osc_frame():
2018-12-18 01:45:23 +00:00
#print 'oscframe'
2018-12-13 11:05:32 +00:00
# clear timed_out flag
oscserver.timed_out = False
# handle all pending requests then return
while not oscserver.timed_out:
oscserver.handle_request()
def PingAll():
2019-08-06 01:08:54 +00:00
print ("Pinging all plugins...")
for plugin in gstt.plugins.keys():
2019-08-06 01:08:54 +00:00
print("pinging", plugin)
#sendWSall("/"+ plugin + "/start 0")
plugins.Ping(plugin)
2018-12-13 11:05:32 +00:00
2019-01-16 00:50:24 +00:00
# OSC server Thread : handler, dacs reports and simulator points sender to UI.
2018-12-13 11:05:32 +00:00
def osc_thread():
2019-08-06 01:08:54 +00:00
#while True:
2018-12-13 11:05:32 +00:00
try:
while True:
2018-12-31 02:41:02 +00:00
time.sleep(0.1)
2018-12-13 11:05:32 +00:00
osc_frame()
2018-12-15 19:03:32 +00:00
for laserid in range(0,gstt.LaserNumber): # Laser not used -> led is not lit
2018-12-13 11:05:32 +00:00
lstt = r.get('/lstt/'+ str(laserid))
#print "laserid", laserid,"lstt",lstt
if lstt == "0": # Dac IDLE state(0) -> led is blue (3)
sendWSall("/lstt/" + str(laserid) + " 3")
if lstt == "1": # Dac PREPARE state (1) -> led is cyan (2)
sendWSall("/lstt/" + str(laserid) + " 2")
if lstt == "2": # Dac PLAYING (2) -> led is green (1)
sendWSall("/lstt/" + str(laserid) + " 1")
2018-12-15 19:03:32 +00:00
2018-12-13 11:05:32 +00:00
lack= r.get('/lack/'+str(laserid))
2019-02-26 10:10:57 +00:00
if gstt.debug >1:
print "laserid", laserid, "lack", lack
2018-12-13 11:05:32 +00:00
if lack == 'a': # Dac sent ACK ("a") -> led is green (1)
sendWSall("/lack/" + str(laserid) +" 1")
if lack == 'F': # Dac sent FULL ("F") -> led is orange (5)
sendWSall("/lack/" + str(laserid) +" 5")
if lack == 'I': # Dac sent INVALID ("I") -> led is yellow (4)
sendWSall("/lack/" + str(laserid)+" 4")
#print lack
if lack == "64" or lack =="35": # no connection to dac -> leds are red (6)
sendWSall("/lack/" + str(laserid) + " 0")
sendWSall("/lstt/" + str(laserid) + " 0")
#sendWSall("/lstt/" + str(laserid) + " 0")
sendWSall("/points/" + str(laserid) + " 0")
else:
# last number of points sent to etherdream buffer
sendWSall("/points/" + str(laserid) + " " + str(r.get('/cap/'+str(laserid))))
2019-08-06 01:08:54 +00:00
#print "Sending simu frame from",'/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)
#print r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser))
sendWSall("/simul" +" "+ r.get('/pl/'+str(gstt.SceneNumber)+'/'+str(gstt.Laser)))
2018-12-13 11:05:32 +00:00
except Exception as e:
import sys, traceback
print '\n---------------------'
print 'Exception: %s' % e
print '- - - - - - - - - - -'
traceback.print_tb(sys.exc_info()[2])
print "\n"
#
# Websocket part
#
# Called for every WS client connecting (after handshake)
2019-03-10 22:06:04 +00:00
def new_client(client, wserver):
2018-12-15 19:03:32 +00:00
2018-12-13 11:05:32 +00:00
print("New WS client connected and was given id %d" % client['id'])
sendWSall("/status Hello %d" % client['id'])
for laserid in range(0,gstt.LaserNumber):
2019-08-06 01:08:54 +00:00
sendWSall("/ip/" + str(laserid) + " " + str(gstt.lasersIPS[laserid]))
sendWSall("/kpps/" + str(laserid)+ " " + str(gstt.kpps[laserid]))
2019-08-06 01:08:54 +00:00
sendWSall("/laser"+str(laserid)+"/start 1")
if gstt.swapX[laserid] == 1:
2018-12-15 19:03:32 +00:00
sendWSall("/swap/X/" + str(laserid)+ " 1")
else:
2018-12-15 19:03:32 +00:00
sendWSall("/swap/X/" + str(laserid)+ " 0")
if gstt.swapY[laserid] == 1:
2018-12-15 19:03:32 +00:00
sendWSall("/swap/Y/" + str(laserid)+ " 1")
else:
2018-12-15 19:03:32 +00:00
sendWSall("/swap/Y/" + str(laserid)+ " 0")
2018-12-13 11:05:32 +00:00
# Called for every WS client disconnecting
2019-03-10 22:06:04 +00:00
def client_left(client, wserver):
2018-12-13 11:05:32 +00:00
print("WS Client(%d) disconnected" % client['id'])
2019-03-10 22:06:04 +00:00
# Called for each WS received message.
def message_received(client, wserver, message):
2018-12-13 11:05:32 +00:00
if len(message) > 200:
message = message[:200]+'..'
2018-12-15 19:03:32 +00:00
2019-02-26 10:10:57 +00:00
#if gstt.debug >0:
# print ("")
# print("WS Client(%d) said: %s" % (client['id'], message))
2018-12-15 19:03:32 +00:00
2019-02-26 10:10:57 +00:00
print("")
2018-12-13 11:05:32 +00:00
oscpath = message.split(" ")
if gstt.debug > 0:
print "WS Client", client['id'], "said :", message, "splitted in an oscpath :", oscpath
2019-08-06 01:08:54 +00:00
PingAll()
message4plugin = False
2019-03-17 03:19:57 +00:00
# WS received Message is for a plugin ?
2019-03-17 03:19:57 +00:00
for plugin in gstt.plugins.keys():
if oscpath[0].find(plugin) != -1:
message4plugin = True
if plugins.Send(plugin,oscpath):
2019-08-06 01:08:54 +00:00
print "message sent correctly to", plugin
else:
print"plugin was offline"
2019-02-26 10:10:57 +00:00
# WS received message is an LJ command
2019-03-17 03:19:57 +00:00
if message4plugin == False:
2019-03-17 03:19:57 +00:00
if len(oscpath) == 1:
args[0] = "noargs"
#print "noargs command"
2019-03-17 03:19:57 +00:00
elif len(oscpath) > 1:
args[0] = str(oscpath[1])
#print "arg",oscpath[1]
commands.handler(oscpath[0].split("/"),args)
print ""
2018-12-13 11:05:32 +00:00
2019-03-10 22:06:04 +00:00
2018-12-13 11:05:32 +00:00
# if needed a loop back : WS Client -> server -> WS Client
#sendWSall("ws"+message)
def handle_timeout(self):
self.timed_out = True
def sendWSall(message):
2018-12-27 11:40:30 +00:00
#if gstt.debug >0:
#print("WS sending %s" % (message))
2019-03-10 22:06:04 +00:00
wserver.send_message_to_all(message)
2019-08-06 01:08:54 +00:00
'''
print ""
print "Midi Configuration"
midi.InConfig()
midi.OutConfig()
'''
2018-12-13 11:05:32 +00:00
2018-12-19 11:39:54 +00:00
# Creating a startup point list for each client : 0,1,2,...
2018-12-13 11:05:32 +00:00
2018-12-19 11:39:54 +00:00
print ""
2019-08-06 01:08:54 +00:00
for clientid in range(0,gstt.MaxScenes+1):
2018-12-19 11:39:54 +00:00
print "Creating startup point lists for client",clientid,"..."
digit_points = font1.DigitsDots(clientid,65280)
2018-12-13 11:05:32 +00:00
2018-12-19 11:39:54 +00:00
# Order all lasers to show the laser client number at startup -> tell all 4 laser process to USER PLs
for laserid in range(0,gstt.LaserNumber):
2018-12-13 11:05:32 +00:00
2018-12-19 11:39:54 +00:00
if r.set('/pl/'+str(clientid)+'/'+str(laserid), str(digit_points)) == True:
print "/pl/"+str(clientid)+"/"+str(laserid)+" ", ast.literal_eval(r.get('/pl/'+str(clientid)+'/'+str(laserid)))
2018-12-13 11:05:32 +00:00
2018-12-19 11:39:54 +00:00
r.set('/order/'+str(laserid), 0)
2019-08-06 01:08:54 +00:00
if r.set("/clientkey","/pl/"+str(gstt.SceneNumber)+"/")==True:
print "sent clientkey : /pl/"+str(gstt.SceneNumber)+"/"
2018-12-13 11:05:32 +00:00
print ""
print "Etherdream connection check is NOT DISPLAYED"
2018-12-13 11:05:32 +00:00
# Launch one process (a newdacp instance) by etherdream
print ""
dac_worker0= Process(target=dac_process,args=(0,0))
print "Launching Laser 0 Process..."
dac_worker0.start()
if lasernumber >0:
dac_worker1= Process(target=dac_process,args=(1,0))
print "Launching Laser 1 Process..."
dac_worker1.start()
if lasernumber >1:
dac_worker2= Process(target=dac_process,args=(2,0))
print "Launching Laser 2 Process..."
dac_worker2.start()
if lasernumber >2:
dac_worker3= Process(target=dac_process,args=(3,0))
print "Launching Laser 3 Process..."
dac_worker3.start()
2019-03-10 22:06:04 +00:00
2018-12-13 11:05:32 +00:00
# Main loop do nothing. Maybe do the webui server ?
try:
#while True:
# Websocket startup
2019-03-10 22:06:04 +00:00
wserver = WebsocketServer(wsPORT,host=serverIP)
plugins.Init(wserver)
# Launch OSC thread listening to oscserver
2018-12-13 11:05:32 +00:00
print ""
print "Launching OSC server..."
print "at", oscserverIPin, "port",str(oscserverPORTin)
print "Will update webUI dac status every second"
2018-12-21 16:23:43 +00:00
oscserver.addMsgHandler( "/noteon", commands.NoteOn )
# Default OSC handler for all OSC incoming message
oscserver.addMsgHandler("default", handler)
2018-12-18 01:45:23 +00:00
thread.start_new_thread(osc_thread, ())
2018-12-13 11:05:32 +00:00
2019-03-10 22:06:04 +00:00
#print wserver
2018-12-13 11:05:32 +00:00
print ""
print "Launching webUI Websocket server..."
print "at", serverIP, "port",wsPORT
2019-03-10 22:06:04 +00:00
wserver.set_fn_new_client(new_client)
wserver.set_fn_client_left(client_left)
wserver.set_fn_message_received(message_received)
print ""
print "Resetting all Homographies.."
for laserid in range(0,gstt.LaserNumber):
homographyp.newEDH(laserid)
2018-12-13 11:05:32 +00:00
print ""
2019-08-06 01:08:54 +00:00
print "WS server running forever..."
2019-03-10 22:06:04 +00:00
wserver.run_forever()
2018-12-13 11:05:32 +00:00
except KeyboardInterrupt:
pass
# Gently stop on CTRL C
finally:
dac_worker0.join()
if lasernumber >0:
dac_worker1.join()
if lasernumber >1:
dac_worker2.join()
if lasernumber >2:
dac_worker3.join()
for laserid in range(0,lasernumber+1):
2018-12-15 19:03:32 +00:00
print "Laser",laserid,"feedbacks reset."
2018-12-13 11:05:32 +00:00
r.set('/lack/'+str(laserid),64)
r.set('/lstt/'+str(laserid),64)
r.set('/cap/'+str(laserid),0)
2019-02-10 15:53:51 +00:00
print "Fin de LJ."
2018-12-13 11:05:32 +00:00
2018-12-18 01:45:23 +00:00
'''
Some code previously used, for reference :
random_points = [(300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 0), (500.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280), (500.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 400.0+random.randint(-100, 100), 65280), (300.0+random.randint(-100, 100), 200.0+random.randint(-100, 100), 65280)]
'''
2018-12-13 11:05:32 +00:00