ArtNetProcessor.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. #! /usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #from __future__ import absolute_import, division, print_function
  4. #from builtins import str, open, range, dict
  5. #from builtins import *
  6. """
  7. This file is part of librelight.
  8. librelight is free software: you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation, either version 2 of the License, or
  11. (at your option) any later version.
  12. librelight is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with librelight. If not, see <http://www.gnu.org/licenses/>.
  18. (c) 2012 micha.rathfelder@gmail.com
  19. """
  20. import sys
  21. sys.stdout.write("\x1b]2;DMX-SHEET 5\x07") # terminal title
  22. import string
  23. import time
  24. import os
  25. import json
  26. from optparse import OptionParser
  27. parser = OptionParser()
  28. parser.add_option("-r", "--recive", dest="recive",
  29. help="set recive ip like --recive 10.")
  30. parser.add_option("-s", "--sendto", dest="sendto",
  31. help="set sender ip like --sendto 2.255.255.255")
  32. parser.add_option("-t", "--test", dest="testuniv",
  33. help="set test univers like --test [0-16]")
  34. #parser.add_option("-q", "--quiet",
  35. # action="store_false", dest="verbose", default=True,
  36. # help="don't print status messages to stdout")
  37. (options, args) = parser.parse_args()
  38. print("option",options)
  39. print(options.sendto)
  40. from collections import OrderedDict
  41. # ============================================================
  42. # Text Grafik Curses =========================================
  43. # ============================================================
  44. import curses
  45. class CursesDummy():
  46. def __init__(self):
  47. self.sel_host=Pager()
  48. self.sel_host.wrap=1
  49. self.sel_univ=Pager()
  50. self.sel_univ.wrap=1
  51. self.sel_mode=Pager()
  52. self.sel_mode.wrap=1
  53. pass
  54. def dir(self):
  55. pass
  56. def test(self):
  57. pass
  58. def init(self):
  59. pass
  60. def addstr(self,x,y,txt):
  61. pass
  62. def draw_lines(self,lines):
  63. pass
  64. def inp(self):
  65. return ""
  66. pass
  67. def read(self):
  68. pass
  69. def clear(self):
  70. pass
  71. def exit(self):
  72. pass
  73. class Manager():
  74. def __init__(self):
  75. self.myscreen = curses.initscr()
  76. print( dir(self.myscreen))
  77. print( self.myscreen.getmaxyx() )
  78. self._inp=""
  79. self.cmd = []
  80. if options.sendto:
  81. self.mode="ltp"
  82. else:
  83. self.mode="dmx"
  84. self.sel_host=Pager()
  85. self.sel_host.wrap=1
  86. self.sel_univ=Pager()
  87. self.sel_univ.wrap=1
  88. self.sel_mode=Pager()
  89. self.sel_mode.wrap=1
  90. if options.sendto:
  91. self.sel_mode.data = ["ltp","dmx","mtx","main"] # mtx = matrix
  92. else:
  93. self.sel_mode.data = ["dmx","main"] # mtx = matrix
  94. self.sel_mode.maxindex = len( self.sel_mode.data )-1
  95. self.ttime = time.time()
  96. self.univ2 = 0
  97. self.host =""
  98. self.ohost = HostBuffer() # as default
  99. def dir(self):
  100. return dir(self.myscreen)
  101. def test(self):
  102. self.init()
  103. #self.loop()
  104. self.draw_lines(["a","b","c"])
  105. try:
  106. time.sleep(10)
  107. finally:
  108. self.exit()
  109. def init(self):
  110. curses.savetty()
  111. curses.noecho()
  112. curses.cbreak()
  113. curses.noqiflush() #?
  114. curses.noraw() #?
  115. self.clear()
  116. curses.beep()
  117. frame = 10
  118. i = 0
  119. def addstr(self,x,y,txt):
  120. self.myscreen.addstr(x, y, txt ) #zeile,spalte,text
  121. def draw_lines(self,lines):
  122. self.clear()
  123. try:
  124. x,y= self.myscreen.getmaxyx()
  125. for i,l in enumerate(lines):
  126. #print(i,l)
  127. if i >= x-2:
  128. break
  129. self.myscreen.addstr(i+1, 1, l ) #zeile,spalte,text
  130. if i >= self.myscreen.getmaxyx()[0]-2:
  131. self.myscreen.addstr(i+1, 1, "..." ) #zeile,spalte,text
  132. self.myscreen.refresh()
  133. self.myscreen.resize(x-1,y-1) # to prevent slowdown..
  134. self.myscreen.resize(x,y)
  135. except KeyboardInterrupt as e:
  136. self.exit()
  137. print("KeyboardInterrupt")
  138. raise e
  139. #except Exception as e:
  140. # self.exit()
  141. # raise e
  142. def inp(self):
  143. x= self._inp
  144. self._inp=""
  145. return x
  146. def read(self):
  147. self.myscreen.nodelay(1)
  148. try:
  149. self._inp=self.myscreen.getkey()
  150. if not self._inp:
  151. self._inp = self.myscreen.getch()
  152. self.myscreen.addstr(0, 1, str(self._inp) ) #zeile,spalte,text
  153. self.myscreen.refresh()
  154. return self._inp
  155. except:
  156. pass#self._inp=""
  157. def clear(self):
  158. self.myscreen.clear()
  159. self.myscreen.border(0)
  160. curses.nocbreak();
  161. self.myscreen.keypad(0);
  162. #self.read()
  163. curses.echo()
  164. curses.resetty()
  165. #self.myscreen.addstr(10, 2, x ) #zeile,spalte,text
  166. def exit(self):
  167. self.clear()
  168. curses.endwin()
  169. print("ENDE",self)
  170. def keyread(self):
  171. #continue
  172. # input command buffer
  173. self.read()
  174. inp2=self.inp()
  175. if "q" == inp2:
  176. inp2=""
  177. self.exit()
  178. sys.exit()
  179. elif "?" == inp2:
  180. self.mode = "?"
  181. elif "," == inp2:
  182. self.sel_mode.next()
  183. inp2=""
  184. elif ";" == inp2:
  185. self.sel_mode.prev()
  186. inp2=""
  187. elif "." == inp2:
  188. self.sel_univ.next()
  189. inp2=""
  190. elif ":" == inp2:
  191. self.sel_univ.prev()
  192. inp2=""
  193. elif "-" == inp2:
  194. self.sel_host.next()
  195. inp2=""
  196. elif "_" == inp2:
  197. self.sel_host.prev()
  198. inp2=""
  199. elif "#" == inp2:
  200. if "main" in self.sel_mode.data:
  201. x = self.sel_mode.data.index( "main")
  202. self.sel_mode.index = x
  203. self.sel_mode.check()
  204. inp2=""
  205. if inp2 == "\n":
  206. cmd2 = "".join( self.cmd).split()
  207. self.cmd=[]
  208. if len(cmd2) < 2:
  209. pass
  210. elif "C^" in cmd2:
  211. screen.exit()
  212. sys.exit()
  213. elif "univ" in cmd2 or "u" == cmd2[0]:
  214. x=""
  215. if cmd2[1] in sel_univ.data:
  216. x = sel_univ.data.index( cmd2[1])
  217. sel_univ.index = x
  218. sel_univ.check()
  219. elif "mode" in cmd2 or "m" == cmd2[0]:
  220. if cmd2[1] in self.sel_mode.data:
  221. x = self.sel_mode.data.index( cmd2[1])
  222. self.sel_mode.index = x
  223. self.sel_mode.check()
  224. elif "host" in cmd2 or "h" == cmd2[0]:
  225. try:
  226. x=int(cmd2[1])
  227. self.sel_host.set(x)
  228. except:
  229. pass
  230. else:
  231. self.cmd.append(inp2)
  232. def loop(self):
  233. self.keyread()
  234. #print( "LOOP")
  235. host = self.sel_host.get()
  236. univ2 = self.sel_univ.get()
  237. self.mode = self.sel_mode.get()
  238. if time.time()-0.12 > self.ttime:
  239. lines = [ ]
  240. #print("cmd:",cmd)
  241. lines.append(" CMD:" + "".join(self.cmd) )
  242. if self.mode=="help" or self.mode=="?":
  243. lines.append("HILFE[h]: " )
  244. lines.append("MODE [m]: inp, in2 in1 " )
  245. lines.append("UNIV [u]: 0-16 " )
  246. lines.append(" " )
  247. lines.append("HILFE " )
  248. elif self.mode=="dmx" or self.mode == "DMX":
  249. self.ttime = time.time()
  250. dmx=self.ohost.get(host,univ=univ2)#univ=head_uni)
  251. info=self.ohost.info()
  252. #lines.append("frame "+str(info.keys()) )
  253. if univ2 in info:
  254. if host in info[univ2] :
  255. lines.append("frame "+str(info[univ2][host]["frame"]))
  256. x=""
  257. for i,v in enumerate(dmx):
  258. if v == 0:
  259. v = "+"
  260. x += str(v).rjust(4," ")
  261. if (i+1) % 20 == 0:# and i:
  262. lines.append(x)
  263. x=""
  264. if x:
  265. lines.append(x)
  266. lines.append(" ")
  267. lines.append(str(self.ttime))
  268. #screen.draw_lines(lines)
  269. elif self.mode=="mtx":
  270. self.ttime = time.time()
  271. dmx=self.ohost.get_mtx(host,univ=univ2)#univ=head_uni)
  272. info=self.ohost.info()
  273. #lines.append("frame "+str(info.keys()) )
  274. if univ2 in info:
  275. if host in info[univ2] :
  276. lines.append("frame "+str(info[univ2][host]["frame"]))
  277. x=""
  278. for i,v in enumerate(dmx):
  279. x += str(v).rjust(4," ")
  280. if (i+1) % 20 == 0:# and i:
  281. lines.append(x)
  282. x=""
  283. if x:
  284. lines.append(x)
  285. lines.append(" ")
  286. lines.append(str(self.ttime))
  287. #screen.draw_lines(lines)
  288. elif self.mode=="ltp" or self.mode=="LTP":
  289. self.ttime = time.time()
  290. dmx=self.ohost.get(univ=univ2)#head_uni)
  291. #univ2=""
  292. host=""
  293. info=self.ohost.info()
  294. lines.append("frame "+str(info.keys()) )
  295. x=""
  296. for i,v in enumerate(dmx):
  297. x += str(v).rjust(4," ")
  298. if (i+1) % 20 == 0:
  299. lines.append(x)
  300. x=""
  301. if x:
  302. lines.append(x)
  303. lines.append(" ")
  304. lines.append(str(self.ttime))
  305. #screen.draw_lines(lines)
  306. else:
  307. self.ttime = time.time()
  308. x=self.ohost.get(univ=univ2)
  309. #lines = []
  310. host=""
  311. univ2=""
  312. info=self.ohost.info()
  313. jinfo = ""
  314. for i in info:
  315. xl = json.dumps(i) + "=======X " # live
  316. lines.append( xl )
  317. for j in info[i]:
  318. lines2=[]
  319. lines.append( " " + json.dumps([j,""]) )
  320. for k in info[i][j]:
  321. if k in ["fpsx","uni","flag"]:
  322. lines2.append( " "+str(k).ljust(5," ")+": " + json.dumps( info[i][j][k]) )
  323. else:
  324. lines.append( " "+str(k).ljust(5," ")+": " + json.dumps( info[i][j][k]) )
  325. lines2 = "".join(lines2)
  326. lines.append(lines2)
  327. lines.append( " " + json.dumps([j,""]) )
  328. lines.append(" ")
  329. lines.append(str(self.ttime))
  330. #screen.draw_lines(lines)
  331. tmp = ""
  332. tmp += " mode:"+(str(self.mode).ljust(10," "))
  333. tmp += " univ:"+str(self.sel_univ.index)+":"+(str(self.sel_univ.get()).ljust(8," "))
  334. tmp += " host:"+str(self.sel_host.index)+":"+(str(self.sel_host.get()).ljust(8," "))
  335. tmp += " --recive:"+str(options.recive)
  336. tmp += " --sendto:"+str(options.sendto)
  337. lines.insert(0,tmp)
  338. tmp = ""
  339. tmp += " univ:"+ (str(self.sel_univ.data))#.ljust(20," "))
  340. tmp += " list:"+ (str(self.sel_host.data))#.ljust(20," "))
  341. lines.insert(0,tmp)
  342. self.draw_lines(lines)
  343. class UniversBuffer():
  344. def __init__(self,univers_nr=0):
  345. """buffer and merge a universe from multiple sender/hosts/ip's
  346. """
  347. self.__hosts = []
  348. self.__universes_dmx = {}
  349. self.__universes_fps = {}
  350. self.__universes_frames = {}
  351. self.__universes_flag = {}
  352. self.__universes_x_frames = {}
  353. self.__universes_x_time = {}
  354. self.__universes_count = {}
  355. self.__universes_timer = {}
  356. self.__universes_matrix = ["."]*512
  357. self.__universes_info = {}
  358. self.__univers_nr = univers_nr
  359. self.__frame = 0
  360. def _add(self,host):
  361. if host not in self.__hosts:
  362. self.__hosts.append(host) #re-order hosts list for LTP
  363. #print( "ADDING HOST:",host,"UNIV:",self.__univers_nr)
  364. self.__universes_dmx[host] = [0]*512
  365. self.__universes_frames[host] = 0
  366. self.__universes_x_frames[host] = 0
  367. self.__universes_fps[host] = [""]*20
  368. self.__universes_flag[host] = [0]*20
  369. self.__universes_x_time[host] = time.time()
  370. self.__universes_timer[host] = [0]*512
  371. self.__universes_info[host] = {}
  372. def _next_frame(self,host):
  373. self.__frame += 1
  374. self.__universes_frames[host] += 1
  375. self.__universes_x_frames[host] += 1
  376. if self.__universes_x_time[host]+10 < time.time():
  377. sec = time.time()-self.__universes_x_time[host]
  378. fps = self.__universes_x_frames[host] /sec
  379. #fps = round(fps,1)
  380. fps = int(fps)
  381. self.__universes_fps[host].pop(0)
  382. self.__universes_fps[host].append(fps)
  383. self.__universes_x_time[host] = time.time()
  384. self.__universes_x_frames[host] = 0
  385. def update(self,host,dmxframe):
  386. if type(dmxframe) != list:
  387. #print( "update ERROR dmxframe is not a list", host )
  388. return
  389. self._add(host)
  390. update_matrix = [0]*512
  391. dmx=[0]*512
  392. update_flag = 0
  393. dmxframe_old = self.__universes_dmx[host]
  394. self._next_frame(host)
  395. if len(dmxframe) <= 512: #len(dmxframe_old):
  396. for i,v in enumerate(dmxframe):
  397. if dmxframe[i] != dmxframe_old[i]:
  398. update_flag += 1
  399. self.__universes_matrix[i] = self.__hosts.index(host)
  400. dmx[i] = v
  401. self.__universes_flag[host].pop(0)
  402. self.__universes_flag[host].append( update_flag )
  403. tmp = {}
  404. tmp["flag"] =update_flag
  405. tmp["flagx"] = self.__universes_flag[host]
  406. tmp["fpsx"] = int(self.__universes_x_frames[host] / (time.time()-self.__universes_x_time[host]))
  407. tmp["frame"] = self.__frame
  408. #tmp["hosts"] = self.__hosts
  409. tmp["uni"] = self.__univers_nr
  410. tmp["fps"] = self.__universes_fps[host]
  411. self.__universes_info[host] = tmp
  412. if update_flag:
  413. #print( "UPDATE HOST:",host, update_flag,"UNIV:",self.__univers_nr)
  414. self.__universes_dmx[host] = dmx # dmxframe
  415. self.__universes_timer[host] = update_matrix
  416. def get(self,host=""):
  417. if host and host in self.__hosts:
  418. return self.__universes_dmx[host]
  419. dmx = [":"]*512
  420. for i,v in enumerate(self.__universes_matrix):
  421. if type(v) is int:
  422. host = self.__hosts[v]
  423. v = self.__universes_dmx[host][i]
  424. dmx[i] = v
  425. return dmx
  426. def get_mtx(self,host=""):
  427. return self.__universes_matrix
  428. def info(self):
  429. return self.__universes_info
  430. def hosts(self):
  431. x = self.__universes_dmx.keys()
  432. x=list(x)
  433. x.sort()
  434. return x
  435. class HostBuffer():
  436. def __init__(self):
  437. """buffer hosts and route data into universes
  438. """
  439. self.__hosts = [] # LTP order
  440. self.__universes = OrderedDict() # {} # 192.168.0.1 = [0]*512
  441. #self.update(host="localhost",univ=0,dmxframe=[6]*512)
  442. dmxframe = [0]*512
  443. dmxframe[15] = 6
  444. #self.update(host="333.333.333.333",univ=8,dmxframe=dmxframe)
  445. def get_mtx(self,host="", univ=""):
  446. return self.__universes[str(univ)].get_mtx(host)
  447. def get(self,host="", univ=""):
  448. if str(univ) in self.__universes:
  449. return self.__universes[str(univ)].get(host)
  450. else:
  451. return [-8]*512
  452. def hosts(self):
  453. hosts = []
  454. for univ in self.__universes:
  455. x=self.__universes[univ].hosts()
  456. for y in x:
  457. #x=univ.hosts()
  458. if y not in hosts:
  459. hosts.append(y)
  460. hosts.sort()
  461. return hosts
  462. def univs(self):
  463. x=self.__universes.keys()
  464. x=list(x)
  465. #x.sort()
  466. return x
  467. def update(self,host,univ, dmxframe):
  468. #print( "update", host )
  469. if str(univ) not in self.__universes:
  470. self.__universes[str(univ)] = UniversBuffer(str(univ))
  471. self.__universes[str(univ)].update(host,dmxframe)
  472. def info(self,univ=0):
  473. out = {}
  474. #print self.__universes.keys()
  475. for univ in self.__universes.keys():
  476. #print("INFO:",univ)
  477. x=self.__universes[univ]
  478. out[univ] = x.info()
  479. return out
  480. # ============================================================
  481. # Network ====================================================
  482. # ============================================================
  483. import socket, struct
  484. import fcntl #socket control
  485. import errno
  486. def toPrintable(nonprintable):
  487. out = ""
  488. for i in str(nonprintable):
  489. printable = string.ascii_letters + string.digits +"/()=?{[]}\;:,.-_ "
  490. if str(i) in printable :
  491. out += str(i)
  492. return out
  493. def unpack_art_dmx(data):
  494. dmx = []
  495. for i in range(len(data[18:]) ):
  496. x=data[18+i]
  497. #print("x",x)
  498. #print( "data",b'!B', data[18+i])
  499. #x=struct.unpack( b'!B',data[18+i])
  500. #print( "data",b'!B', data[18+i],x)
  501. #x=x[0]
  502. dmx += [x]
  503. return dmx
  504. class Socket():
  505. def __init__(self):
  506. self.__poll = 0
  507. self.__data = []
  508. self.__addr = "NONE"
  509. self.open()
  510. def open(self):
  511. try:
  512. print("connecting to ArtNet Port 6454")
  513. self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  514. self.sock.bind(('', 6454))
  515. fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
  516. #self.sock.setblocking(0)
  517. except socket.error as e:
  518. print("Socket 6454 ", "ERR: {0} ".format(e.args))
  519. #raw_input()
  520. #sys.exit()
  521. def poll(self):
  522. if not self.__poll:
  523. try:
  524. self.__data, self.__addr = self.sock.recvfrom(6454)
  525. data, addr = (self.__data,self.__addr)
  526. self.host = addr[0]
  527. head = data[:18]
  528. rawdmx = data[18:]
  529. #print([head],addr)
  530. self.univ = -1
  531. try:
  532. self.head = struct.unpack("!8sHBBBBHBB" , head )
  533. except Exception as e:
  534. pass#print( "======E09823" , e)
  535. univ = self.head[6]/255 # /512 # * 512
  536. self.univ = int(univ)
  537. if not options.recive:
  538. self.__poll = 1
  539. return 1
  540. elif self.host.startswith(options.recive):
  541. self.__poll = 1
  542. return 1
  543. else:
  544. self.__poll = 0
  545. except socket.timeout as e:
  546. err = e.args[0]
  547. if err == 'timed out':
  548. sleep(1)
  549. print('recv timed out, retry later')
  550. else:
  551. print(e)
  552. except socket.error as e:
  553. pass
  554. def recive(self):
  555. if self.__poll:
  556. self.__poll = 0
  557. data, addr = (self.__data,self.__addr)
  558. #print( self.univ,self.head)
  559. self.dmx = unpack_art_dmx(data)
  560. return { "host":self.host,"dmx":self.dmx,"univ":self.univ,"head":self.head,"data":data,"addr":addr}
  561. # ============================================================
  562. # miniartnet4.py =============================================
  563. # ============================================================
  564. import time
  565. import socket
  566. import struct
  567. import random
  568. class ArtNetNode():
  569. """simple Object to generate ArtNet Network packages
  570. works in Python2 and Python3 2021-12-05
  571. """
  572. def __init__(self, to="10.10.10.255",univ=7):
  573. try:
  574. univ = int(univ)
  575. except:
  576. print("errror univ",univ ,"is not int ... set to 7")
  577. univ = 7
  578. self.univ=univ
  579. self.sendto = to
  580. self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  581. self.s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
  582. self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  583. self.stamp = time.time()
  584. self.test_stamp = time.time()
  585. self.dmx=[33]*512
  586. self.v=0
  587. self.d=1
  588. def head(self):
  589. self._header = []
  590. self._header.append(b"Art-Net\x00") # Name, 7byte + 0x00
  591. self._header.append(struct.pack('<H', 0x5000)) # OpCode ArtDMX -> 0x5000, Low Byte first
  592. self._header.append(struct.pack('>H', 14)) # Protocol Version 14, High Byte first
  593. self._header.append(b"\x00") # Order -> nope -> 0x00
  594. self._header.append(struct.pack('B',1)) # Eternity Port
  595. # Address
  596. #if 0 <= universe <= 15 and 0 <= net <= 127 and 0 <= subnet <= 15
  597. net, subnet, universe = (0,0,self.univ) #address
  598. self._header.append(struct.pack('<H', net << 8 | subnet << 4 | universe))
  599. self._header = b"".join(self._header)
  600. def send(self,dmx=None):
  601. if dmx is None:
  602. dmx = self.dmx
  603. else:
  604. self.dmx = dmx
  605. self.head()
  606. c=[self._header]
  607. c.append( struct.pack('>H', len(dmx) ) )
  608. #print([c])
  609. dmx_count = 0
  610. for v in dmx:
  611. if type(v) is not int:
  612. v=0
  613. elif v > 255: # max dmx value 255
  614. v = 255
  615. elif v < 0: # min dmx value 0
  616. v = 0
  617. dmx_count += 1
  618. c.append(struct.pack("B",v))
  619. c = b"".join(c)
  620. self.s.sendto(c, (self.sendto, 6454))
  621. return c
  622. def _test_frame(self):
  623. if self.test_stamp+0.1 > time.time():
  624. return 0
  625. self.test_stamp = time.time()
  626. dmx = [0]*512
  627. dmx[420] = self.v
  628. self.dmx = dmx
  629. self.next()
  630. #self.send(dmx)
  631. #print( [x] )
  632. if self.v >= 255:
  633. self.d=0
  634. elif self.v <=0:
  635. self.d=1
  636. if self.d:
  637. self.v+=1
  638. else:
  639. self.v-=1
  640. #time.sleep(1/30.)
  641. def next(self):
  642. if self.stamp + (1/60) <= time.time():
  643. self.send()
  644. def artnet_test():
  645. artnet = ArtNetNode()
  646. artnet._tes_frame()
  647. # ============================================================
  648. # helper =====================================================
  649. # ============================================================
  650. class Pager(): #scroll thru list
  651. def __init__(self):
  652. self.data = []
  653. self.index = 0
  654. self.wrap = 0
  655. self.maxindex = 0
  656. def append(self,val):
  657. self.data.append(val)
  658. self.check()
  659. def set(self,nr):
  660. self.index = nr
  661. self.check()
  662. def get(self):
  663. self.check()
  664. if self.data:
  665. return self.data[self.index]
  666. def next(self):
  667. self.index += 1
  668. self.check(flag=1)
  669. def prev(self):
  670. self.index -= 1
  671. self.check(flag=1)
  672. def check(self,flag=0):
  673. if flag:
  674. if self.maxindex and self.maxindex <= len(self.data):
  675. max = self.maxindex
  676. else:
  677. max = len(self.data)
  678. else:
  679. max = len(self.data)
  680. if self.wrap:
  681. if self.index >= max:
  682. self.index = 0
  683. elif self.index < 0:
  684. self.index = max-1
  685. else:
  686. if self.index >= max:
  687. self.index = max-1
  688. elif self.index < 0:
  689. self.index = 0
  690. # ============================================================
  691. # main =======================================================
  692. # ============================================================
  693. class Main():
  694. def __init__(self):
  695. pass
  696. def loop(self):
  697. ohost = HostBuffer()
  698. screen=Manager()
  699. screen.exit()
  700. screen.ohost = ohost
  701. #artnet_out = ArtNetNode(to="10.0.25.255")
  702. artnet_out = ArtNetNode(to=options.sendto)
  703. #artnet_out._test_frame()
  704. if options.testuniv:
  705. artnet = ArtNetNode(univ=options.testuniv)
  706. artnet._test_frame()
  707. xsocket = Socket()
  708. send_time = time.time()
  709. try:
  710. while 1:
  711. if options.testuniv:
  712. artnet._test_frame()
  713. #artnet_out._test_frame()
  714. if xsocket.poll():
  715. x = xsocket.recive()
  716. ohost.update(x["host"],x["univ"],x["dmx"])
  717. screen.sel_univ.data = ohost.univs()
  718. screen.sel_host.data = ohost.hosts()
  719. if send_time +(1/30.) < time.time() and options.sendto:
  720. send_time = time.time()
  721. #x=ohost.get(univ=univ2)
  722. info=ohost.info()
  723. jinfo = ""
  724. for i in info:
  725. univ = i
  726. #print( [ univ])
  727. if str(univ) == "54":
  728. break
  729. xl = json.dumps(univ) + "======= " #XX
  730. ltp=ohost.get(univ=i)
  731. #print( xl )
  732. #print( len(ltp) ,ltp[:20])
  733. ltp[511] = int(univ)
  734. artnet_out.univ=int(univ)
  735. artnet_out.send(ltp)
  736. #for j in info[i]:
  737. # print( str(univ)+" " + json.dumps([j,""]) )
  738. # for k in info[i][j]:
  739. # print( str(univ)+ " "+str(k).ljust(5," ")+": " + json.dumps( info[i][j][k]) )
  740. screen.loop()
  741. time.sleep(.001)
  742. finally:
  743. screen.exit()
  744. #print(dir(curses))
  745. if __name__ == "__main__":
  746. main = Main()
  747. main.loop()