console.py 20 KB

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