console.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  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@uxsrv.de
  15. """
  16. import sys
  17. if "__file__" in dir():
  18. sys.stdout.write("\x1b]2;"+str(__file__)+"\x07") # terminal title
  19. else:
  20. sys.stdout.write("\x1b]2;"+str("__file__")+"\x07") # terminal title
  21. import time
  22. import socket
  23. import struct
  24. import sys
  25. import random
  26. import math
  27. from collections import OrderedDict
  28. import lib.chat as chat
  29. import lib.ArtNetNode as ANN
  30. import _thread as thread
  31. #thread.start_new_thread
  32. import lib.motion as motion
  33. #idmx = [0]*512 # incremental dmx
  34. dmx = [0]*512 # absolute dmx data
  35. def artnet_loop():
  36. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=12)
  37. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=0)
  38. artnet = ANN.ArtNetNode(to="10.10.10.255",univ=0)
  39. #artnet = ANN.ArtNetNode(to="2.0.0.255",univ=0)
  40. #artnet = ANN.ArtNetNode(to="10.10.10.255",univ=1)
  41. #dmx[205] = 255 #205 BLUE
  42. artnet.dmx= dmx #[0]*512
  43. artnet.send()
  44. while 1:
  45. #artnet._test_frame()
  46. artnet.next()
  47. time.sleep(0.01)
  48. class Main():
  49. def __init__(self):
  50. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=12)
  51. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=0)
  52. #artnet = ANN.ArtNetNode(to="2.0.0.255",univ=0)
  53. #artnet = ANN.ArtNetNode(to="10.10.10.255",univ=1)
  54. self.artnet = {}
  55. #self.artnet["0"] = ANN.ArtNetNode(to="10.10.10.255",univ=0)
  56. #self.artnet["0"].dmx[512-1] = 10
  57. #self.artnet["1"] = ANN.ArtNetNode(to="10.10.10.255",univ=1)
  58. #self.artnet["1"].dmx[512-1] = 11
  59. self.fx = {} # key is dmx address
  60. def loop(self):
  61. #dmx[205] = 255 #205 BLUE
  62. #self.artnet.send()
  63. xx = [0]*512
  64. #artnet = self.artnet["0"]
  65. #artnet.dmx = xx# [:] #dmx #[0]*512
  66. old_univ = -1
  67. while 1:
  68. t = clock.time()
  69. ii = 0
  70. for ii,dmxch in enumerate(Bdmx):
  71. i = ii%512
  72. univ = ii//512
  73. if str(univ) not in self.artnet:
  74. print("add uiv",univ)
  75. self.artnet[str(univ)] = ANN.ArtNetNode(to="10.10.10.255",univ=univ)
  76. self.artnet[str(univ)].dmx[512-1] = 100+univ
  77. if univ != old_univ:
  78. old_univ = univ
  79. #print("UNIV",ii/512)
  80. try:
  81. artnet.next()
  82. except:pass
  83. artnet = self.artnet[str(univ)]
  84. artnet.dmx = xx
  85. v = dmxch.next(t)
  86. if i == 0:
  87. if int(xx[i]*100) != int( v*100):
  88. #print("----v",x[i],v,t)
  89. pass
  90. #print("i:{:0.2f} xx:{:0.2f} v:{:0.2f} {:0.2f}----v {}".format(i,xx[i],v,t+100,dmxch))
  91. #print("i:{:0.2f} xx:{:0.2f} v:{:0.2f} {:0.2f}----v {}".format(i,xx[i],v,t+100,dmxch))
  92. xx[i] = int(v)
  93. try:
  94. artnet.next()
  95. except:pass
  96. time.sleep(0.01)
  97. main = Main()
  98. #thread.start_new_thread(artnet_loop,())
  99. thread.start_new_thread(main.loop,())
  100. class CLOCK():
  101. def __init__(self):
  102. self.__time = 0
  103. self.__start = time.time() # only for debugging
  104. self.__tick = 0.01 # incremental timer drift's on highe cpu load ?
  105. def time(self):
  106. return self.__time
  107. def get_drift(self):
  108. run_time = time.time() - self.__start
  109. tick_time = self.__time # * self.__tick
  110. print( "runtime:{:0.2f} tick_timer:{:0.2f} drift:{:0.2f}".format(run_time,tick_time,run_time-tick_time))
  111. def loop(self):
  112. while 1:
  113. self.__time +=self.__tick
  114. #if int(self.__time*100)/10. % 10 == 0:# self.__time % 2 == 0:
  115. # print( self.get_drift())
  116. #print(self.__time)
  117. #for i in range(10):
  118. time.sleep(self.__tick)
  119. clock = CLOCK()
  120. thread.start_new_thread(clock.loop,())
  121. class Fade():
  122. def __init__(self,start,target,time,clock,delay=0):
  123. #print("init Fade ",start,target,time,clock)
  124. if delay < 0:
  125. delay = 0.0001
  126. if time <= 0:
  127. time = 0.0001
  128. clock += delay
  129. self.__delay = delay
  130. self.__clock = clock
  131. self.__clock_curr = clock
  132. self.__time = time
  133. self.__start = start
  134. self.__last = start
  135. self.__target = target
  136. self.run = 1
  137. #print("INIT", str(self) )
  138. def __str__(self):
  139. return self.__repr__()
  140. def __repr__(self):
  141. return "<Fade Next:{:0.2f} Start:{:0.2f} Target:{:0.2f} T{:0.2f} Clock:{:0.2f} run:{} delay:{:0.2f}>".format(
  142. self.__last, self.__start,self.__target,self.__time,self.__clock_curr,self.run,self.__delay )
  143. def next(self,clock=None):
  144. if self.__time <= 0 and self.__delay <= 0:
  145. self.__last = self.__target
  146. self.run = 0
  147. if type(clock) is float or type(clock) is int:#not None:
  148. self.__clock_curr = clock
  149. if self.__target > self.__start:
  150. if self.__last >= self.__target:
  151. self.run = 0
  152. return self.__target
  153. else:
  154. if self.__last <= self.__target:
  155. self.run = 0
  156. return self.__target
  157. current = (self.__clock - self.__clock_curr) / self.__time
  158. length = self.__start - self.__target
  159. self.__last = self.__start+ length*current
  160. #if self.__last < 0:
  161. # self.__last = 0
  162. #if self.__last > 255:
  163. # self.__last = 255
  164. self.run = 1
  165. return self.__last
  166. def ctl(self,cmd="",value=None): # if x-fade cmd="%" value=50
  167. # start,stop,fwd,bwd,revers
  168. pass
  169. class FX():
  170. def __init__(self,xtype="sinus",size=10,speed=10,start=0,offset=0,base="",clock=0):
  171. self.__xtype=xtype
  172. self.__size = size
  173. self.__start = start
  174. self.__base = base
  175. self.__speed = speed
  176. self.__offset = offset
  177. self.__clock = clock
  178. self.__clock_curr = clock
  179. self.run = 1
  180. self.__angel = self.__clock_curr*360%360
  181. def __str__(self):
  182. return self.__repr__()
  183. def __repr__(self):
  184. return "<FX Next:{:0.2f} xtype:{} Size:{:0.2f} Speed:{:0.2f} ang:{:0.2f} base:{} Clock:{:0.2f} run:{}>".format(
  185. self.next(),self.__xtype, self.__size,self.__speed,self.__angel, self.__base,self.__clock_curr,self.run )
  186. def next(self,clock=None):
  187. if type(clock) is float or type(clock) is int:#not None:
  188. self.__clock_curr = clock
  189. t = self.__clock_curr * self.__speed / 255
  190. t += self.__offset / 1024 #255
  191. t += self.__start / 1024 #255
  192. self.__angel = t%1*360 #self.__clock_curr%1 #*360%360
  193. t = t%1
  194. rad = math.radians(self.__angel)
  195. base = 0
  196. if self.__base == "+": # add
  197. base = self.__size
  198. elif self.__base == "-": # sub
  199. base = self.__size*-1
  200. # todo start angle 20°
  201. # todo width angle 90°
  202. #print("{:0.2f} {:0.2f} {:0.2f} {:0.2f}".format(self.__angel ,self.__clock_curr,self.__angel ,math.sin(rad) ) )
  203. if self.__xtype == "sinus":
  204. return math.sin( rad ) * self.__size/2 + base/2
  205. elif self.__xtype == "cosinus":
  206. return math.cos( rad ) * self.__size/2 + base/2
  207. elif self.__xtype == "on2":
  208. out = self.__size/2
  209. if self.__angel > 90 and self.__angel <=270:
  210. out *=-1
  211. out += base/2
  212. print("ON {:0.2f} {:0.2f} {:0.2f} {:0.2f}".format(out,t,0,self.__angel, base))
  213. return out
  214. elif self.__xtype == "on":
  215. out = self.__size/2
  216. if self.__angel > 90 and self.__angel <=270:
  217. pass
  218. else:
  219. out *=-1
  220. out += base/2
  221. return out
  222. elif self.__xtype == "bump":
  223. out = 0
  224. if self.__base == "-": # sub
  225. out = (t%1-1) * self.__size
  226. elif self.__base == "+": # sub
  227. out = (t%1) * self.__size
  228. else:
  229. out = (t%1-0.5) * self.__size
  230. #print("bump",out)
  231. return out
  232. elif self.__xtype == "bump2":
  233. out = 0
  234. if self.__base == "+": # sub
  235. out = (t%1-1) * (self.__size *-1)
  236. elif self.__base == "-": # sub
  237. out = (t%1) * (self.__size *-1)
  238. else:
  239. out = (t%1-0.5) * (self.__size *-1)
  240. #print("bump",out)
  241. return out
  242. elif self.__xtype == "fade":
  243. x = t * 2
  244. if x > 1:
  245. x = 2-x
  246. x -= 0.5
  247. out = x * self.__size + base/2
  248. #print("FADE {:0.2f} {:0.2f} {:0.2f} {:0.2f}".format(out,t,x,self.__angel, base))
  249. return out
  250. else:
  251. return 0
  252. class DMXCH(object):
  253. def __init__(self):
  254. self._base_value = 0
  255. self._fade = None
  256. self._fx = None
  257. self._fx_value = 0
  258. self._flush = None
  259. self._flush_fx = None
  260. self._flush_fx_value = 0
  261. self._last_val = None
  262. def fade(self,target,time=0,clock=0,delay=0):
  263. if target != self._base_value:
  264. try:
  265. target = float(target)
  266. self._fade = Fade(self._base_value,target,time=time,clock=clock,delay=delay)
  267. #self._fade.next()
  268. #self._fade.next()
  269. except Exception as e:
  270. print( "Except:fade",e,target,time,clock)
  271. def fx(self,xtype="sinus",size=40,speed=40,start=0,offset=0,base="", clock=0):
  272. if str(xtype).lower() == "off":
  273. #self._fx = Fade(self._fx_value,target=0,time=2,clock=clock)
  274. self._fx = None
  275. self._fx_value = 0
  276. else:
  277. self._fx = FX(xtype=xtype,size=size,speed=speed,start=start,offset=offset,base=base,clock=clock)
  278. def flush(self,target,time=0,clock=0,delay=0):
  279. if str(target).lower() == "off":
  280. self._flush = None
  281. else:#elif target != self._base_value:
  282. try:
  283. target = float(target)
  284. self._flush = Fade(self._last_val,target,time=time,clock=clock,delay=delay)
  285. except Exception as e:
  286. print( "Except:flush",target,time,clock,__name__,e,)
  287. def flush_fx(self,xtype="sinus",size=40,speed=40,start=0,offset=0,base="",clock=0):
  288. if str(xtype).lower() == "off":
  289. #self._fx = Fade(self._fx_value,target=0,time=2,clock=clock)
  290. self._flush_fx = None
  291. self._flush_fx_value = 0
  292. else:
  293. self._flush_fx = FX(xtype=xtype,size=size,speed=speed,start=start,offset=offset,base=base,clock=clock)
  294. def fx_ctl(self,cmd=""):#start,stop,off
  295. pass
  296. def __str__(self):
  297. return self.__repr__()
  298. def __repr__(self):
  299. return "< DMXCH {:0.2f} > \n{}\n {}".format( self._last_val,self._fx,self._fade)
  300. def fade_ctl(self,cmd=""):#start,stop,backw,fwd,bounce
  301. pass
  302. def next(self,clock=0):
  303. value = self._base_value
  304. if self._last_val is None:
  305. self._last_val = value
  306. fx_value = self._fx_value
  307. if self._flush is not None:
  308. value = self._flush.next(clock)
  309. #flicker bug ?!
  310. value = self._flush.next(clock)
  311. fx_value = 0
  312. elif self._fade is not None:#is Fade:# is Fade:
  313. self._base_value = self._fade.next(clock)
  314. #flicker bug ?!
  315. self._base_value = self._fade.next(clock)
  316. value = self._base_value
  317. if self._flush_fx is not None:# is FX:
  318. fx_value = self._flush_fx.next(clock)
  319. elif self._fx is not None and self._flush is None:# is FX:
  320. self._fx_value = self._fx.next(clock)
  321. fx_value = self._fx_value
  322. self._last_val = value+fx_value
  323. return self._last_val
  324. Bdmx = []
  325. for i in range(512*6):
  326. Bdmx.append( DMXCH() )
  327. #print(type(dmx[i]))
  328. def split_cmd(data):
  329. if "cmd" in data:
  330. cmd = data["cmd"]
  331. #print("cmd",cmd)
  332. if "," in cmd:
  333. cmds = cmd.split(",")
  334. else:
  335. cmds = [cmd]
  336. return cmds
  337. def CB(data):
  338. #print("CB",data)
  339. cmds = split_cmd(data)
  340. c = clock.time()
  341. c = float(c)
  342. time = 0
  343. delay = 0
  344. for xcmd in cmds:
  345. if xcmd:
  346. print("CB",xcmd)
  347. else:
  348. continue
  349. if xcmd.startswith("df"):
  350. xxcmd=xcmd[2:].split(":")
  351. #print("DMX:",xxcmd)
  352. if len(xxcmd) < 2:
  353. print("cmd err df",xcmd)
  354. continue
  355. if "alloff" == xxcmd[1].lower():
  356. for i in Bdmx:
  357. if i is not None:
  358. i.flush(target="off",clock=c)
  359. continue
  360. l = xxcmd
  361. try:
  362. k=int(l[0])-1
  363. v=l[1]
  364. if len(l) >= 3:
  365. time=float(l[2])
  366. #if v > 255:
  367. # v = 255
  368. if len(l) >= 3:
  369. try:time=float(l[2])
  370. except:print("ERR","time",xcmd)
  371. if len(l) >= 4:
  372. try:delay=float(l[3])
  373. except:print("ERR","delay",xcmd)
  374. if len(Bdmx) > k:
  375. Bdmx[k].flush(target=v,time=time, clock=c,delay=delay)
  376. except Exception as e:
  377. print("EXCEPTION IN FADE",e)
  378. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  379. elif xcmd.startswith("d"):
  380. xxcmd=xcmd[1:].split(":")
  381. #print("DMX:",xxcmd)
  382. l = xxcmd
  383. try:
  384. k=int(l[0])-1
  385. v=l[1]
  386. if len(l) >= 3:
  387. time=float(l[2])
  388. #if v > 255:
  389. # v = 255
  390. if len(l) >= 3:
  391. try:time=float(l[2])
  392. except:pass
  393. if len(l) >= 4:
  394. try:delay=float(l[3])
  395. except:pass
  396. if len(Bdmx) > k:
  397. Bdmx[k].fade(target=v,time=time, clock=c,delay=delay)
  398. except Exception as e:
  399. print("EXCEPTION IN FADE",e)
  400. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  401. elif xcmd.startswith("fxf"):
  402. xxcmd=xcmd[3:].split(":")
  403. #print("fxf:",xxcmd)
  404. if "alloff" == xxcmd[1].lower():
  405. for i in Bdmx:
  406. if i is not None:
  407. i.flush_fx(xtype="off",clock=c)
  408. l = xxcmd
  409. try:
  410. xtype=""
  411. size=40
  412. speed=100
  413. start=0
  414. offset=0
  415. base=""
  416. k=int(l[0])-1
  417. xtype=l[1]
  418. if len(l) >= 3:
  419. try:size=int(l[2])
  420. except:pass
  421. if len(l) >= 4:
  422. try:speed=int(l[3])
  423. except:pass
  424. if len(l) >= 5:
  425. try:start=int(l[4])
  426. except:pass
  427. if len(l) >= 6:
  428. try:offset=int(l[5])
  429. except:pass
  430. if len(l) >= 7:
  431. try:base=l[6]
  432. except:pass
  433. if len(Bdmx) > k:
  434. #Bdmx[k].fade(target=v,time=t, clock=c)
  435. Bdmx[k].flush_fx(xtype=xtype,size=size,speed=speed,start=start,offset=offset,base=base,clock=c)
  436. except Exception as e:
  437. print("EXCEPTION IN FX",e)
  438. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  439. elif xcmd.startswith("fx"):
  440. xxcmd=xcmd[2:].split(":")
  441. print("DMX:",xxcmd)
  442. if len(xxcmd) < 2:
  443. print("xxcmd err",xxcmd,xcmd)
  444. continue
  445. if "alloff" == xxcmd[1].lower():
  446. for i in Bdmx:
  447. i.fx(xtype="off",clock=c)
  448. l = xxcmd
  449. try:
  450. xtype=""
  451. size=40
  452. speed=100
  453. start=0
  454. offset=0
  455. base=""
  456. k=int(l[0])-1
  457. xtype=l[1]
  458. if len(l) >= 3:
  459. try:size=int(l[2])
  460. except:pass
  461. if len(l) >= 4:
  462. try:speed=int(l[3])
  463. except:pass
  464. if len(l) >= 5:
  465. try:start=int(l[4])
  466. except:pass
  467. if len(l) >= 6:
  468. try:offset=int(l[5])
  469. except:pass
  470. if len(l) >= 7:
  471. try:base=l[6]
  472. except:pass
  473. if len(Bdmx) > k:
  474. #Bdmx[k].fade(target=v,time=t, clock=c)
  475. Bdmx[k].fx(xtype=xtype,size=size,speed=speed,start=start,offset=offset,base=base,clock=c)
  476. except Exception as e:
  477. print("EXCEPTION IN FX",xcmd,e)
  478. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  479. chat.cmd(CB) # server listener
  480. input("END")