_console.py 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367
  1. #! /usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. This file is part of LibreLight.
  5. LibreLight is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, version 2 of the License.
  8. LibreLight is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with LibreLight. If not, see <http://www.gnu.org/licenses/>.
  14. (c) 2012 micha@librelight.de
  15. """
  16. import sys
  17. import time
  18. import json
  19. import zlib
  20. rnd_id = ""
  21. rnd_id += " Beta 22.02 "
  22. import subprocess
  23. import tool.git as git
  24. rnd_id += git.get_all()
  25. if "__file__" in dir():
  26. sys.stdout.write("\x1b]2;"+str(__file__)+" "+rnd_id+"\x07") # terminal title
  27. else:
  28. sys.stdout.write("\x1b]2;"+str("__file__")+" "+rnd_if+"\x07") # terminal title
  29. __run_main = 0
  30. if __name__ == "__main__":
  31. __run_main = 1
  32. else:
  33. import __main__
  34. print(dir())
  35. if "unittest" not in dir(__main__):
  36. __run_main = 1
  37. import time
  38. import socket
  39. import struct
  40. import sys
  41. import random
  42. import math
  43. from collections import OrderedDict
  44. import lib.zchat as chat
  45. import lib.ArtNetNode as ANN
  46. import _thread as thread
  47. #thread.start_new_thread
  48. import lib.motion as motion
  49. #idmx = [0]*512 # incremental dmx
  50. dmx = [0]*512 # absolute dmx data
  51. gcolor = 1
  52. def cprint(*text,color="blue",space=" ",end="\n"):
  53. color = color.lower()
  54. #return 0 #disable print dbg
  55. if not gcolor:
  56. print(text)
  57. return 0
  58. if color == "green":
  59. txt = '\033[92m'
  60. elif color == "red":
  61. txt = '\033[0;31m\033[1m'
  62. elif color == "yellow":
  63. txt = '\033[93m\033[1m'
  64. elif color == "cyan":
  65. txt = '\033[96m'
  66. else:
  67. txt = '\033[94m'
  68. for t in text:
  69. txt += str(t ) +" "
  70. #HEADER = '\033[95m'
  71. #OKBLUE = '\033[94m'
  72. #OKCYAN = '\033[96m'
  73. #OKGREEN = '\033[92m'
  74. #WARNING = '\033[93m'
  75. #FAIL = '\033[91m'
  76. #ENDC = '\033[0m'
  77. #BOLD = '\033[1m'
  78. #UNDERLINE = '\033[4m'
  79. txt += '\033[0m'
  80. print(txt,end=end)
  81. #return txt
  82. def artnet_loop():
  83. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=12)
  84. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=0)
  85. artnet = ANN.ArtNetNode(to="10.10.10.255",univ=0)
  86. #artnet = ANN.ArtNetNode(to="2.0.0.255",univ=0)
  87. #artnet = ANN.ArtNetNode(to="10.10.10.255",univ=1)
  88. #dmx[205] = 255 #205 BLUE
  89. artnet.dmx= dmx #[0]*512
  90. artnet.send()
  91. while 1:
  92. #artnet._test_frame()
  93. artnet.next()
  94. time.sleep(0.001)
  95. class CLOCK():
  96. def __init__(self):
  97. self.__time = 0
  98. self.__start = time.time() # only for debugging
  99. self.__tick = 0.01 # incremental timer drift's on highe cpu load ?
  100. def time(self):
  101. return self.__time
  102. def get_drift(self):
  103. run_time = time.time() - self.__start
  104. tick_time = self.__time # * self.__tick
  105. print( "runtime:{:0.2f} tick_timer:{:0.2f} drift:{:0.2f}".format(run_time,tick_time,run_time-tick_time))
  106. def loop(self):
  107. while 1:
  108. self.__time +=self.__tick
  109. #if int(self.__time*100)/10. % 10 == 0:# self.__time % 2 == 0:
  110. # print( self.get_drift())
  111. #print(self.__time)
  112. #for i in range(10):
  113. time.sleep(self.__tick)
  114. class CLOCK_REAL():
  115. def __init__(self):
  116. self.__time = 0
  117. self.__start = time.time() # only for debugging
  118. self.__tick = 0.001 # incremental timer drift's on highe cpu load ?
  119. def time(self):
  120. self.__time = time.time()
  121. return self.__time
  122. def get_drift(self):
  123. run_time = time.time() - self.__start
  124. tick_time = self.__time # * self.__tick
  125. print( "runtime:{:0.2f} tick_timer:{:0.2f} drift:{:0.2f}".format(run_time,tick_time,run_time-tick_time))
  126. def loop(self):
  127. pass
  128. #clock = CLOCK()
  129. clock = CLOCK_REAL()
  130. if __run_main:
  131. thread.start_new_thread(clock.loop,())
  132. class Fade():
  133. def __init__(self,start,target,ftime,clock,delay=0):
  134. #print("init Fade ",start,target,ftime,clock)
  135. if delay < 0:
  136. delay = 0.0001
  137. if ftime <= 0:
  138. ftime = 0.0001
  139. clock += delay
  140. self.__delay = delay
  141. self.__clock = clock
  142. self.__clock_curr = clock
  143. self.__ftime = ftime
  144. self.__start = start
  145. self.__last = start
  146. self.__target = target
  147. self.abs = 0
  148. self.run = 1
  149. self.end = 0
  150. self.off = 0
  151. #print("INIT", str(self) )
  152. def __str__(self):
  153. return self.__repr__()
  154. def __repr__(self):
  155. return "<FADE Next:{:0.2f} from:{:0.2f} to:{:0.2f} ft:{:0.2f} Clock:{:0.2f} run:{} delay:{:0.2f}>".format(
  156. self.__last, self.__start,self.__target,self.__ftime,self.__clock_curr,self.run,self.__delay )
  157. def next(self,clock=None):
  158. if self.__ftime <= 0 and self.__delay <= 0:
  159. self.__last = self.__target
  160. self.end = 1
  161. self.run = 0
  162. if type(clock) is float or type(clock) is int:#not None:
  163. self.__clock_curr = clock
  164. if self.__target > self.__start:
  165. if self.__last >= self.__target:
  166. self.run = 0
  167. self.end = 1
  168. return self.__target
  169. else:
  170. if self.__last <= self.__target:
  171. self.run = 0
  172. self.end = 1
  173. return self.__target
  174. current = (self.__clock - self.__clock_curr) / self.__ftime
  175. length = self.__start - self.__target
  176. self.__last = self.__start+ length*current
  177. #if self.__last < 0:
  178. # self.__last = 0
  179. #if self.__last > 255:
  180. # self.__last = 255
  181. self.run = 1
  182. return self.__last
  183. def ctl(self,cmd="",value=None): # if x-fade cmd="%" value=50
  184. # start,stop,fwd,bwd,revers
  185. pass
  186. class _MASTER():
  187. def __init__(self,name="None"):
  188. self.__data = {}
  189. self.name = name
  190. def val(self,name,value=None):
  191. _value = 100 #%
  192. name = str(name)
  193. if name not in self.__data:
  194. self.__data[name] = 100
  195. _value = self.__data[name]
  196. if value is not None:
  197. if _value != value:
  198. print(self.name,"CHANGE MASTER:",name,"from:",_value,"to:",value)
  199. self.__data[name] = value
  200. _value = self.__data[name]
  201. return _value /100.
  202. exec_size_master = _MASTER("EXEC-SIZE")
  203. exec_speed_master = _MASTER("EXEC-SPEED")
  204. exec_offset_master = _MASTER("EXEC-OFFSET")
  205. size_master = _MASTER("SIZE")
  206. speed_master = _MASTER("SPEED")
  207. exe_master = []
  208. exe_master.append({"SIZE":100,"SPEED":100,"id":12,"link-ids":[2]})
  209. class MASTER_FX():
  210. def __init__(self):
  211. #cprint(self,"MASTER_FX INIT !",color="green")
  212. self.__data = []
  213. self.__ok = []
  214. self.i=0
  215. self.old_offsets = []
  216. self.offsets = []
  217. self.count = -1
  218. self.init = 10
  219. def add(self,fx):
  220. if fx not in self.__data:
  221. #cprint(self,"ADD TO MASTER !",color="green")
  222. self.__data.append(fx)
  223. info = fx._get_info()
  224. #cprint(self,"ADD" ,info,color="green")
  225. offset = 0
  226. if "offset" in info:
  227. offset = info["offset"]
  228. self.old_offsets.append(offset)
  229. self.offsets.append(offset)
  230. if "xtype" in info:
  231. if info["xtype"] == "rnd":
  232. self._shuffle()
  233. #self.init += 1
  234. def _shuffle(self):
  235. #cprint(self,"REORDER RANDOM !",color="green")
  236. #self.init = 0
  237. #cprint(self.old_offsets)
  238. random.seed(1000)
  239. random.shuffle(self.old_offsets)
  240. #cprint(self.old_offsets)
  241. def _init(self):
  242. self._shuffle()
  243. #self.offsets = []
  244. for i,v in enumerate(self.old_offsets):
  245. offset = self.old_offsets[i]
  246. self.offsets[i] = offset
  247. self.init = 0
  248. def next(self,child):
  249. i = self.__data.index(child)
  250. offset = self.old_offsets[i]
  251. self.offsets[i] = offset
  252. return offset
  253. #for i,v in enumerate(self.old_offsets):
  254. # offset = self.old_offsets[i]
  255. # self.offsets[i] = offset
  256. def get(self,child,count):
  257. offset = 0
  258. if child not in self.__data:
  259. return offset
  260. if self.init:
  261. self._init()
  262. idx = self.__data.index(child)
  263. if (self.count != count and idx == 0 ) or self.init == 0:
  264. self.init = 1
  265. self._shuffle()
  266. #print( count)
  267. self.count=count
  268. idx = self.__data.index(child)
  269. offset = self.offsets[idx]
  270. return offset
  271. class FX():
  272. 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):
  273. self.__xtype=xtype
  274. self.__size = size
  275. self.__start = start
  276. self.__master_id = master_id
  277. if width > 200:
  278. width = 200
  279. if width <= 0:
  280. width = 1
  281. self.__fade_in_master = 0
  282. self.__width = width
  283. self.__invert = invert
  284. self.__base = base
  285. self.__speed = speed
  286. self.__offset = offset
  287. self.__clock = clock
  288. self.__clock_curr = clock
  289. self.__clock_delta = 0
  290. self.__clock_old = self.__clock_curr
  291. self.out = 0
  292. self.old_v = -1
  293. self.run = 1
  294. self.count = -1
  295. self.abs = 0 # ABSOLUT
  296. self.__angel = self.__clock_curr*360%360
  297. if master is None:
  298. cprint(master, "MASTER_FX ERR",master,color="red")
  299. self.__master = MASTER_FX()
  300. self.__master.add(self)
  301. else:
  302. self.__master = master
  303. self.__master.add(self)
  304. if self.__xtype == "rnd":
  305. self.__offset = self.__master.get(self,-2)
  306. self.__offset = self.__master.next(self)#,count)
  307. self._exec_id = None
  308. self.next()
  309. def exec_id(self,_id=None):
  310. if type(_id) is not type(None):
  311. self._exec_id = str(_id)
  312. return self._exec_id
  313. def _get_info(self):
  314. return {"offset":self.__offset,"xtype":self.__xtype}
  315. def __str__(self):
  316. return self.__repr__()
  317. def __repr__(self):
  318. ABS = "INC"
  319. if self.abs:
  320. ABS = "ABS"
  321. return "<FX Next:{:0.2f} xtype:{} Size:{:0.2f} Speed:{:0.2f} ang:{:0.2f} base:{} Clock:{:0.2f} run:{} EXEC:{} :{}>".format(
  322. self.next(), self.__xtype, self.__size, self.__speed, self.__angel
  323. , self.__base, self.__clock_curr, self.run, self._exec_id,ABS )
  324. #def _calc_fx(self):
  325. def _calc_fx(self,v,t,size,base):
  326. base = 0
  327. if self.__base == "-": # sub
  328. if self.__invert:
  329. v = 1-v
  330. size *=-1
  331. v *=-1
  332. elif self.__base == "+": # sub
  333. if self.__invert:
  334. v = v-1
  335. else:
  336. v = (t%1-0.5)
  337. def next(self,clock=None):
  338. if type(clock) is float or type(clock) is int:#not None:
  339. self.__clock_curr = clock
  340. d = (self.__clock_curr - self.__clock_old)
  341. m1 = ( speed_master.val(self.__master_id)) # global speed-master
  342. m2 = ( exec_speed_master.val(self._exec_id)) # exec start by 0
  343. shift = 0
  344. m = (m1 * m2) -1
  345. shift += d * m
  346. self.__clock_delta += shift
  347. self.__clock_old = self.__clock_curr
  348. t = self.__clock_curr
  349. t += self.__clock_delta
  350. t *= self.__speed / 60
  351. offset2 = self.__offset
  352. offset2 *= exec_offset_master.val(self._exec_id)
  353. t += offset2 / 100
  354. t += self.__start / 1024 #255
  355. tw = t%1
  356. count = t//1
  357. t = t * (100/self.__width)
  358. if tw > self.__width/100:
  359. t = 1
  360. self.__angel = t%1*360
  361. t = t%1
  362. rad = math.radians(self.__angel)
  363. self.abs = 0
  364. v=0
  365. out = 0
  366. base = 0
  367. size = self.__size
  368. if self.__base == "+": # add
  369. base = size/2
  370. elif self.__base == "-": # sub
  371. base = size/2*-1
  372. if self.__xtype == "sinus":
  373. v = math.sin( rad )
  374. v/=2
  375. elif self.__xtype == "cosinus":
  376. v = math.cos( rad )
  377. if self.__base == "+": # add
  378. size *= -1
  379. v/=2
  380. elif self.__xtype == "rnd":
  381. if self.__angel > 90 and self.__angel <=270:
  382. v=1
  383. else:
  384. v=0
  385. if count != self.count and v == 0: # and v: # % 2 == 0:#!= self.count:
  386. self.__master.next(self)#,count)
  387. self.__offset = self.__master.get(self,count)
  388. self._calc_fx(v,t,size,base)
  389. elif self.__xtype == "on":
  390. if self.__angel > 90 and self.__angel <=270:
  391. v=1
  392. else:
  393. v=0
  394. self._calc_fx(v,t,size,base)
  395. elif self.__xtype == "ramp" or self.__xtype == "ramp":
  396. v = (t%1)
  397. base = 0
  398. if self.__base == "-": # sub
  399. if self.__invert:
  400. v = 1-v
  401. size *=-1
  402. v *=-1
  403. elif self.__base == "+": # sub
  404. if self.__invert:
  405. v = v-1
  406. else:
  407. v = (t%1-0.5)
  408. self._calc_fx(v,t,size,base)
  409. elif self.__xtype == "static":
  410. self.abs = 1
  411. base = size #100
  412. v=0
  413. size=0
  414. elif self.__xtype == "ramp2" or self.__xtype == "bump2":
  415. v = (t%1)
  416. v = 1-v
  417. if v == 1:
  418. v=0
  419. self._calc_fx(v,t,size,base)
  420. elif self.__xtype == "fade":
  421. x = t * 2
  422. if x > 1:
  423. x = 2-x
  424. x -= 0.5
  425. v = x*2
  426. if self.__base == "+": # add
  427. pass
  428. else:
  429. v *= -1
  430. v/=2
  431. if self.__invert:
  432. v *=-1
  433. out = v *size +base
  434. self.out = out
  435. self.count = count
  436. out = out * size_master.val(self.__master_id) # master
  437. out = out * exec_size_master.val(self._exec_id) # master
  438. return out
  439. class DMXCH(object):
  440. def __init__(self,dmx=-1):
  441. self._base_value = 0
  442. self._fade = None
  443. self._fx = [None,None] # None
  444. self._fx_value = 0
  445. self._dmx = dmx
  446. self._dmx_fine = 0
  447. self._fix_id = 0
  448. self._v_master_id=0
  449. self._flash = None
  450. self._flash_fx = None
  451. self._flash_fx_value = 0
  452. self._last_val = None
  453. self._exec_ids = [None,None,None,None] # go, go-fx, flash, flash-fx
  454. def fade(self,target,ftime=0,clock=0,delay=0):
  455. if target != self._base_value:
  456. try:
  457. target = float(target)
  458. self._fade = Fade(self._base_value,target,ftime=ftime,clock=clock,delay=delay)
  459. except Exception as e:
  460. print( "Except:fade",e,target,ftime,clock)
  461. self.next(clock)
  462. def fx(self,xtype="sinus",size=40,speed=40,invert=0,width=100,start=0,offset=0,base="", clock=0,master=None):
  463. self._fx[0] = self._fx[1]
  464. if str(xtype).lower() == "off":
  465. fx_value = self._fx_value
  466. if fx_value != 0:
  467. cprint("???????______ FX OFF AS FADE",fx_value,0,255)
  468. self._fx[1] = Fade(fx_value,0,ftime=0.5,clock=clock)
  469. else:
  470. self._fx[1] = None
  471. self._fx_value = 0
  472. else:
  473. self._fx[1] = FX(xtype=xtype,size=size,speed=speed,invert=invert
  474. ,width=width,start=start,offset=offset,base=base
  475. ,clock=clock,master=master,master_id=1)
  476. self._fx[1].exec_id(self._exec_ids[1])
  477. self.next(clock)
  478. def flash(self,target,ftime=0,clock=0,delay=0):
  479. if str(target).lower() == "off":
  480. if self._flash:
  481. cur_val = self._flash.next()
  482. cur_tar = self._base_value
  483. self._flash = Fade(cur_val,cur_tar,ftime=ftime,clock=clock)
  484. self._flash.off = 1
  485. else:
  486. try:
  487. target = float(target)
  488. self._flash = Fade(self._last_val,target,ftime=ftime,clock=clock,delay=delay)
  489. self._flash = Fade(self._last_val,target,ftime=0,clock=clock,delay=delay)
  490. except Exception as e:
  491. print( "Except:flash",target,ftime,clock,__name__,e,)
  492. self.next(clock)
  493. def flash_fx(self,xtype="sinus",size=40,speed=40,invert=0,width=100,start=0,offset=0,base="",clock=0,master=None):
  494. if str(xtype).lower() == "off":
  495. fx_value = self._fx_value
  496. self._flash_fx = None
  497. self._flash_fx_value = 0
  498. else:
  499. self._flash_fx = FX(xtype=xtype,size=size,speed=speed,invert=invert
  500. ,width=width,start=start,offset=offset,base=base
  501. ,clock=clock,master=master,master_id=0)
  502. self._flash_fx.exec_id(self._exec_ids[3])
  503. self.next(clock)
  504. #print("init flash_fx",self)
  505. def fx_ctl(self,cmd=""): #start,stop,off
  506. pass
  507. def __str__(self):
  508. return self.__repr__()
  509. def exec_ids(self,_id=None):
  510. #if type(_id) is not type(None):
  511. # #self._exec_id = _id
  512. # #print("set exec_id",_id)
  513. return self._exec_ids
  514. def __repr__(self):
  515. v = self._last_val
  516. if type(self._last_val) in [int,float]:
  517. v = round(self._last_val,2)
  518. return "<BUFFER DMX:{} FINE:{} VAL:{} EXEC:{}\n fd:{}\n fx:{}\n fx_flash:{}\n".format(
  519. self._dmx,self._dmx_fine
  520. ,v,str(self._exec_ids)
  521. ,self._fade
  522. ,self._fx
  523. ,self._flash_fx)
  524. def fade_ctl(self,cmd=""): #start,stop,backw,fwd,bounce
  525. pass
  526. def next(self,clock=0):
  527. try:
  528. self._next(clock)
  529. except Exception as e:
  530. cprint("Exception DMXCH.next()" ,e)
  531. out = self._last_val
  532. return out
  533. def _next(self,clock=0):
  534. value = self._base_value
  535. if self._last_val is None:
  536. self._last_val = value
  537. fx_value = self._fx_value
  538. fx_abs = 0
  539. if self._flash is not None:
  540. value = self._flash.next(clock)
  541. value = self._flash.next(clock) #flicker bug ?!
  542. if self._flash.end == 1 and self._flash.off == 1:
  543. self._flash = None
  544. fx_value = 0
  545. elif self._fade is not None: # is Fade: # is Fade:
  546. self._base_value = self._fade.next(clock)
  547. self._base_value = self._fade.next(clock) #flicker bug ?!
  548. value = self._base_value
  549. if self._flash_fx is not None:# is FX:
  550. fx_value = self._flash_fx.next(clock)
  551. fx_abs = self._flash_fx.abs
  552. else:
  553. self._fx_value = 0
  554. if self._fx[-1] is not None and self._flash is None:# is FX:
  555. self._fx_value += self._fx[-1].next(clock)
  556. fx_abs = self._fx[-1].abs
  557. fx_value = self._fx_value
  558. if fx_abs == 1:
  559. self._last_val = fx_value
  560. else:
  561. self._last_val = value + fx_value
  562. if self._v_master_id in V_MASTER:
  563. vm = V_MASTER[self._v_master_id].next(clock)
  564. vm = vm/256
  565. self._last_val *= vm
  566. out = self._last_val
  567. return out
  568. V_MASTER = {} #DMXCH
  569. Bdmx = []
  570. for i in range(512*7+1):
  571. Bdmx.append( DMXCH(i) )
  572. #print(type(dmx[i]))
  573. _id = 1
  574. def split_cmd(data):
  575. if "cmd" in data:
  576. cmd = data["cmd"]
  577. #print("cmd",cmd)
  578. if "," in cmd:
  579. cmds = cmd.split(",")
  580. else:
  581. cmds = [cmd]
  582. return cmds
  583. class VDMX():
  584. """functional implementation as class for namespace encapsulation
  585. """
  586. def __init__(self):
  587. self.data = OrderedDict()
  588. self.data[4] = {"DMX":[21,22,23],"VALUE":255, "LIMIT":255} #,"DMXCH":DMXCH("V4")}
  589. for k,v in self.data.items():
  590. pass
  591. #dmxch = v["DMXCH"]
  592. #dmxch.fade(10,0)
  593. #dmxch.fx(size=200,speed=200,base="-") #self,xtype="sinus",size=40,speed=40,invert=0,width=100,start=0,offset=0,base="", clock=0,master=None):
  594. def _list_by_dmx(self,_dmx=0):
  595. data = OrderedDict()
  596. for i,link in self.data.items(): # enumerate(self.data):
  597. if _dmx in link["DMX"]:
  598. #print( "_list_by_dmx",i,link)
  599. data[i] = link
  600. return data
  601. def dmx_by_id(self,_id=0):
  602. #print("dmx by master-id:",_id)
  603. if _id in self.data:
  604. for i,link in self.data[_id].items():
  605. #print("dmx_by_id", i,link)
  606. return (i,link)
  607. return 0,{}
  608. def by_dmx(self,clock,dmx):
  609. #print("master of dmx:",dmx)
  610. val=0
  611. flag = 0
  612. data = self._list_by_dmx(dmx)
  613. for i,row in data.items():
  614. if "DMXCH" not in row:
  615. row["DMXCH"] = DMXCH("V{}".format(i))
  616. row["DMXCH"].fade(255,0)
  617. v = row["DMXCH"].next(clock)
  618. #row["DMXCH"].fade(200,20)
  619. if v >= val:
  620. val = v
  621. flag = 1
  622. out = 1.
  623. if val > 255:
  624. val = 255
  625. if flag:
  626. out = val/255.
  627. else:
  628. out = 1.
  629. return out
  630. vdmx = VDMX()
  631. class HTP_MASTER():
  632. """functional implementation as class for namespace encapsulation
  633. """
  634. def __init__(self):
  635. self.data = OrderedDict()
  636. #self.data[1] = {"DMX":[1,2,3],"VALUE":80, "LIMIT":255}
  637. #self.data[2] = {"DMX":[12,13,22],"VALUE":70, "LIMIT":255}
  638. #self.data[3] = {"DMX":[22,23,24],"VALUE":99, "LIMIT":255}
  639. self.data[4] = {"DMX":[22,23,24],"VALUE":99, "LIMIT":255,"DMXCH":DMXCH(4)}
  640. def _list_by_dmx(self,_dmx=0):
  641. data = OrderedDict()
  642. for i,link in self.data.items(): # enumerate(self.data):
  643. if _dmx in link["DMX"]:
  644. #print( "_list_by_dmx",i,link)
  645. data[i] = link
  646. return data
  647. def dmx_by_id(self,_id=0):
  648. #print("dmx by master-id:",_id)
  649. if _id in self.data:
  650. for i,link in self.data[_id].items():
  651. #print("dmx_by_id", i,link)
  652. return (i,link)
  653. return 0,{}
  654. def val_by_dmx(self,dmx=0):
  655. #print("master of dmx:",dmx)
  656. val=0
  657. flag = 0
  658. data = self._list_by_dmx(dmx)
  659. for i,link in data.items():
  660. #print("master_by_dmx", i,link)
  661. if link["VALUE"] > val:
  662. #print("master_by_dmx", i,link)
  663. val = link["VALUE"]
  664. flag=1
  665. out = 1.
  666. if flag:
  667. out = val/255.
  668. return out
  669. htp_master = HTP_MASTER()
  670. #htp_master.data[_id] = {"DMX":[1,2,3],"VALUE":80, "LIMIT":255,"DMXCH":DMXCH()}
  671. class Main():
  672. def __init__(self):
  673. self.artnet = {}
  674. self.fx = {} # key is dmx address
  675. self.lock = thread.allocate_lock()
  676. def loop(self):
  677. xx = [0]*512
  678. ii = 0
  679. old_univ = -1
  680. xx = [0]*512
  681. for ii,dmxch in enumerate(Bdmx):
  682. i = ii%512
  683. univ = ii//512
  684. if str(univ) not in self.artnet:
  685. print("add uiv",univ)
  686. self.artnet[str(univ)] = ANN.ArtNetNode(to="10.10.10.255",univ=univ)
  687. if univ != old_univ:
  688. old_univ = univ
  689. try:
  690. artnet.next()
  691. except:pass
  692. artnet = self.artnet[str(univ)]
  693. artnet.dmx = [0]*512
  694. fps_start = time.time()
  695. fps = 0
  696. dbg= 0#1
  697. while 1:
  698. self.lock.acquire_lock()
  699. start = time.time()
  700. _t=0
  701. t = clock.time()
  702. ii = 0
  703. old_univ = -1
  704. xx = [0]*512
  705. for ii,dmxch in enumerate(Bdmx):
  706. i = ii%512
  707. univ = ii//512
  708. s_univ = str(univ)
  709. if s_univ not in self.artnet:
  710. print("add uiv",univ)
  711. self.artnet[s_univ] = ANN.ArtNetNode(to="10.10.10.255",univ=univ)
  712. if dbg:
  713. end = time.time()
  714. print(" t",_t,ii,round(end-start,4))
  715. start = time.time()
  716. _t+=1
  717. old_univ = -1
  718. xx = [0]*512
  719. for ii,dmxch in enumerate(Bdmx):
  720. i = ii%512
  721. univ = ii//512
  722. if univ != old_univ:
  723. old_univ = univ
  724. artnet = self.artnet[str(univ)]
  725. xx = artnet.dmx
  726. v = dmxch.next(t)
  727. xx[i] = int(v)
  728. if dbg:
  729. end = time.time()
  730. print(" t",_t,ii,round(end-start,4))
  731. start = time.time()
  732. _t+=1
  733. old_univ = -1
  734. xx = [0]*512
  735. for ii,dmxch in enumerate(Bdmx): #fine loop
  736. dmx_fine = dmxch._dmx_fine
  737. if dmx_fine > 0:
  738. i = ii%512
  739. univ = ii//512
  740. if univ != old_univ:
  741. artnet = self.artnet[str(univ)]
  742. xx = artnet.dmx# = xx
  743. v = dmxch.next(t)
  744. vv = vdmx.by_dmx(clock=i,dmx=ii+1)
  745. try:
  746. v = v*vv # disable v-master
  747. except Exception as e:
  748. cprint("Exception v*vv",[v,vv],e)
  749. continue
  750. vf = int(v%1*255)
  751. dmx_fine = dmx_fine%512
  752. try:
  753. if v >= 255:
  754. xx[dmx_fine-1] = 255
  755. elif v < 0:
  756. xx[dmx_fine-1] = 0
  757. else:
  758. xx[dmx_fine-1] = int(v%1*255)
  759. except Exception as e:
  760. print("E dmx_fine",e,dmx_fine)
  761. if dbg:
  762. end = time.time()
  763. print(" t",_t,ii,round(end-start,4))
  764. print()
  765. start = time.time()
  766. _t+=1
  767. self.lock.release_lock()
  768. for k,artnet in self.artnet.items():
  769. artnet.next()
  770. fps += 1
  771. stop_fps = 50
  772. time.sleep(1/30)
  773. if fps >= stop_fps:
  774. fps_t = time.time()
  775. print(round(stop_fps/(fps_t-fps_start),2),"core/fps")
  776. fps = 0
  777. fps_start = time.time()
  778. main = Main()
  779. if __run_main:
  780. thread.start_new_thread(main.loop,())
  781. def _init_action(row):#Bdmx,out,DMX):
  782. Admx = row["DMXCH"]
  783. line_sub_count = 0
  784. if row["fx"]:
  785. x = row["fx"]
  786. Admx.fx(xtype=x["xtype"]
  787. ,size=x["size"]
  788. ,speed=x["speed"]
  789. ,invert=x["invert"]
  790. ,width=x["width"]
  791. ,start=x["start"]
  792. ,offset=x["offset"]
  793. ,base=x["base"]
  794. ,clock=x["clock"]
  795. ,master=x["master"])
  796. line_sub_count += 1
  797. if row["flash_fx"]:
  798. x = row["flash_fx"]
  799. Admx.flash_fx(xtype=x["xtype"]
  800. ,size=x["size"]
  801. ,speed=x["speed"]
  802. ,invert=x["invert"]
  803. ,width=x["width"]
  804. ,start=x["start"]
  805. ,offset=x["offset"]
  806. ,base=x["base"]
  807. ,clock=x["clock"]
  808. ,master=x["master"])
  809. line_sub_count += 1
  810. if row["flash"]:
  811. x = row["flash"]
  812. Admx.flash(target=x["target"]
  813. ,ftime=x["ftime"]
  814. ,clock=x["clock"]
  815. ,delay=x["delay"])
  816. line_sub_count += 1
  817. if row["fade"]:
  818. x = row["fade"]
  819. Admx.fade(target=x["target"]
  820. ,ftime=x["ftime"]
  821. ,clock=x["clock"]
  822. ,delay=x["delay"])
  823. line_sub_count += 1
  824. return line_sub_count
  825. def set_dmx_fine_ch(Admx,dmx_fine_nr):
  826. try:
  827. if int(dmx_fine_nr) > 0:
  828. Admx._dmx_fine = int(dmx_fine_nr)
  829. except Exception as e:
  830. cprint(x,color="red")
  831. cprint("except 3455",e,color="red")
  832. def _parse_cmds(cmds,clock=0,master_fx=None):
  833. c=clock
  834. out = {}
  835. for x in cmds:
  836. Admx = DMXCH() #dummy
  837. _fix_id=0
  838. _attr = ""
  839. if "CMD" in x:
  840. print("CMD:",x)
  841. if "EXEC-SPEED-MASTER" == x["CMD"]:
  842. exec_speed_master.val(x["NR"],x["VALUE"])
  843. if "EXEC-SIZE-MASTER" == x["CMD"]:
  844. exec_size_master.val(x["NR"],x["VALUE"])
  845. if "EXEC-OFFSET-MASTER" == x["CMD"]:
  846. exec_offset_master.val(x["NR"],x["VALUE"])
  847. if "SPEED-MASTER" == x["CMD"]:
  848. speed_master.val(x["NR"],x["VALUE"])
  849. if "SIZE-MASTER" == x["CMD"]:
  850. size_master.val(x["NR"],x["VALUE"])
  851. else:
  852. #print("x",x)
  853. if "DMX" in x:
  854. DMX = int(x["DMX"])
  855. else:
  856. continue
  857. if "VALUE" in x:
  858. v = x["VALUE"]
  859. else:
  860. continue
  861. _inc = 0
  862. _fix_id = 0
  863. _val = -1
  864. _clock = 0
  865. exec_id = None
  866. if "VALUE" in x:
  867. _val = x["VALUE"]
  868. if "INC" in x:
  869. _inc = x["INC"]
  870. if "FIX" in x:
  871. _fix_id = x["FIX"]
  872. if "clock" in x:
  873. _clock=x["clock"]
  874. if "ATTR" in x:
  875. _attr = x["ATTR"]
  876. if DMX <= 0: # VIRTUAL
  877. DMX = "FIX"+str(_fix_id)
  878. ok = 0
  879. if "ATTR" in x:
  880. _attr = x["ATTR"]
  881. if "DIM" == x["ATTR"]:
  882. if _fix_id not in V_MASTER:
  883. V_MASTER[_fix_id] = DMXCH()
  884. #print("_val",_val)
  885. #V_MASTER[_fix_id].fade(_val,ftime=0,clock=0,delay=0)
  886. #print(" V-MASTER",_fix_id,_val,_inc)
  887. ok = 1
  888. if _fix_id in V_MASTER:
  889. Admx = V_MASTER[_fix_id]
  890. if not ok:
  891. continue
  892. else:
  893. if DMX < len(Bdmx):
  894. Admx = Bdmx[DMX-1]
  895. else:
  896. print("DMX ADDRESS too BIG",DMX)
  897. continue
  898. if "DMX-FINE" in x and DMX > 0:
  899. set_dmx_fine_ch(Admx, x["DMX-FINE"])
  900. #print("-")
  901. if "EXEC" in x:
  902. exec_id = x["EXEC"]
  903. if "ATTR" in x:
  904. _attr = x["ATTR"]
  905. if "FIX" in x:
  906. _fix_id = x["FIX"]
  907. fx=""
  908. fx2={}
  909. ftime=0
  910. delay=0
  911. if "FX" in x:
  912. fx = x["FX"]
  913. if "FX2" in x:
  914. fx2 = x["FX2"]
  915. if "FADE" in x:
  916. ftime = x["FADE"]
  917. if "DELAY" in x:
  918. delay = x["DELAY"]
  919. #print("DO",[exec_id],x)
  920. # ids = [401,402,304,103]
  921. # exec-id, exec-fx-id, flush-id, flush-fx-id
  922. if v != "off":
  923. if "FLASH" in x:
  924. ids = Admx.exec_ids()
  925. if type(v) is int:
  926. ids[2] = exec_id
  927. if fx2:
  928. ids[3] = exec_id
  929. #print(" ",[ids, exec_id],"FL")
  930. else: # GO or ON
  931. ids = Admx.exec_ids()
  932. if type(v) is int:
  933. ids[0] = exec_id
  934. if fx2:
  935. ids[1] = exec_id
  936. #print(" ",[ids, exec_id],"GO")
  937. if v == "off":
  938. if "FLASH" in x:
  939. ids = Admx.exec_ids()
  940. stop = 0
  941. #print(" ",[ids, exec_id])
  942. if ids[2] != exec_id:
  943. stop = 1
  944. else:
  945. ids[2] = None
  946. if fx2:
  947. if ids[3] != exec_id:
  948. stop = 1
  949. else:
  950. ids[3] = None
  951. stop = 0
  952. if stop:
  953. # this FLASH cmd OFF/RELEASE is not valid anymore
  954. continue
  955. #aprint("OK")
  956. #ids = Admx.exec_ids()
  957. #print("OK ",[ids, exec_id])
  958. #Bdmx[DMX].exec_id(exec_id)
  959. out[DMX] = {"flash":{},"fade":{},"fx":{},"flash_fx":{},"fix_id":_fix_id,"attr":_attr,"DMXCH":Admx}
  960. if v is not None:
  961. if "FLASH" in x:
  962. out[DMX]["flash"] = {"target":v,"ftime":ftime, "clock":c,"delay":delay,"DMXCH":Admx}
  963. else:
  964. out[DMX]["fade"] = {"target":v,"ftime":ftime, "clock":c,"delay":delay,"DMXCH":Admx}
  965. if type(fx2) is dict and fx2:
  966. xtype="fade"
  967. size = 10
  968. speed = 10
  969. start = 0
  970. offset= 0
  971. width=100
  972. invert=0
  973. base = "-"
  974. if "TYPE" in fx2:
  975. xtype = fx2["TYPE"]
  976. if "SIZE" in fx2:
  977. size = fx2["SIZE"]
  978. if "SPEED" in fx2:
  979. speed = fx2["SPEED"]
  980. if "OFFSET" in fx2:
  981. offset = fx2["OFFSET"]
  982. if "BASE" in fx2:
  983. base = fx2["BASE"]
  984. if "INVERT" in fx2:
  985. invert = fx2["INVERT"]
  986. if "WIDTH" in fx2:
  987. width = fx2["WIDTH"]
  988. if "off" == x["VALUE"]: #fix fx flash off
  989. xtype= "off"
  990. if "alloff" == xtype.lower():
  991. for dmxch in Bdmx:
  992. if dmxch is not None:
  993. dmxch.flash_fx(xtype="off",clock=c)
  994. dmxch.fx(xtype="off",clock=c)
  995. for j in V_MASTER:
  996. dmxch = V_MASTER[j]
  997. if j is not None:
  998. dmxch.flash_fx(xtype="off",clock=c)
  999. dmxch.fx(xtype="off",clock=c)
  1000. if "FLASH" in x:
  1001. out[DMX]["flash_fx"] = {"xtype":xtype,"size":size,"speed":speed,
  1002. "invert":invert,"width":width,"start":start
  1003. ,"offset":offset,"base":base,"clock":c,"master":master_fx}
  1004. else:
  1005. out[DMX]["fx"] = {"xtype":xtype,"size":size,"speed":speed
  1006. ,"invert":invert,"width":width,"start":start
  1007. ,"offset":offset,"base":base,"clock":c,"master":master_fx}
  1008. elif type(fx) is str and fx:
  1009. # old fx like sinus:200:12:244
  1010. ccm = str(DMX+1)+":"+fx
  1011. print("fx",ccm)
  1012. if "FLASH" in x:
  1013. pass#CB({"cmd":"fxf"+ccm})
  1014. else:
  1015. pass#CB({"cmd":"fx"+ccm})
  1016. return out
  1017. import hashlib
  1018. JCB_GLOB_BUF = {}
  1019. def JCB(data,sock=None): #json client input
  1020. t_start = time.time()
  1021. s = time.time()
  1022. e = time.time()
  1023. ct = int(e*100)/100
  1024. print()
  1025. msg = "{} JCB START: {:0.02f} sizeof:{}"
  1026. msg = msg.format(ct,e-s,sys.getsizeof(data) )
  1027. print(msg)
  1028. jdatas = []
  1029. l2 = 0
  1030. for line in data:
  1031. data2 = json.loads(line)
  1032. l2 += len(data2)
  1033. #print("line:",line)
  1034. jdatas.append(data2) #["CMD"])
  1035. print("INPUT JCB =>",len(data),":",l2)
  1036. c = clock.time()
  1037. c = float(c)
  1038. ftime = 0
  1039. delay = 0
  1040. out = {}
  1041. line=""
  1042. for cmds in jdatas:
  1043. for line in cmds: # run first
  1044. #print(line)
  1045. if "FLASH" in line:
  1046. cprint("FLUSH",end=" ",color="CYAN")
  1047. if "VALUE" in line:
  1048. if line["VALUE"] == "off":
  1049. cprint("OFF",end=" ",color="red")
  1050. else:
  1051. cprint("ON",end=" ",color="green")
  1052. print("")
  1053. else:
  1054. cprint("FADE",color="CYAN")
  1055. break
  1056. for cmds in jdatas:
  1057. for line in cmds:
  1058. if "time" in line:
  1059. jt_start = line["time"]
  1060. latenz = round(t_start-jt_start,4)
  1061. if latenz > 0.5:
  1062. cprint("latenz 0.5 >",latenz,color="red")
  1063. break
  1064. for cmds in jdatas:
  1065. #line = json.dumps(cmds)
  1066. #md5 = hashlib.md5.hexdigest(line)
  1067. master_fx = MASTER_FX()
  1068. if not cmds:
  1069. continue
  1070. try:
  1071. out = _parse_cmds(cmds,clock=c,master_fx=master_fx)
  1072. #cprint("-","{:0.04} sec.".format(time.time()-t_start),color="yellow")
  1073. # ------- ----------------------------------------------------
  1074. except Exception as e:
  1075. cprint("EXCEPTION JCB",e,color="red")
  1076. cprint("----",str(cmds)[:150],"...",color="red")
  1077. cprint("Error on line {}".format(sys.exc_info()[-1].tb_lineno),color="red")
  1078. raise e
  1079. line_count = 0
  1080. line_count_sub = 0
  1081. line_size = 0
  1082. attr_count = {}
  1083. attr_count2 = 0
  1084. if out:
  1085. try:
  1086. try: # second loop to sync-start all dmxch's
  1087. main.lock.acquire_lock()
  1088. for _id in out:
  1089. row = out[_id]
  1090. #print(row)
  1091. line_size += sys.getsizeof(row)
  1092. #print("_id",_id)
  1093. Admx = row["DMXCH"]
  1094. #print("Admx",Admx)
  1095. if "attr" in row:
  1096. if row["attr"] not in attr_count:
  1097. attr_count[row["attr"]] = 0
  1098. attr_count[row["attr"]] += 1
  1099. attr_count2 +=1
  1100. if row["fix_id"]:
  1101. _fix_id = row["fix_id"]
  1102. Admx._fix_id = _fix_id
  1103. if "attr" in row:
  1104. if row["attr"] in ["RED","GREEN","BLUE","WHITE","AMBER"]: #CYAN,MAGENTA,YELLOW
  1105. Admx._v_master_id = _fix_id
  1106. #print("SET V_MASTER",row)
  1107. line_count_sub += _init_action(row)
  1108. line_count += 1
  1109. e = time.time()
  1110. print(" sub-JCB TIME:","{:0.02f}".format(e-s),int(e*100)/100)
  1111. finally:
  1112. main.lock.release_lock()
  1113. #time.sleep(1/30)
  1114. except Exception as e:
  1115. cprint("EXCEPTION JCB",e,color="red")
  1116. cprint("----",str(cmds)[:150],"...",color="red")
  1117. cprint("Error on line {}".format(sys.exc_info()[-1].tb_lineno),color="red")
  1118. raise e
  1119. #cprint(" ","{:0.04} sec.".format(time.time()-t_start),color="yellow")
  1120. print("attr_count:",attr_count)
  1121. #print(line_count,line_size)
  1122. e = time.time()
  1123. ct = int(e*100)/100
  1124. msg = "{} JCB: END {:0.02f} sizeof:{} fix-count:{} attr-count:{}"
  1125. msg = msg.format(ct,e-s,line_size,line_count,line_count_sub )
  1126. print(msg)
  1127. time.sleep(1/60)
  1128. if __run_main:
  1129. s = chat.Server(cb=JCB)
  1130. while 1:
  1131. s.poll()
  1132. time.sleep(0.001)