console.py 18 KB

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