console.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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,offset=0,clock=0):
  151. self.__xtype=xtype
  152. self.__size = size
  153. self.__speed = speed
  154. self.__offset = offset
  155. self.__clock = clock
  156. self.__clock_curr = clock
  157. self.run = 1
  158. def __str__(self):
  159. return self.__repr__()
  160. def __repr__(self):
  161. return "<FX Next:{:0.2f} xtype:{} Size:{:0.2f} Speed:{:0.2f} Clock:{:0.2f} run:{}>".format(
  162. self.next(),self.__xtype, self.__size,self.__speed,self.__clock_curr,self.run )
  163. def next(self,clock=None):
  164. if type(clock) is float or type(clock) is int:#not None:
  165. self.__clock_curr = clock
  166. t = self.__clock_curr * self.__speed / 255
  167. t += self.__offset / 255
  168. if self.__xtype == "sinus":
  169. return math.sin( t ) * self.__size
  170. elif self.__xtype == "cosinus":
  171. return math.cos( t ) * self.__size
  172. else:
  173. return 0
  174. class DMXCH(object):
  175. def __init__(self):
  176. self._base_value = 0
  177. self._fade = None
  178. self._fx = None
  179. self._fx_value = 0
  180. self._flush = None
  181. self._flush_fx = None
  182. self._flush_fx_value = 0
  183. self._last_val = None
  184. def fade(self,target,time=0,clock=0,delay=0):
  185. if target != self._base_value:
  186. try:
  187. target = float(target)
  188. self._fade = Fade(self._base_value,target,time=time,clock=clock,delay=delay)
  189. #self._fade.next()
  190. #self._fade.next()
  191. except Exception as e:
  192. print( "Except:fade",e,target,time,clock)
  193. def fx(self,xtype="sinus",size=40,speed=40,offset=0,clock=0):
  194. if str(xtype).lower() == "off":
  195. #self._fx = Fade(self._fx_value,target=0,time=2,clock=clock)
  196. self._fx = None
  197. self._fx_value = 0
  198. else:
  199. self._fx = FX(xtype=xtype,size=size,speed=speed,offset=offset,clock=clock)
  200. def flush(self,target,time=0,clock=0,delay=0):
  201. if str(target).lower() == "off":
  202. self._flush = None
  203. else:#elif target != self._base_value:
  204. try:
  205. target = float(target)
  206. self._flush = Fade(self._last_val,target,time=time,clock=clock,delay=delay)
  207. except Exception as e:
  208. print( "Except:flush",target,time,clock,__name__,e,)
  209. def flush_fx(self,xtype="sinus",size=40,speed=40,offset=0,clock=0):
  210. if str(xtype).lower() == "off":
  211. #self._fx = Fade(self._fx_value,target=0,time=2,clock=clock)
  212. self._flush_fx = None
  213. self._flush_fx_value = 0
  214. else:
  215. self._flush_fx = FX(xtype=xtype,size=size,speed=speed,offset=offset,clock=clock)
  216. def fx_ctl(self,cmd=""):#start,stop,off
  217. pass
  218. def __str__(self):
  219. return self.__repr__()
  220. def __repr__(self):
  221. return "< DMXCH {:0.2f} > \n{}\n {}".format( self._last_val,self._fx,self._fade)
  222. def fade_ctl(self,cmd=""):#start,stop,backw,fwd,bounce
  223. pass
  224. def next(self,clock=0):
  225. value = self._base_value
  226. if self._last_val is None:
  227. self._last_val = value
  228. fx_value = self._fx_value
  229. if self._flush is not None:
  230. value = self._flush.next(clock)
  231. #flicker bug ?!
  232. value = self._flush.next(clock)
  233. fx_value = 0
  234. elif self._fade is not None:#is Fade:# is Fade:
  235. self._base_value = self._fade.next(clock)
  236. #flicker bug ?!
  237. self._base_value = self._fade.next(clock)
  238. value = self._base_value
  239. if self._flush_fx is not None:# is FX:
  240. fx_value = self._flush_fx.next(clock)
  241. elif self._fx is not None and self._flush is None:# is FX:
  242. self._fx_value = self._fx.next(clock)
  243. fx_value = self._fx_value
  244. self._last_val = value+fx_value
  245. return self._last_val
  246. Bdmx = []
  247. for i in range(512):
  248. Bdmx.append( DMXCH() )
  249. #print(type(dmx[i]))
  250. def split_cmd(data):
  251. if "cmd" in data:
  252. cmd = data["cmd"]
  253. #print("cmd",cmd)
  254. if "," in cmd:
  255. cmds = cmd.split(",")
  256. else:
  257. cmds = [cmd]
  258. return cmds
  259. def CB(data):
  260. #print("CB",data)
  261. cmds = split_cmd(data)
  262. c = clock.time()
  263. c = float(c)
  264. time = 0
  265. delay = 0
  266. for xcmd in cmds:
  267. if xcmd.startswith("df"):
  268. xxcmd=xcmd[2:].split(":")
  269. #print("DMX:",xxcmd)
  270. if len(xxcmd) < 2:
  271. print("cmd err df",xcmd)
  272. continue
  273. if "alloff" == xxcmd[1].lower():
  274. for i in Bdmx:
  275. if i is not None:
  276. i.flush(target="off",clock=c)
  277. continue
  278. l = xxcmd
  279. try:
  280. k=int(l[0])-1
  281. v=l[1]
  282. if len(l) >= 3:
  283. time=float(l[2])
  284. #if v > 255:
  285. # v = 255
  286. if len(l) >= 3:
  287. try:time=float(l[2])
  288. except:print("ERR","time",xcmd)
  289. if len(l) >= 4:
  290. try:delay=float(l[3])
  291. except:print("ERR","delay",xcmd)
  292. if len(Bdmx) > k:
  293. Bdmx[k].flush(target=v,time=time, clock=c,delay=delay)
  294. except Exception as e:
  295. print("EXCEPTION IN FADE",e)
  296. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  297. elif xcmd.startswith("d"):
  298. xxcmd=xcmd[1:].split(":")
  299. #print("DMX:",xxcmd)
  300. l = xxcmd
  301. try:
  302. k=int(l[0])-1
  303. v=l[1]
  304. if len(l) >= 3:
  305. time=float(l[2])
  306. #if v > 255:
  307. # v = 255
  308. if len(l) >= 3:
  309. try:time=float(l[2])
  310. except:pass
  311. if len(l) >= 4:
  312. try:delay=float(l[3])
  313. except:pass
  314. if len(Bdmx) > k:
  315. Bdmx[k].fade(target=v,time=time, clock=c,delay=delay)
  316. except Exception as e:
  317. print("EXCEPTION IN FADE",e)
  318. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  319. elif xcmd.startswith("fxf"):
  320. xxcmd=xcmd[3:].split(":")
  321. #print("fxf:",xxcmd)
  322. if "alloff" == xxcmd[1].lower():
  323. for i in Bdmx:
  324. if i is not None:
  325. i.flush_fx(xtype="off",clock=c)
  326. l = xxcmd
  327. try:
  328. xtype=""
  329. size=40
  330. speed=100
  331. offset=0
  332. k=int(l[0])-1
  333. xtype=l[1]
  334. if len(l) >= 3:
  335. try:size=int(l[2])
  336. except:pass
  337. if len(l) >= 4:
  338. try:speed=int(l[3])
  339. except:pass
  340. if len(l) >= 5:
  341. try:offset=int(l[4])
  342. except:pass
  343. if len(Bdmx) > k:
  344. #Bdmx[k].fade(target=v,time=t, clock=c)
  345. Bdmx[k].flush_fx(xtype=xtype,size=size,speed=speed,offset=offset,clock=c)
  346. except Exception as e:
  347. print("EXCEPTION IN FX",e)
  348. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  349. elif xcmd.startswith("fx"):
  350. xxcmd=xcmd[2:].split(":")
  351. #print("DMX:",xxcmd)
  352. if len(xxcmd) < 2:
  353. print("xxcmd err",xxcmd,xcmd)
  354. continue
  355. if "alloff" == xxcmd[1].lower():
  356. for i in Bdmx:
  357. i.fx(xtype="off",clock=c)
  358. l = xxcmd
  359. try:
  360. xtype=""
  361. size=40
  362. speed=100
  363. offset=0
  364. k=int(l[0])-1
  365. xtype=l[1]
  366. if len(l) >= 3:
  367. try:size=int(l[2])
  368. except:pass
  369. if len(l) >= 4:
  370. try:speed=int(l[3])
  371. except:pass
  372. if len(l) >= 5:
  373. try:offset=int(l[4])
  374. except:pass
  375. if len(Bdmx) > k:
  376. #Bdmx[k].fade(target=v,time=t, clock=c)
  377. Bdmx[k].fx(xtype=xtype,size=size,speed=speed,offset=offset,clock=c)
  378. except Exception as e:
  379. print("EXCEPTION IN FX",xcdm,e)
  380. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  381. chat.cmd(CB) # server listener
  382. input("END")