console.py 17 KB

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