#! /usr/bin/python3
# -*- coding: utf-8 -*-
"""
This file is part of LibreLight.
LibreLight is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 2 of the License.
LibreLight is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LibreLight. If not, see .
(c) 2012 micha@librelight.de
"""
import sys
import time
import json
import zlib
rnd_id = ""
rnd_id += " Beta 22.02 "
import subprocess
import tool.git as git
rnd_id += git.get_all()
import lib.binfs as binfs
binfs.fname="/tmp/vmaster.bin"
#binfs.data =[0]*1024
#binfs.patch(self._v_master_id,vm)
binfs.debug = 0
binfs.loop()
if "__file__" in dir():
sys.stdout.write("\x1b]2;"+str(__file__)+" "+rnd_id+"\x07") # terminal title
else:
sys.stdout.write("\x1b]2;"+str("__file__")+" "+rnd_if+"\x07") # terminal title
__run_main = 0
if __name__ == "__main__":
__run_main = 1
else:
import __main__
print(dir())
if "unittest" not in dir(__main__):
__run_main = 1
import time
import socket
import struct
import sys
import random
import math
from collections import OrderedDict
import lib.zchat as chat
import lib.ArtNetNode as ANN
import _thread as thread
#thread.start_new_thread
#import lib.motion as motion
#idmx = [0]*512 # incremental dmx
dmx = [0]*512 # absolute dmx data
gcolor = 1
def cprint(*text,color="blue",space=" ",end="\n"):
color = color.lower()
#return 0 #disable print dbg
if not gcolor:
print(text)
return 0
if color == "green":
txt = '\033[92m'
elif color == "red":
txt = '\033[0;31m\033[1m'
elif color == "yellow":
txt = '\033[93m\033[1m'
elif color == "cyan":
txt = '\033[96m'
else:
txt = '\033[94m'
for t in text:
txt += str(t ) +" "
#HEADER = '\033[95m'
#OKBLUE = '\033[94m'
#OKCYAN = '\033[96m'
#OKGREEN = '\033[92m'
#WARNING = '\033[93m'
#FAIL = '\033[91m'
#ENDC = '\033[0m'
#BOLD = '\033[1m'
#UNDERLINE = '\033[4m'
txt += '\033[0m'
print(txt,end=end)
#return txt
def artnet_loop():
#artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=12)
#artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=0)
artnet = ANN.ArtNetNode(to="10.10.10.255",univ=0)
#artnet = ANN.ArtNetNode(to="2.0.0.255",univ=0)
#artnet = ANN.ArtNetNode(to="10.10.10.255",univ=1)
#dmx[205] = 255 #205 BLUE
artnet.dmx= dmx #[0]*512
artnet.send()
while 1:
#artnet._test_frame()
artnet.next()
time.sleep(0.001)
class CLOCK():
def __init__(self):
self.__time = 0
self.__start = time.time() # only for debugging
self.__tick = 0.01 # incremental timer drift's on highe cpu load ?
def time(self):
return self.__time
def get_drift(self):
run_time = time.time() - self.__start
tick_time = self.__time # * self.__tick
print( "runtime:{:0.2f} tick_timer:{:0.2f} drift:{:0.2f}".format(run_time,tick_time,run_time-tick_time))
def loop(self):
while 1:
self.__time +=self.__tick
#if int(self.__time*100)/10. % 10 == 0:# self.__time % 2 == 0:
# print( self.get_drift())
#print(self.__time)
#for i in range(10):
time.sleep(self.__tick)
class CLOCK_REAL():
def __init__(self):
self.__time = 0
self.__start = time.time() # only for debugging
self.__tick = 0.001 # incremental timer drift's on highe cpu load ?
def time(self):
self.__time = time.time()
return self.__time
def get_drift(self):
run_time = time.time() - self.__start
tick_time = self.__time # * self.__tick
print( "runtime:{:0.2f} tick_timer:{:0.2f} drift:{:0.2f}".format(run_time,tick_time,run_time-tick_time))
def loop(self):
pass
#clock = CLOCK()
clock = CLOCK_REAL()
if __run_main:
thread.start_new_thread(clock.loop,())
class Fade():
def __init__(self,start,target,ftime,clock,delay=0):
#print("init Fade ",start,target,ftime,clock)
if delay < 0:
delay = 0.0001
if ftime <= 0:
ftime = 0.0001
clock += delay
self.__delay = delay
self.__clock = clock
self.__clock_curr = clock
self.__ftime = ftime
self.__start = start
self.__last = start
self.__target = target
self.abs = 0
self.run = 1
self.end = 0
self.off = 0
#print("INIT", str(self) )
def __str__(self):
return self.__repr__()
def __repr__(self):
return "".format(
self.__last, self.__start,self.__target,self.__ftime,self.__clock_curr,self.run,self.__delay )
def next(self,clock=None):
if self.__ftime <= 0 and self.__delay <= 0:
self.__last = self.__target
self.end = 1
self.run = 0
if type(clock) is float or type(clock) is int:#not None:
self.__clock_curr = clock
if self.__target > self.__start:
if self.__last >= self.__target:
self.run = 0
self.end = 1
return self.__target
else:
if self.__last <= self.__target:
self.run = 0
self.end = 1
return self.__target
current = (self.__clock - self.__clock_curr) / self.__ftime
length = self.__start - self.__target
self.__last = self.__start+ length*current
self.run = 1
return self.__last
def ctl(self,cmd="",value=None): # if x-fade cmd="%" value=50
pass
class _MASTER():
def __init__(self,name="None"):
self.__data = {}
self.name = name
def val(self,name,value=None):
_value = 100 #%
name = str(name)
if name not in self.__data:
self.__data[name] = 100
_value = self.__data[name]
if value is not None:
if _value != value:
print(self.name,"CHANGE MASTER:",name,"from:",_value,"to:",value)
self.__data[name] = value
_value = self.__data[name]
return _value /100.
exec_size_master = _MASTER("EXEC-SIZE")
exec_speed_master = _MASTER("EXEC-SPEED")
exec_offset_master = _MASTER("EXEC-OFFSET")
size_master = _MASTER("SIZE")
speed_master = _MASTER("SPEED")
exe_master = []
exe_master.append({"SIZE":100,"SPEED":100,"id":12,"link-ids":[2]})
class MASTER_FX():
def __init__(self):
self.__data = []
self.__ok = []
self.i=0
self.old_offsets = []
self.offsets = []
self.count = -1
self.init = 10
def add(self,fx):
if fx not in self.__data:
self.__data.append(fx)
info = fx._get_info()
offset = 0
if "offset" in info:
offset = info["offset"]
self.old_offsets.append(offset)
self.offsets.append(offset)
if "xtype" in info:
if info["xtype"] == "rnd":
self._shuffle()
def _shuffle(self):
random.seed(1000)
random.shuffle(self.old_offsets)
def _init(self):
self._shuffle()
for i,v in enumerate(self.old_offsets):
offset = self.old_offsets[i]
self.offsets[i] = offset
self.init = 0
def next(self,child):
i = self.__data.index(child)
offset = self.old_offsets[i]
self.offsets[i] = offset
return offset
def get(self,child,count):
offset = 0
if child not in self.__data:
return offset
if self.init:
self._init()
idx = self.__data.index(child)
if (self.count != count and idx == 0 ) or self.init == 0:
self.init = 1
self._shuffle()
self.count=count
idx = self.__data.index(child)
offset = self.offsets[idx]
return offset
class FX():
def __init__(self,xtype="sinus",size=10,speed=10,invert=0,width=100,start=0,offset=0,base="",clock=0,master=None,master_id=0):
self.__xtype=xtype
self.__size = size
self.__start = start
self.__master_id = master_id
if width > 200:
width = 200
if width <= 0:
width = 1
self.__fade_in_master = 0
self.__width = width
self.__invert = invert
self.__base = base
self.__speed = speed
self.__offset = offset
self.__clock = clock
self.__clock_curr = clock
self.__clock_delta = 0
self.__clock_old = self.__clock_curr
self.out = 0
self.old_v = -1
self.run = 1
self.count = -1
self.abs = 0 # ABSOLUT
self.__angel = self.__clock_curr*360%360
if master is None:
cprint(master, "MASTER_FX ERR",master,color="red")
self.__master = MASTER_FX()
self.__master.add(self)
else:
self.__master = master
self.__master.add(self)
if self.__xtype == "rnd":
self.__offset = self.__master.get(self,-2)
self.__offset = self.__master.next(self)#,count)
self._exec_id = None
self.next()
def exec_id(self,_id=None):
if type(_id) is not type(None):
self._exec_id = str(_id)
return self._exec_id
def _get_info(self):
return {"offset":self.__offset,"xtype":self.__xtype}
def __str__(self):
return self.__repr__()
def __repr__(self):
ABS = "INC"
if self.abs:
ABS = "ABS"
return "".format(
self.next(), self.__xtype, self.__size, self.__speed, self.__angel
, self.__base, self.__clock_curr, self.run, self._exec_id,ABS )
def _calc_fx(self,v,t,size,base):
base = 0
if self.__base == "-": # sub
if self.__invert:
v = 1-v
size *=-1
v *=-1
elif self.__base == "+": # sub
if self.__invert:
v = v-1
else:
v = (t%1-0.5)
return v
def next(self,clock=None):
if type(clock) is float or type(clock) is int:#not None:
self.__clock_curr = clock
d = (self.__clock_curr - self.__clock_old)
m1 = ( speed_master.val(self.__master_id)) # global speed-master
m2 = ( exec_speed_master.val(self._exec_id)) # exec start by 0
shift = 0
m = (m1 * m2) -1
shift += d * m
self.__clock_delta += shift
self.__clock_old = self.__clock_curr
t = self.__clock_curr
t += self.__clock_delta
t *= self.__speed / 60
offset2 = self.__offset
offset2 *= exec_offset_master.val(self._exec_id)
t += offset2 / 100
t += self.__start / 1024 #255
tw = t%1
count = t//1
t = t * (100/self.__width)
if tw > self.__width/100:
t = 1
self.__angel = t%1*360
t = t%1
rad = math.radians(self.__angel)
self.abs = 0
v=0
out = 0
base = 0
size = self.__size
if self.__base == "+": # add
base = size/2
elif self.__base == "-": # sub
base = size/2*-1
if self.__xtype == "sinus":
v = math.sin( rad )
v/=2
elif self.__xtype == "cosinus":
v = math.cos( rad )
if self.__base == "+": # add
size *= -1
v/=2
elif self.__xtype == "rnd":
#base = 0
if self.__angel > 90 and self.__angel <=270:
v=1
else:
v=0
#if count != self.count and v: # % 2 == 0:#!= self.count:
# #self.__offset = random.randint(0,1024)# /1024
# self.__master._shuffle()
if count != self.count and v == 0: # and v: # % 2 == 0:#!= self.count:
self.__master.next(self)#,count)
#self.__master.next(self)#,count)
self.__offset = self.__master.get(self,count)
base = 0
if self.__base == "-": # sub
if self.__invert:
v = 1-v
#base = -size
size *=-1
v *=-1
elif self.__base == "+": # sub
if self.__invert:
v = v-1
else:
v = (t%1-0.5)
elif self.__xtype == "on":
#base = 0
if self.__angel > 90 and self.__angel <=270:
v=1
else:
v=0
base = 0
if self.__base == "-": # sub
if self.__invert:
v = 1-v
#base = -size
size *=-1
v *=-1
elif self.__base == "+": # sub
if self.__invert:
v = v-1
else:
v = (t%1-0.5)
elif self.__xtype == "ramp" or self.__xtype == "bump":
v = (t%1)
base = 0
if self.__base == "-": # sub
if self.__invert:
v = 1-v
#base = -size
size *=-1
v *=-1
elif self.__base == "+": # sub
if self.__invert:
v = v-1
else:
v = (t%1-0.5)
elif self.__xtype == "ramp2" or self.__xtype == "bump2":
v = (t%1)
v = 1-v
if v == 1:
v=0
base = 0
if self.__base == "-": # sub
if self.__invert:
v = 1-v
#base = -size
size *=-1
v *=-1
elif self.__base == "+": # sub
if self.__invert:
v = v-1
else:
v = (t%1-0.5)
elif self.__xtype == "static":
self.abs = 1
base = size #100
v=0
size=0
elif self.__xtype == "fade":
x = t * 2
if x > 1:
x = 2-x
x -= 0.5
v = x*2
#base /= 2
#base *=2
if self.__base == "+": # add
pass#base /= 2
else:
v *= -1
v/=2
if self.__invert:
v *=-1
#if self.__fade_in_master < 255:
# self.__fade_in_master += v*size
out = v *size +base
self.out = out
self.count = count
out = out * size_master.val(self.__master_id) # master
out = out * exec_size_master.val(self._exec_id) # master
#* (self.__fade_in_master /255.)
return out
class DMXCH(object):
def __init__(self,dmx=-1):
self._base_value = 0
self._fade = None
self._fx = [None,None] # None
self._fx_value = 0
self._dmx = dmx
self._dmx_fine = 0
self._fix_id = 0
self._v_master_id=0
self._last_val_raw=0
self._flash = None
self._flash_fx = None
self._flash_fx_value = 0
self._last_val = None
self._exec_ids = [None,None,None,None] # go, go-fx, flash, flash-fx
def fade(self,target,ftime=0,clock=0,delay=0):
if target != self._base_value:
try:
target = float(target)
self._fade = Fade(self._base_value,target,ftime=ftime,clock=clock,delay=delay)
except Exception as e:
print( "Except:fade",e,target,ftime,clock)
self.next(clock)
def fx(self,xtype="sinus",size=40,speed=40,invert=0,width=100,start=0,offset=0,base="", clock=0,master=None):
self._fx[0] = self._fx[1]
if str(xtype).lower() == "off":
fx_value = self._fx_value
if fx_value != 0:
#cprint("???????______ FX OFF AS FADE",fx_value,0,255)
if self._fx[1].abs:
self._fx[1] = Fade(self._last_val_raw,0,ftime=0.5,clock=clock)
else:
self._fx[1] = Fade(fx_value,0,ftime=0.5,clock=clock)
else:
self._fx[1] = None
self._fx_value = 0
else:
self._fx[1] = FX(xtype=xtype,size=size,speed=speed,invert=invert
,width=width,start=start,offset=offset,base=base
,clock=clock,master=master,master_id=1)
self._fx[1].exec_id(self._exec_ids[1])
self.next(clock)
def flash(self,target,ftime=0,clock=0,delay=0):
if str(target).lower() == "off":
if self._flash:
cur_val = self._flash.next()
cur_tar = self._base_value
self._flash = Fade(cur_val,cur_tar,ftime=ftime,clock=clock)
self._flash.off = 1
else:
try:
target = float(target)
self._flash = Fade(self._last_val,target,ftime=ftime,clock=clock,delay=delay)
self._flash = Fade(self._last_val,target,ftime=0,clock=clock,delay=delay)
except Exception as e:
print( "Except:flash",target,ftime,clock,__name__,e,)
self.next(clock)
def flash_fx(self,xtype="sinus",size=40,speed=40,invert=0,width=100,start=0,offset=0,base="",clock=0,master=None):
if str(xtype).lower() == "off":
fx_value = self._fx_value
self._flash_fx = None
self._flash_fx_value = 0
else:
self._flash_fx = FX(xtype=xtype,size=size,speed=speed,invert=invert
,width=width,start=start,offset=offset,base=base
,clock=clock,master=master,master_id=0)
self._flash_fx.exec_id(self._exec_ids[3])
self.next(clock)
#print("init flash_fx",self)
def fx_ctl(self,cmd=""): #start,stop,off
pass
def __str__(self):
return self.__repr__()
def exec_ids(self,_id=None):
#if type(_id) is not type(None):
# #self._exec_id = _id
# #print("set exec_id",_id)
return self._exec_ids
def __repr__(self):
v = self._last_val
if type(self._last_val) in [int,float]:
v = round(self._last_val,2)
return "= val:
val = v
flag = 1
out = 1.
if val > 255:
val = 255
if flag:
out = val/255.
else:
out = 1.
return out
vdmx = VDMX()
class HTP_MASTER():
"""functional implementation as class for namespace encapsulation
"""
def __init__(self):
self.data = OrderedDict()
#self.data[1] = {"DMX":[1,2,3],"VALUE":80, "LIMIT":255}
#self.data[2] = {"DMX":[12,13,22],"VALUE":70, "LIMIT":255}
#self.data[3] = {"DMX":[22,23,24],"VALUE":99, "LIMIT":255}
self.data[4] = {"DMX":[22,23,24],"VALUE":99, "LIMIT":255,"DMXCH":DMXCH(4)}
def _list_by_dmx(self,_dmx=0):
data = OrderedDict()
for i,link in self.data.items(): # enumerate(self.data):
if _dmx in link["DMX"]:
#print( "_list_by_dmx",i,link)
data[i] = link
return data
def dmx_by_id(self,_id=0):
#print("dmx by master-id:",_id)
if _id in self.data:
for i,link in self.data[_id].items():
#print("dmx_by_id", i,link)
return (i,link)
return 0,{}
def val_by_dmx(self,dmx=0):
#print("master of dmx:",dmx)
val=0
flag = 0
data = self._list_by_dmx(dmx)
for i,link in data.items():
#print("master_by_dmx", i,link)
if link["VALUE"] > val:
#print("master_by_dmx", i,link)
val = link["VALUE"]
flag=1
out = 1.
if flag:
out = val/255.
return out
htp_master = HTP_MASTER()
#htp_master.data[_id] = {"DMX":[1,2,3],"VALUE":80, "LIMIT":255,"DMXCH":DMXCH()}
class Main():
def __init__(self):
self.artnet = {}
self.fx = {} # key is dmx address
self.lock = thread.allocate_lock()
def loop(self):
xx = [0]*512
ii = 0
old_univ = -1
xx = [0]*512
for ii,dmxch in enumerate(Bdmx):
i = ii%512
univ = ii//512
if str(univ) not in self.artnet:
print("add uiv",univ)
self.artnet[str(univ)] = ANN.ArtNetNode(to="10.10.10.255",univ=univ)
if univ != old_univ:
old_univ = univ
try:
artnet.next()
except:pass
artnet = self.artnet[str(univ)]
artnet.dmx = [0]*512
fps_start = time.time()
fps = 0
dbg= 0#1
while 1:
self.lock.acquire_lock()
start = time.time()
_t=0
t = clock.time()
ii = 0
old_univ = -1
xx = [0]*512
for ii,dmxch in enumerate(Bdmx):
i = ii%512
univ = ii//512
s_univ = str(univ)
if s_univ not in self.artnet:
print("add uiv",univ)
self.artnet[s_univ] = ANN.ArtNetNode(to="10.10.10.255",univ=univ)
if dbg:
end = time.time()
print(" t",_t,ii,round(end-start,4))
start = time.time()
_t+=1
old_univ = -1
xx = [0]*512
for ii,dmxch in enumerate(Bdmx):
i = ii%512
univ = ii//512
if univ != old_univ:
old_univ = univ
artnet = self.artnet[str(univ)]
xx = artnet.dmx
v = dmxch.next(t)
xx[i] = int(v)
if dbg:
end = time.time()
print(" t",_t,ii,round(end-start,4))
start = time.time()
_t+=1
old_univ = -1
xx = [0]*512
for ii,dmxch in enumerate(Bdmx): #fine loop
dmx_fine = dmxch._dmx_fine
if dmx_fine > 0:
i = ii%512
univ = ii//512
if univ != old_univ:
artnet = self.artnet[str(univ)]
xx = artnet.dmx# = xx
v = dmxch.next(t)
vv = vdmx.by_dmx(clock=i,dmx=ii+1)
try:
v = v*vv # disable v-master
except Exception as e:
cprint("Exception v*vv",[v,vv],e)
continue
vf = int(v%1*255)
dmx_fine = dmx_fine%512
try:
if v >= 255:
xx[dmx_fine-1] = 255
elif v < 0:
xx[dmx_fine-1] = 0
else:
xx[dmx_fine-1] = int(v%1*255)
except Exception as e:
print("E dmx_fine",e,dmx_fine)
if dbg:
end = time.time()
print(" t",_t,ii,round(end-start,4))
print()
start = time.time()
_t+=1
self.lock.release_lock()
for k,artnet in self.artnet.items():
artnet.next()
fps += 1
stop_fps = 50
time.sleep(1/30)
if fps >= stop_fps:
fps_t = time.time()
FPS = round(stop_fps/(fps_t-fps_start),2)
print("{:0.0f} core/fps".format(FPS) )
fps = 0
fps_start = time.time()
main = Main()
if __run_main:
thread.start_new_thread(main.loop,())
def _init_action(row):#Bdmx,out,DMX):
Admx = row["DMXCH"]
line_sub_count = 0
if row["fx"]:
x = row["fx"]
Admx.fx(xtype=x["xtype"]
,size=x["size"]
,speed=x["speed"]
,invert=x["invert"]
,width=x["width"]
,start=x["start"]
,offset=x["offset"]
,base=x["base"]
,clock=x["clock"]
,master=x["master"])
line_sub_count += 1
if row["flash_fx"]:
x = row["flash_fx"]
Admx.flash_fx(xtype=x["xtype"]
,size=x["size"]
,speed=x["speed"]
,invert=x["invert"]
,width=x["width"]
,start=x["start"]
,offset=x["offset"]
,base=x["base"]
,clock=x["clock"]
,master=x["master"])
line_sub_count += 1
if row["flash"]:
x = row["flash"]
Admx.flash(target=x["target"]
,ftime=x["ftime"]
,clock=x["clock"]
,delay=x["delay"])
line_sub_count += 1
if row["fade"]:
x = row["fade"]
Admx.fade(target=x["target"]
,ftime=x["ftime"]
,clock=x["clock"]
,delay=x["delay"])
line_sub_count += 1
return line_sub_count
def set_dmx_fine_ch(Admx,dmx_fine_nr):
try:
if int(dmx_fine_nr) > 0:
Admx._dmx_fine = int(dmx_fine_nr)
except Exception as e:
cprint(x,color="red")
cprint("except 3455",e,color="red")
def _parse_fx2(x,fx2,clock):
if type(fx2) is dict and fx2:
pass
else:
return
xtype="fade"
size = 10
speed = 10
start = 0
offset= 0
width=100
invert=0
base = "-"
if "TYPE" in fx2:
xtype = fx2["TYPE"]
if "SIZE" in fx2:
size = fx2["SIZE"]
if "SPEED" in fx2:
speed = fx2["SPEED"]
if "OFFSET" in fx2:
offset = fx2["OFFSET"]
if "BASE" in fx2:
base = fx2["BASE"]
if "INVERT" in fx2:
invert = fx2["INVERT"]
if "WIDTH" in fx2:
width = fx2["WIDTH"]
if "off" == x["VALUE"]: #fix fx flash off
xtype= "off"
if "alloff" == xtype.lower():
for dmxch in Bdmx:
if dmxch is not None:
dmxch.flash_fx(xtype="off",clock=clock)
dmxch.fx(xtype="off",clock=clock)
for j in V_MASTER:
dmxch = V_MASTER[j]
if j is not None:
dmxch.flash_fx(xtype="off",clock=clock)
dmxch.fx(xtype="off",clock=clock)
xout = {"xtype":xtype,"size":size,"speed":speed
,"invert":invert,"width":width,"start":start
,"offset":offset,"base":base,"clock":clock,"master":0
}
#,"offset":offset,"base":base,"clock":c,"master":master_fx
mode="fx"
if "FLASH" in x:
mode = "flash_fx"
return [mode,xout]
def _parse_master(x):
print("CMD:",x)
if "EXEC-SPEED-MASTER" == x["CMD"]:
exec_speed_master.val(x["NR"],x["VALUE"])
if "EXEC-SIZE-MASTER" == x["CMD"]:
exec_size_master.val(x["NR"],x["VALUE"])
if "EXEC-OFFSET-MASTER" == x["CMD"]:
exec_offset_master.val(x["NR"],x["VALUE"])
if "SPEED-MASTER" == x["CMD"]:
speed_master.val(x["NR"],x["VALUE"])
if "SIZE-MASTER" == x["CMD"]:
size_master.val(x["NR"],x["VALUE"])
def _parse_cmds(cmds,clock=0):
out = {}
for cmd in cmds:
try:
_parse_cmd(out,cmd,clock=clock)
except Exception as e:
cprint("EXCEPTION JCB",e,color="red")
cprint("----",str(cmds)[:150],"...",color="red")
cprint("Error on line {}".format(sys.exc_info()[-1].tb_lineno),color="red")
raise e
return out
def _parse_cmd(out,cmd,clock=0):
master_fx = MASTER_FX()
Admx = DMXCH() #dummy
x=cmd
c=clock
_fix_id=0
_attr = ""
if "CMD" in x:
_parse_master(x)
return #continue
if "DMX" not in x:
return #continue
DMX = int(x["DMX"])
if "VALUE" not in x:
return #continue
_val = x["VALUE"]
_inc = 0
_fix_id = 0
_clock = 0
exec_id = None
if "INC" in x:
_inc = x["INC"]
if "FIX" in x:
_fix_id = x["FIX"]
if "clock" in x:
_clock=x["clock"]
if "ATTR" in x:
_attr = x["ATTR"]
if DMX <= 0: # VIRTUAL
DMX = "FIX"+str(_fix_id)
ok = 0
if "ATTR" in x:
_attr = x["ATTR"]
if "DIM" == x["ATTR"]:
if _fix_id not in V_MASTER:
V_MASTER[_fix_id] = DMXCH()
#print("_val",_val)
#V_MASTER[_fix_id].fade(_val,ftime=0,clock=0,delay=0)
#print(" V-MASTER",_fix_id,_val,_inc)
ok = 1
if _fix_id in V_MASTER:
Admx = V_MASTER[_fix_id]
if not ok:
return #continue
else:
if DMX < len(Bdmx):
Admx = Bdmx[DMX-1]
else:
print("DMX ADDRESS too BIG",DMX)
return #continue
if "DMX-FINE" in x and DMX > 0:
set_dmx_fine_ch(Admx, x["DMX-FINE"])
if "EXEC" in x:
exec_id = x["EXEC"]
if "ATTR" in x:
_attr = x["ATTR"]
if "FIX" in x:
_fix_id = x["FIX"]
fx=""
fx2={}
ftime=0
delay=0
if "FX" in x:
fx = x["FX"]
if "FX2" in x:
fx2 = x["FX2"]
if "FADE" in x:
ftime = x["FADE"]
if "DELAY" in x:
delay = x["DELAY"]
#print("DO",[exec_id],x)
# ids = [401,402,304,103]
# exec-id, exec-fx-id, flush-id, flush-fx-id
if _val != "off":
if "FLASH" in x:
ids = Admx.exec_ids()
if type(_val) is int:
ids[2] = exec_id
if fx2:
ids[3] = exec_id
#print(" ",[ids, exec_id],"FL")
else: # GO or ON
ids = Admx.exec_ids()
if type(_val) is int:
ids[0] = exec_id
if fx2:
ids[1] = exec_id
#print(" ",[ids, exec_id],"GO")
if _val == "off":
# flash bug if lot's of virtual dimmer are RELEASED-FROM-FLASH ("FLASH off")
# the V-MASTER FLASH ist HANGING ... no ENCODER change possible !!! ???
if 0: # "FLASH" in x:
ids = Admx.exec_ids()
stop = 0
#print(" ",[ids, exec_id])
if ids[2] != exec_id:
stop = 1
else:
ids[2] = None
if fx2:
if ids[3] != exec_id:
stop = 1
else:
ids[3] = None
stop = 0
if stop:
# this FLASH cmd OFF/RELEASE is not valid anymore
return #continue
#aprint("OK")
#ids = Admx.exec_ids()
#print("OK ",[ids, exec_id])
#Bdmx[DMX].exec_id(exec_id)
out[DMX] = {"flash":{},"fade":{},"fx":{},"flash_fx":{},"fix_id":_fix_id,"attr":_attr,"DMXCH":Admx}
if _val is not None:
Xval = {"target":_val,"ftime":ftime, "clock":c,"delay":delay,"DMXCH":Admx}
mode = "fade"
if "FLASH" in x:
mode = "flash"
out[DMX][mode] = Xval
# FX PARSE
_fx2 = _parse_fx2(x,fx2,clock=c)
if _fx2:
_key=_fx2[0] # fx, fx_flash
Xval=_fx2[1] # dict
Xval["master"] = master_fx
out[DMX][_key] = Xval
elif type(fx) is str and fx:
# old fx like sinus:200:12:244
ccm = str(DMX+1)+":"+fx
print("fx",ccm)
if "FLASH" in x:
pass #CB({"cmd":"fxf"+ccm})
else:
pass #CB({"cmd":"fx"+ccm})
def calc_jitter(jdatas,t_start):
for cmds in jdatas:
for line in cmds:
if "time" in line:
jt_start = line["time"]
latenz = round(t_start-jt_start,4)
if latenz > 0.5:
cprint("jitter 0.5 >",latenz,color="red")
break
def process_flash(jdatas):
for cmds in jdatas:
for line in cmds: # run first
if "FLASH" in line:
cprint("FLUSH",end=" ",color="CYAN")
if "VALUE" in line:
if line["VALUE"] == "off":
cprint("OFF",end=" ",color="red")
else:
cprint("ON",end=" ",color="green")
print("")
else:
cprint("FADE",color="CYAN")
break
def parse_json(data):
jdatas = []
l2 = 0
print("INPUT JCB =>",len(data),":",l2)
for line in data:
data2 = json.loads(line)
l2 += len(data2)
jdatas.append(data2) #["CMD"])
jdatas2 = []
for cmds in jdatas:
if not cmds:
continue
jdatas2.append(cmds)
return jdatas2
import hashlib
JCB_GLOB_BUF = {}
def JCB(data,sock=None): #json client input
t_start = time.time()
s = time.time()
e = time.time()
ct = int(e*100)/100
print()
msg = "{} JCB START: {:0.02f} sizeof:{}"
msg = msg.format(ct,e-s,sys.getsizeof(data) )
print(msg)
jdatas = parse_json(data)
c = clock.time()
c = float(c)
ftime = 0
delay = 0
out = {}
line=""
process_flash(jdatas)
calc_jitter(jdatas,t_start)
for cmds in jdatas:
master_fx = MASTER_FX()
out = _parse_cmds(cmds,clock=c)
line_count = 0
line_count_sub = 0
line_size = 0
attr_count = {}
attr_count2 = 0
if not out:
return
try:
main.lock.acquire_lock()
for _id in out:
row = out[_id]
#print(" ",_id,[str(row)])
line_size += sys.getsizeof(row)
#print("_id",_id)
Admx = row["DMXCH"]
#print("Admx",Admx)
if "attr" in row:
if row["attr"] not in attr_count:
attr_count[row["attr"]] = 0
attr_count[row["attr"]] += 1
attr_count2 +=1
if row["fix_id"]:
_fix_id = row["fix_id"]
Admx._fix_id = _fix_id
if "attr" in row:
if row["attr"] in ["RED","GREEN","BLUE","WHITE","AMBER"]: #CYAN,MAGENTA,YELLOW
Admx._v_master_id = _fix_id
#print("SET V_MASTER",row)
line_count_sub += _init_action(row)
line_count += 1
e = time.time()
print(" sub-JCB TIME:","{:0.02f}".format(e-s),int(e*100)/100)
#time.sleep(1/30)
except Exception as e:
cprint("EXCEPTION JCB",e,color="red")
cprint("----",str(cmds)[:150],"...",color="red")
cprint("Error on line {}".format(sys.exc_info()[-1].tb_lineno),color="red")
raise e
finally:
main.lock.release_lock()
#cprint(" ","{:0.04} sec.".format(time.time()-t_start),color="yellow")
print("attr_count:",attr_count)
#print(line_count,line_size)
e = time.time()
ct = int(e*100)/100
msg = "{} JCB: END {:0.02f} sizeof:{} fix-count:{} attr-count:{}"
msg = msg.format(ct,e-s,line_size,line_count,line_count_sub )
print(msg)
time.sleep(1/60)
if __run_main:
s = chat.Server(cb=JCB)
while 1:
s.poll()
time.sleep(0.001)