console.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. #! /usr/bin/python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. This file is part of grandPA.
  5. grandPA 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. grandPA 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 grandPA. If not, see <http://www.gnu.org/licenses/>.
  15. (c) 2012 micha.rathfelder@gmail.com
  16. """
  17. import time
  18. import socket
  19. import struct
  20. import sys
  21. import random
  22. import math
  23. from collections import OrderedDict
  24. import lib.chat as chat
  25. import lib.ArtNetNode as ANN
  26. import _thread as thread
  27. #thread.start_new_thread
  28. import lib.motion as motion
  29. #idmx = [0]*512 # incremental dmx
  30. dmx = [0]*512 # absolute dmx data
  31. def artnet_loop():
  32. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=12)
  33. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=0)
  34. artnet = ANN.ArtNetNode(to="10.10.10.255",univ=0)
  35. #artnet = ANN.ArtNetNode(to="2.0.0.255",univ=0)
  36. #artnet = ANN.ArtNetNode(to="10.10.10.255",univ=1)
  37. dmx[205] = 255 #205 BLUE
  38. artnet.dmx= dmx #[0]*512
  39. artnet.send()
  40. while 1:
  41. #artnet._test_frame()
  42. artnet.next()
  43. time.sleep(0.01)
  44. class Main():
  45. def __init__(self):
  46. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=12)
  47. #artnet = ANN.ArtNetNode(to="127.0.0.1",port=6555,univ=0)
  48. #artnet = ANN.ArtNetNode(to="2.0.0.255",univ=0)
  49. #artnet = ANN.ArtNetNode(to="10.10.10.255",univ=1)
  50. self.artnet = ANN.ArtNetNode(to="10.10.10.255",univ=0)
  51. self.fx = {} # key is dmx address
  52. def loop(self):
  53. #dmx[205] = 255 #205 BLUE
  54. self.artnet.send()
  55. xx = [0]*512
  56. self.artnet.dmx = xx# [:] #dmx #[0]*512
  57. while 1:
  58. t = clock.time()
  59. for i,dmxch in enumerate(Bdmx):
  60. v = dmxch.next(t)
  61. if i == 0:
  62. if int(xx[i]*100) != int( v*100):
  63. #print("----v",x[i],v,t)
  64. pass
  65. #print("i:{:0.2f} xx:{:0.2f} v:{:0.2f} {:0.2f}----v {}".format(i,xx[i],v,t+100,dmxch))
  66. #print("i:{:0.2f} xx:{:0.2f} v:{:0.2f} {:0.2f}----v {}".format(i,xx[i],v,t+100,dmxch))
  67. xx[i] = int(v)
  68. #artnet._test_frame()
  69. self.artnet.next()
  70. #self.artnet.send()
  71. time.sleep(0.01)
  72. main = Main()
  73. #thread.start_new_thread(artnet_loop,())
  74. thread.start_new_thread(main.loop,())
  75. class CLOCK():
  76. def __init__(self):
  77. self.__time = 0
  78. self.__start = time.time() # only for debugging
  79. self.__tick = 0.01 # incremental timer drift's on highe cpu load ?
  80. def time(self):
  81. return self.__time
  82. def get_drift(self):
  83. run_time = time.time() - self.__start
  84. tick_time = self.__time # * self.__tick
  85. print( "runtime:{:0.2f} tick_timer:{:0.2f} drift:{:0.2f}".format(run_time,tick_time,run_time-tick_time))
  86. def loop(self):
  87. while 1:
  88. self.__time +=self.__tick
  89. #if int(self.__time*100)/10. % 10 == 0:# self.__time % 2 == 0:
  90. # print( self.get_drift())
  91. #print(self.__time)
  92. #for i in range(10):
  93. time.sleep(self.__tick)
  94. clock = CLOCK()
  95. thread.start_new_thread(clock.loop,())
  96. class Fade():
  97. def __init__(self,start,target,time,clock,delay=0):
  98. #print("init Fade ",start,target,time,clock)
  99. if delay < 0:
  100. delay = 0
  101. if time <= 0:
  102. time = 0.0001
  103. clock += delay
  104. self.__delay = delay
  105. self.__clock = clock
  106. self.__clock_curr = clock
  107. self.__time = time
  108. self.__start = start
  109. self.__last = start
  110. self.__target = target
  111. self.run = 1
  112. print("INIT", str(self) )
  113. def __str__(self):
  114. return self.__repr__()
  115. def __repr__(self):
  116. return "<Fade Next:{:0.2f} Start:{:0.2f} Target:{:0.2f} T{:0.2f} Clock:{:0.2f} run:{} delay:{:0.2f}>".format(
  117. self.__last, self.__start,self.__target,self.__time,self.__clock_curr,self.run,self.__delay )
  118. def next(self,clock=None):
  119. if self.__time <= 0 and self.__delay <= 0:
  120. self.__last = self.__target
  121. self.run = 0
  122. if type(clock) is float or type(clock) is int:#not None:
  123. self.__clock_curr = clock
  124. if self.__target > self.__start:
  125. if self.__last >= self.__target:
  126. self.run = 0
  127. return self.__target
  128. else:
  129. if self.__last <= self.__target:
  130. self.run = 0
  131. return self.__target
  132. current = (self.__clock - self.__clock_curr) / self.__time
  133. length = self.__start - self.__target
  134. self.__last = self.__start+ length*current
  135. #if self.__last < 0:
  136. # self.__last = 0
  137. #if self.__last > 255:
  138. # self.__last = 255
  139. self.run = 1
  140. return self.__last
  141. def ctl(self,cmd="",value=None): # if x-fade cmd="%" value=50
  142. # start,stop,fwd,bwd,revers
  143. pass
  144. class FX():
  145. def __init__(self,xtype="sinus",size=10,speed=10,offset=0,clock=0):
  146. self.__xtype=xtype
  147. self.__size = size
  148. self.__speed = speed
  149. self.__offset = offset
  150. self.__clock = clock
  151. self.__clock_curr = clock
  152. self.run = 1
  153. def __str__(self):
  154. return self.__repr__()
  155. def __repr__(self):
  156. return "<FX Next:{:0.2f} xtype:{} Size:{:0.2f} Speed:{:0.2f} Clock:{:0.2f} run:{}>".format(
  157. self.next(),self.__xtype, self.__size,self.__speed,self.__clock_curr,self.run )
  158. def next(self,clock=None):
  159. if type(clock) is float or type(clock) is int:#not None:
  160. self.__clock_curr = clock
  161. t = self.__clock_curr * self.__speed / 255
  162. t += self.__offset / 255
  163. if self.__xtype == "sinus":
  164. return math.sin( t ) * self.__size
  165. elif self.__xtype == "cosinus":
  166. return math.cos( t ) * self.__size
  167. else:
  168. return 0
  169. class DMXCH(object):
  170. def __init__(self):
  171. self._base_value = 0
  172. self._fade = None
  173. self._fx = None
  174. self._fx_value = 0
  175. self._flush = None
  176. self._flush_fx = None
  177. self._flush_fx_value = 0
  178. self._last_val = 0
  179. def fade(self,target,time=0,clock=0,delay=0):
  180. if target != self._base_value:
  181. self._fade = Fade(self._base_value,target,time=time,clock=clock,delay=delay)
  182. def fx(self,xtype="sinus",size=40,speed=40,offset=0,clock=0):
  183. if str(xtype).lower() == "off":
  184. #self._fx = Fade(self._fx_value,target=0,time=2,clock=clock)
  185. self._fx = None
  186. self._fx_value = 0
  187. else:
  188. self._fx = FX(xtype=xtype,size=size,speed=speed,offset=offset,clock=clock)
  189. def flush(self,target,time=0,clock=0,delay=0):
  190. if str(target).lower() == "off":
  191. self._flush = None
  192. elif target != self._base_value:
  193. self._flush = Fade(self._last_value,target,time=time,clock=clock,delay=delay)
  194. def flush_fx(self,xtype="sinus",size=40,speed=40,offset=0,clock=0):
  195. if str(xtype).lower() == "off":
  196. #self._fx = Fade(self._fx_value,target=0,time=2,clock=clock)
  197. self._flush_fx = None
  198. self._flush_fx_value = 0
  199. else:
  200. self._flush_fx = FX(xtype=xtype,size=size,speed=speed,offset=offset,clock=clock)
  201. def fx_ctl(self,cmd=""):#start,stop,off
  202. pass
  203. def __str__(self):
  204. return self.__repr__()
  205. def __repr__(self):
  206. return "< DMXCH {:0.2f} > \n{}\n {}".format( self._last_val,self._fx,self._fade)
  207. def fade_ctl(self,cmd=""):#start,stop,backw,fwd,bounce
  208. pass
  209. def next(self,clock=0):
  210. value = self._base_value
  211. fx_value = self._fx_value
  212. if self._flush is not None:
  213. value = self._flush.next(clock)
  214. elif self._fade is not None:#is Fade:# is Fade:
  215. self._base_value = self._fade.next(clock)
  216. value = self._base_value
  217. if self._flush_fx is not None:# is FX:
  218. fx_value = self._flush_fx.next(clock)
  219. elif self._fx is not None:# is FX:
  220. self._fx_value = self._fx.next(clock)
  221. fx_value = self._fx_value
  222. self._last_val = value+fx_value
  223. return self._last_val
  224. Bdmx = []
  225. for i in range(512):
  226. Bdmx.append( DMXCH() )
  227. #print(type(dmx[i]))
  228. def split_cmd(data):
  229. if "cmd" in data:
  230. cmd = data["cmd"]
  231. #print("cmd",cmd)
  232. if "," in cmd:
  233. cmds = cmd.split(",")
  234. else:
  235. cmds = [cmd]
  236. return cmds
  237. def CB(data):
  238. print("CB",data)
  239. cmds = split_cmd(data)
  240. c = clock.time()
  241. time = 2
  242. delay = 0
  243. for xcmd in cmds:
  244. if xcmd.startswith("df"):
  245. xxcmd=xcmd[2:].split(":")
  246. #print("DMX:",xxcmd)
  247. if "alloff" == xxcmd[1].lower():
  248. for i in Bdmx:
  249. i.flush(xtype="off",clock=c)
  250. l = xxcmd
  251. try:
  252. k=int(l[0])-1
  253. v=float(l[1])
  254. if len(l) >= 3:
  255. time=float(l[2])
  256. if v > 255:
  257. v = 255
  258. if len(l) >= 3:
  259. try:time=float(l[2])
  260. except:pass
  261. if len(l) >= 4:
  262. try:delay=float(l[3])
  263. except:pass
  264. if len(Bdmx) > k:
  265. Bdmx[k].flush(target=v,time=time, clock=c,delay=delay)
  266. except Exception as e:
  267. print("EXCEPTION IN FADE",e)
  268. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  269. elif xcmd.startswith("d"):
  270. xxcmd=xcmd[1:].split(":")
  271. #print("DMX:",xxcmd)
  272. l = xxcmd
  273. try:
  274. k=int(l[0])-1
  275. v=float(l[1])
  276. if len(l) >= 3:
  277. time=float(l[2])
  278. if v > 255:
  279. v = 255
  280. if len(l) >= 3:
  281. try:time=float(l[2])
  282. except:pass
  283. if len(l) >= 4:
  284. try:delay=float(l[3])
  285. except:pass
  286. if len(Bdmx) > k:
  287. Bdmx[k].fade(target=v,time=time, clock=c,delay=delay)
  288. except Exception as e:
  289. print("EXCEPTION IN FADE",e)
  290. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  291. elif xcmd.startswith("fxf"):
  292. xxcmd=xcmd[3:].split(":")
  293. print("fxf:",xxcmd)
  294. if "alloff" == xxcmd[1].lower():
  295. for i in Bdmx:
  296. i.flush_fx(xtype="off",clock=c)
  297. l = xxcmd
  298. try:
  299. xtype=""
  300. size=40
  301. speed=100
  302. offset=0
  303. k=int(l[0])-1
  304. xtype=l[1]
  305. if len(l) >= 3:
  306. try:size=int(l[2])
  307. except:pass
  308. if len(l) >= 4:
  309. try:speed=int(l[3])
  310. except:pass
  311. if len(l) >= 5:
  312. try:offset=int(l[4])
  313. except:pass
  314. if len(Bdmx) > k:
  315. #Bdmx[k].fade(target=v,time=t, clock=c)
  316. Bdmx[k].flush_fx(xtype=xtype,size=size,speed=speed,offset=offset,clock=c)
  317. except Exception as e:
  318. print("EXCEPTION IN FX",e)
  319. print("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
  320. elif xcmd.startswith("fx"):
  321. xxcmd=xcmd[2:].split(":")
  322. #print("DMX:",xxcmd)
  323. if "alloff" == xxcmd[1].lower():
  324. for i in Bdmx:
  325. i.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].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. chat.cmd(CB) # server listener
  350. input("END")