device.py 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280
  1. import time
  2. from app import config, log, register, project_cf, speaker_cf, volume_cf, redisObj
  3. import paho.mqtt.client as mqtt
  4. import json
  5. from app.app_config import *
  6. from app.player import VLCController
  7. import sys
  8. from time import sleep
  9. from threading import Lock
  10. import os
  11. import threading
  12. import signal
  13. from app.config import Config
  14. """
  15. desc:
  16. 自定义超时异常
  17. """
  18. class TimeoutError(Exception):
  19. def __init__(self, msg):
  20. super(TimeoutError, self).__init__()
  21. self.msg = msg
  22. def time_out(interval, callback, msg):
  23. def decorator(func):
  24. def handler(signum, frame):
  25. raise TimeoutError(msg)
  26. def wrapper(*args, **kwargs):
  27. try:
  28. signal.signal(signal.SIGALRM, handler)
  29. signal.alarm(interval) # interval秒后向进程发送SIGALRM信号
  30. result = func(*args, **kwargs)
  31. signal.alarm(0) # 函数在规定时间执行完后关闭alarm闹钟
  32. return result
  33. except TimeoutError as e:
  34. callback(e)
  35. return wrapper
  36. return decorator
  37. def callback_timeout(e):
  38. log.logger.error(e.msg)
  39. """
  40. desc:
  41. 项目主要功能类
  42. """
  43. class Device(object):
  44. def __init__(self, config = config):
  45. self.model = config.model
  46. self.soft_version = config.soft_version
  47. self.hard_version = config.hard_version
  48. self.hostname = config.hostname
  49. self.ipaddr = config.ipaddr
  50. self.hard_volume = config.hard_volume
  51. self.hard_volume_control = config.hard_volume_control
  52. self.exten = config.exten
  53. self.exten_password = config.exten_password
  54. self.server_ipaddr = config.server_ipaddr
  55. self.mac = config.mac
  56. self.connect_flags = 1
  57. self.player_current_volume = config.player_current_volume
  58. self.init_player_state = config.init_player_state
  59. self.current_uri = config.current_uri
  60. self.fifo_flag = 0
  61. self.pull_rtsp = 0
  62. self.broadcast_volume_lock = Lock()
  63. if not self._check_config():
  64. sys.exit(1)
  65. # self.player = Player("--aout=alsa", "--audio-resampler=soxr", "--network-caching=50", "--network-synchronisation", "--clock-synchro=-1", "--cr-average=500", "--clock-jitter=50", "--live-caching=100")
  66. self.cmd = [
  67. "/usr/sbin/vlc",
  68. "--control", "rc",
  69. "--rc-fake-tty",
  70. "--quiet",
  71. "--aout=alsa",
  72. "--gain-init=0.0",
  73. "--audio-resampler=soxr",
  74. "--network-caching=50",
  75. "--network-synchronisation",
  76. "--clock-synchro=-1",
  77. "--cr-average=500",
  78. "--clock-jitter=50",
  79. "--live-caching=100",
  80. ]
  81. self.player = VLCController(cmd=self.cmd, on_state_change=self.vlc_callback)
  82. # self.player = VLCController(on_state_change=self.vlc_callback)
  83. self.task_player_state = -1
  84. self.task_soft_volume = -1
  85. self.task_uri = ""
  86. self.player_publish_volume = config.player_current_volume
  87. self.publish_uri = ""
  88. self.task_flag = "normal"
  89. self.publish_uri_flag = 0
  90. self.old_player_state = 0
  91. self.fifo_uri = ""
  92. self.mqttClient = mqtt.Client(client_id = self.mac, clean_session = True)
  93. self.mqttClient.username_pw_set(username=self.exten, password=self.exten_password)
  94. self.mqttClient.on_connect = self.on_connect
  95. self.redis_sub_volume = redisObj.subscribe_volume()
  96. self.audioControlStatus = False
  97. self.upgradeFlag = False
  98. self.currentScreenName = ""
  99. def _update_data(self):
  100. new_config = Config()
  101. self.model = new_config.model
  102. self.soft_version = new_config.soft_version
  103. self.hard_version = new_config.hard_version
  104. self.hostname = new_config.hostname
  105. self.ipaddr = new_config.ipaddr
  106. self.hard_volume = new_config.hard_volume
  107. self.hard_volume_control = new_config.hard_volume_control
  108. self.exten = new_config.exten
  109. self.exten_password = new_config.exten_password
  110. self.server_ipaddr = new_config.server_ipaddr
  111. self.mac = new_config.mac
  112. self.player_current_volume = new_config.player_current_volume
  113. self.init_player_state = new_config.init_player_state
  114. self.current_uri = new_config.current_uri
  115. self.player_publish_volume = new_config.player_current_volume
  116. def vlc_callback(self, state):
  117. if state == 3:
  118. self.MediaPlayerPlaying_cb()
  119. elif state == -1 or state == 0 or state == 5:
  120. self.MediaPlayerStopped_cb()
  121. # else:
  122. # log.logger.info("VLC state:%d not need handle" % (state))
  123. def start_relay_screen_action(self):
  124. speaker_cf.read(SPEAKER_CONFIG_FILE, encoding='utf-8')
  125. #广播音乐触发继电器
  126. relay_play_music = speaker_cf.get("relay_ctrl", "play_music")
  127. #告警触发继电器
  128. relay_alarm = speaker_cf.get("relay_ctrl", "alarm")
  129. url = self._handle_url(self.current_uri)
  130. log.logger.info("trigger url:%s" % (url))
  131. if url.startswith("rtp"):
  132. if relay_play_music != "Disabled":
  133. data = {}
  134. data["id"] = "gpio67"
  135. data["type"] = relay_play_music
  136. redisObj.lpush(json.dumps(data))
  137. log.logger.info("Trigger start play music relay")
  138. # if led_play_music != "Disabled":
  139. # data = {}
  140. # data["id"] = "gpio135"
  141. # data["type"] = led_play_music
  142. # redisObj.lpush(json.dumps(data))
  143. # log.logger.info("Trigger play music flash led")
  144. data = {}
  145. data["action"] = "on"
  146. data["name"] = "PlayMusic"
  147. self.currentScreenName = "PlayMusic"
  148. redisObj.screen_publish(json.dumps(data))
  149. log.logger.info("Trigger start play music to screen")
  150. elif url.startswith("rtsp"):
  151. if "sourceId" in url:
  152. id = int(url.rsplit("-", 1)[-1])
  153. if id > 10:
  154. if relay_play_music != "Disabled":
  155. data = {}
  156. data["id"] = "gpio67"
  157. data["type"] = relay_play_music
  158. redisObj.lpush(json.dumps(data))
  159. log.logger.info("Trigger start play music relay")
  160. #触发场景联动
  161. data = {}
  162. data["action"] = "on"
  163. data["name"] = "PlayMusic"
  164. self.currentScreenName = "PlayMusic"
  165. redisObj.screen_publish(json.dumps(data))
  166. log.logger.info("Trigger start play music to screen")
  167. if id > 0 and id <= 10:
  168. if relay_alarm != "Disabled":
  169. data = {}
  170. data["id"] = "gpio67"
  171. data["type"] = relay_alarm
  172. redisObj.lpush(json.dumps(data))
  173. log.logger.info("Trigger start play alarm relay")
  174. #触发场景联动
  175. data = {}
  176. data["action"] = "on"
  177. data["name"] = "Alarm"
  178. self.currentScreenName = "Alarm"
  179. redisObj.screen_publish(json.dumps(data))
  180. log.logger.info("Trigger start play alarm to screen")
  181. else:
  182. if relay_play_music != "Disabled":
  183. data = {}
  184. data["id"] = "gpio67"
  185. data["type"] = relay_play_music
  186. redisObj.lpush(json.dumps(data))
  187. log.logger.info("Trigger start play music relay")
  188. data = {}
  189. data["action"] = "on"
  190. data["name"] = "PlayMusic"
  191. self.currentScreenName = "PlayMusic"
  192. redisObj.screen_publish(json.dumps(data))
  193. log.logger.info("Trigger start play music to screen")
  194. else:
  195. if "sourceId" in url:
  196. id = int(url.rsplit("-", 1)[1])
  197. if id > 10:
  198. if relay_play_music != "Disabled":
  199. data = {}
  200. data["id"] = "gpio67"
  201. data["type"] = relay_play_music
  202. redisObj.lpush(json.dumps(data))
  203. log.logger.info("Trigger start play music relay")
  204. data = {}
  205. data["action"] = "on"
  206. data["name"] = "PlayMusic"
  207. self.currentScreenName = "PlayMusic"
  208. redisObj.screen_publish(json.dumps(data))
  209. log.logger.info("Trigger start play music to screen")
  210. if id > 0 and id <= 10:
  211. if relay_alarm != "Disabled":
  212. data = {}
  213. data["id"] = "gpio67"
  214. data["type"] = relay_alarm
  215. redisObj.lpush(json.dumps(data))
  216. log.logger.info("Trigger start alarm relay")
  217. data = {}
  218. data["action"] = "on"
  219. data["name"] = "Alarm"
  220. self.currentScreenName = "Alarm"
  221. redisObj.screen_publish(json.dumps(data))
  222. log.logger.info("Trigger start alarm to screen")
  223. else:
  224. if relay_play_music != "Disabled":
  225. data = {}
  226. data["id"] = "gpio67"
  227. data["type"] = relay_play_music
  228. redisObj.lpush(json.dumps(data))
  229. log.logger.info("Trigger start play music relay")
  230. data = {}
  231. data["action"] = "on"
  232. data["name"] = "PlayMusic"
  233. self.currentScreenName = "PlayMusic"
  234. redisObj.screen_publish(json.dumps(data))
  235. log.logger.info("Trigger start play music to screen")
  236. def stop_relay_screen_action(self):
  237. data = {}
  238. data["action"] = "off"
  239. data["name"] = self.currentScreenName
  240. redisObj.screen_publish(json.dumps(data))
  241. log.logger.info("Trigger stop to screen")
  242. speaker_cf.read(SPEAKER_CONFIG_FILE, encoding='utf-8')
  243. #广播音乐触发继电器
  244. relay_play_music = speaker_cf.get("relay_ctrl", "play_music")
  245. #告警触发继电器
  246. relay_alarm = speaker_cf.get("relay_ctrl", "alarm")
  247. if relay_play_music != "Disabled":
  248. data = {}
  249. data["id"] = "gpio67"
  250. data["type"] = "Off"
  251. redisObj.lpush(json.dumps(data))
  252. log.logger.info("Trigger stop play music relay")
  253. if relay_alarm != "Disabled":
  254. data = {}
  255. data["id"] = "gpio67"
  256. data["type"] = "Off"
  257. redisObj.lpush(json.dumps(data))
  258. log.logger.info("Trigger stop alerm relay")
  259. """
  260. desc:
  261. 开始播放事件回调,控制声音渐入
  262. """
  263. def MediaPlayerPlaying_cb(self):
  264. self.player.set_volume(self.player_publish_volume)
  265. log.logger.info("MediaPlayerPlaying_cb")
  266. data = {}
  267. data["name"] = "BROADCAST"
  268. data["action"] = "on"
  269. redisObj.volumeEventPush(json.dumps(data))
  270. self.start_relay_screen_action()
  271. def MediaPlayerStopped_cb(self):
  272. log.logger.info("MediaPlayerStopped_cb")
  273. data = {}
  274. data["name"] = "BROADCAST"
  275. data["action"] = "off"
  276. redisObj.volumeEventPush(json.dumps(data))
  277. self.stop_relay_screen_action()
  278. """
  279. desc:
  280. 系统信号处理函数,主要处理键盘输入,如ctrl+c等
  281. Parameters:
  282. param1 - 信号数字
  283. param2 - 处理方法
  284. """
  285. def singal_handler(self, singal_num, handler):
  286. self.mqttClient.loop_stop()
  287. self.mqttClient.disconnect()
  288. self.connect_flags = 0
  289. self.stop_pull_rtsp()
  290. if self.player:
  291. self.player.quit()
  292. log.logger.info("Mqtt disconnect now!")
  293. redisObj.logpush("MQTT,STATUS,Mqtt disconnect")
  294. sys.exit(0)
  295. """
  296. desc:
  297. 连接mqtt服务器
  298. """
  299. def run(self):
  300. while self.connect_flags:
  301. try:
  302. log.logger.info("Mqtt to %s:%d, connectting..." % (self.server_ipaddr, SERVER_MQTT_PORT))
  303. self.mqttClient.connect(self.server_ipaddr, SERVER_MQTT_PORT, MQTT_CONNECT_TIMEOUT)
  304. self.connect_flags = 0
  305. except:
  306. log.logger.error("Mqtt connect to %s:%d error" % (self.server_ipaddr, SERVER_MQTT_PORT))
  307. log.logger.error("Mqtt reconnect...")
  308. sleep(RETRY_SEC)
  309. self.mqttClient.loop_start()
  310. self.mqttClient.on_message = register.recieve_run
  311. self.mqttClient.on_subcribe = self.on_subcribe
  312. self.mqttClient.on_disconnect = self.on_disconnect
  313. self.mqttClient.on_publish = self.on_publish
  314. self.mqttClient.on_socket_close = self.on_socket_close
  315. self.mqttClient.subscribe(TOPIC_COMMAND, MQTT_QOS)
  316. return True
  317. """
  318. desc:
  319. mqtt连接事件回调函数
  320. """
  321. def on_connect(self, client, userdata, flags, rc):
  322. log.logger.info(mqtt.connack_string(rc))
  323. self.old_player_state = 0
  324. if self.current_uri != "" and self.init_player_state == 3:
  325. if self.player.get_state() != 3:
  326. data = {}
  327. data.setdefault("url", self.current_uri)
  328. data.setdefault("type", "normal")
  329. try:
  330. self.play(data)
  331. except:
  332. log.logger.error("Player on_connect(play) is error")
  333. log.logger.info("On_connect finished!")
  334. sleep(1)
  335. else:
  336. log.logger.info("Not need reconnect!")
  337. self._update_data()
  338. init_data = self._get_init_data()
  339. self.mqttClient.publish(TOPIC_EVENT, json.dumps(init_data).encode("utf-8"), MQTT_QOS)
  340. log.logger.info("Publish data: %s" % (init_data))
  341. return True
  342. """
  343. desc:
  344. 组装mqtt连接到的服务器时需上报的初始化数据
  345. """
  346. def _get_init_data(self):
  347. init_data = {}
  348. data = {}
  349. data.setdefault(SOLF_VOLUME, self.player_current_volume)
  350. data.setdefault(HARD_VOLUME, self.hard_volume)
  351. data.setdefault("hard-volume-control", self.hard_volume_control)
  352. data.setdefault(EXTEN, self.exten)
  353. data.setdefault(DEVICE_MODEL, self.model)
  354. data.setdefault(PRIVATE_IP, self.ipaddr)
  355. data.setdefault("soft-version", self.soft_version)
  356. data.setdefault("hard-version", self.hard_version)
  357. status = self.player.get_state()
  358. if status == 3 or status == 2:
  359. data.setdefault(STATUS, PLAYER_PLAYING)
  360. init_send_uri = self._handle_url(self.current_uri)
  361. data.setdefault("sourceId", init_send_uri)
  362. elif status == 4:
  363. data.setdefault(STATUS, PLAYER_PAUSE)
  364. elif status == -1 or status == 0:
  365. data.setdefault(STATUS, PLAYER_IDLE)
  366. else:
  367. data.setdefault(STATUS, PLAYER_ERROR)
  368. if os.path.exists("/oem/.onvif_upgrade/mqtt_upgraded"):
  369. data.setdefault("upgrade-status", "UpgradeSuccess")
  370. os.remove("/oem/.onvif_upgrade/mqtt_upgraded")
  371. init_data.setdefault(ACTION_NAME, "init")
  372. init_data.setdefault(DATA, data)
  373. return init_data
  374. """
  375. desc:
  376. 设置播放器音量
  377. Parameters:
  378. param1 - 音量
  379. param2 - 类型
  380. """
  381. def set_soft_volume(self, volume, type = "default"):
  382. self.player_current_volume = volume
  383. self.player_publish_volume = volume
  384. volume_cf.read(VOLUME_CONFIG_FILE, encoding='utf-8')
  385. volume_cf.set("volume", "broadcast_volume", str(volume))
  386. with open(VOLUME_CONFIG_FILE, "w") as f:
  387. volume_cf.write(f, space_around_delimiters=False)
  388. os.system("sync")
  389. webMsg = {}
  390. appVolume = {}
  391. webMsg["type"] = "broadcast"
  392. webMsg["appVolume"]=appVolume
  393. appVolume["broadcast_volume"]=volume
  394. redisObj.volumeItemPush(json.dumps(webMsg))
  395. if self.player.get_state() == 3 or self.player.get_state() == 2:
  396. self.player.set_volume(volume)
  397. return True
  398. def set_event_volume(self, volume):
  399. self.broadcast_volume_lock.acquire()
  400. if volume == -1:
  401. self.player_current_volume = 0
  402. self.player_publish_volume = 0
  403. else:
  404. self.player_current_volume = volume
  405. self.player_publish_volume = volume
  406. if volume == -1:
  407. self.player.set_volume(0)
  408. else:
  409. self.player.set_volume(volume)
  410. self.broadcast_volume_lock.release()
  411. return True
  412. """
  413. desc:
  414. task设置播放器音量
  415. Parameters:
  416. param1 - 音量
  417. param2 - 类型
  418. """
  419. def set_task_soft_volume(self, volume):
  420. self.task_soft_volume = volume
  421. self.player_publish_volume = volume
  422. if self.player.get_state() == 3 or self.player.get_state() == 2:
  423. self.player.set_volume(volume)
  424. return True
  425. """
  426. desc:
  427. 设置系统相关数据
  428. Parameters:
  429. param1 - 相关数据
  430. """
  431. def set_service_settings(self, data):
  432. if "soft-volume" in data:
  433. self.player_current_volume = int(data.get("soft-volume"))
  434. self.player_publish_volume = int(data.get("soft-volume"))
  435. if "hard-volume" in data:
  436. self.set_hard_volume(int(data.get("hard-volume")))
  437. if "hard-volume-control" in data:
  438. self.set_hard_volume_control(data.get("hard-volume-control"))
  439. return True
  440. """
  441. desc:
  442. 开始拉取本地摄像头的rtsp流并推送到服务器
  443. Parameters:
  444. param1 - 本地摄像头rtsp地址
  445. param2 - 服务器的rtsp地址
  446. """
  447. def start_pull_rtsp(self, src, dst):
  448. if not src:
  449. log.Logger.error("src not found")
  450. return False
  451. if not dst:
  452. log.Logger.error("dst not found")
  453. return False
  454. else:
  455. if not dst.startswith("rtsp"):
  456. dst = ''.join(["rtsp://", self.server_ipaddr, "/", dst])
  457. tmp_pull_rtsp = self.pull_rtsp
  458. self.stop_pull_rtsp()
  459. self.pull_rtsp = tmp_pull_rtsp
  460. sleep(1)
  461. os.system("%s %s %s > /dev/null 2>&1 &" % (RTSP_PUSHER, src, dst))
  462. log.logger.info("%s %s %s > /dev/null 2>&1 &" % (RTSP_PUSHER, src, dst))
  463. self.pull_rtsp = self.pull_rtsp + 1
  464. log.logger.info("self.pull_rtsp:%d" % (self.pull_rtsp))
  465. return True
  466. """
  467. desc:
  468. 停止拉取本地摄像头的rtsp流
  469. """
  470. def stop_pull_rtsp(self):
  471. os.system("/usr/bin/killall rtsp_pull_push > /dev/null 2>&1 &")
  472. self.pull_rtsp = 0
  473. return True
  474. def publishActionStatus(self, id, action, status):
  475. data = {}
  476. event = {}
  477. event.setdefault("type", TOPIC_RESPONSE)
  478. event.setdefault("id", id)
  479. event.setdefault(DATA, data)
  480. data.setdefault("action", action)
  481. data.setdefault("status", status)
  482. # try:
  483. # self._publish_msg(event)
  484. # except ERROR:
  485. # log.logger.error("Publish event:\n%s" % (ERROR))
  486. self.mqttClient.publish(TOPIC_RESPONSE, json.dumps(event).encode('utf-8'), MQTT_QOS)
  487. def _reboot(self):
  488. os.system("/sbin/reboot")
  489. """
  490. desc:
  491. 重启设备
  492. """
  493. def reboot(self, id):
  494. self.publishActionStatus(id, "reboot", "ok")
  495. sleep(0.5)
  496. self._reboot()
  497. return True
  498. def _reset(self):
  499. os.system("/bin/rm -rf /oem/.userdata && /bin/sync && /sbin/reboot")
  500. """
  501. desc:
  502. 重置设备
  503. """
  504. def reset(self, id):
  505. self.publishActionStatus(id, "reset", "ok")
  506. sleep(0.5)
  507. self._reset()
  508. return True
  509. """
  510. desc:
  511. 升级设备
  512. """
  513. def upgrade(self, id, data):
  514. if data.get("url"):
  515. reset= data.get("reset") or "no"
  516. os.system("/etc/scripts/upgrade.sh pre")
  517. cmd = "/etc/scripts/onvif_upgrade.sh upgrade " + data.get("url") + " " + reset + " >/dev/null 2>&1 &"
  518. os.system(cmd)
  519. else:
  520. # self.publishActionStatus(id, "upgrade", "missArgs")
  521. os.system("echo -n 'MissArgs' > /oem/.onvif_upgrade/status")
  522. return False
  523. # self.publishActionStatus(id, "upgrade", "Downloading")
  524. self.upgradeFlag = True
  525. return True
  526. """
  527. desc:
  528. 获取升级状态
  529. """
  530. def getUpgradeStatus(self, id):
  531. statusPath="/oem/.onvif_upgrade/status"
  532. status=""
  533. try:
  534. with open(statusPath, 'r') as file:
  535. status = file.read()
  536. except IOError:
  537. log.logger.error("无法打开文件:%s" % statusPath)
  538. self.publishActionStatus(id, "upgrade-status", "ReadError")
  539. return True
  540. self.publishActionStatus(id, "upgrade-status", status)
  541. return True
  542. """
  543. desc:
  544. 获取升级状态
  545. """
  546. def getUpgradeStatusFromFile(self):
  547. statusPath="/oem/.onvif_upgrade/status"
  548. status=""
  549. try:
  550. with open(statusPath, 'r') as file:
  551. status = file.read()
  552. except IOError:
  553. log.logger.error("无法打开文件:%s" % statusPath)
  554. return "ReadError"
  555. return status
  556. """
  557. desc:
  558. 导入配置
  559. """
  560. def importConfig(self, id, data):
  561. if data.get("url"):
  562. self.publishActionStatus(id, "import-config", "ok")
  563. cmd = "/etc/scripts/auto_privisioning.sh dhcp " + data.get("url") + " mqtt" + " >/dev/null 2>&1 &"
  564. os.system(cmd)
  565. else:
  566. self.publishActionStatus(id, "upgrade", "missArgs")
  567. return False
  568. return True
  569. """
  570. desc:
  571. 继电器控制
  572. """
  573. def relayControl(self, id, data):
  574. if not "switch" in data:
  575. self.publishActionStatus(id, "relay-control", "missArgs")
  576. return False
  577. duration = {}
  578. relayInfo = {}
  579. relayInfo["data"] = duration
  580. relayInfo["type"] = "relay"
  581. if data["switch"] == "on":
  582. relayInfo["action"] = "on"
  583. if "duration" in data:
  584. duration["duration"] = data["duration"]
  585. else:
  586. duration["duration"] = 0
  587. else:
  588. relayInfo["action"] = "off"
  589. duration["duration"] = 0
  590. redisObj.apipush(json.dumps(relayInfo))
  591. return True
  592. """
  593. desc:
  594. 设置系统的音量
  595. Parameters:
  596. param1 - 系统音量值
  597. """
  598. def set_hard_volume(self, volume):
  599. if volume and volume < 0:
  600. real_hard_volume = 0
  601. elif volume and volume > 30:
  602. real_hard_volume = 0
  603. else:
  604. real_hard_volume = volume
  605. try:
  606. os.system("/etc/scripts/set_volume.sh set %d - > /dev/null 2>&1 &" % (real_hard_volume))
  607. volume_cf.read(VOLUME_CONFIG_FILE, encoding='utf-8')
  608. volume_cf.set("volume", "volume_out", str(real_hard_volume))
  609. with open(VOLUME_CONFIG_FILE, "w") as f:
  610. volume_cf.write(f, space_around_delimiters=False)
  611. os.system("sync")
  612. self.hard_volume = real_hard_volume
  613. except ERROR:
  614. log.logger.error("Set hard volume error:\n%s" % (ERROR))
  615. return False
  616. return True
  617. """
  618. desc:
  619. 设置强控,不允许通过硬件按键修改系统音量
  620. Parameters:
  621. param1 - 强控开关
  622. """
  623. def set_hard_volume_control(self, value):
  624. if value:
  625. try:
  626. volume_cf.read(VOLUME_CONFIG_FILE, encoding='utf-8')
  627. volume_cf.set("volume", "hard_volume_control", value)
  628. with open(VOLUME_CONFIG_FILE, "w") as f:
  629. volume_cf.write(f, space_around_delimiters=False)
  630. os.system("sync")
  631. self.hard_volume_control = value
  632. except ERROR:
  633. log.logger.error("Set hard volume control value:\n%s" % (ERROR))
  634. return False
  635. else:
  636. log.logger.error("Set hard volume control value not exist")
  637. return False
  638. return True
  639. """
  640. desc:
  641. 设置系统分机信息
  642. Parameters:
  643. param1 - 服务器地址
  644. param2 - 用户名(分机号)
  645. param3 - 分机密码
  646. """
  647. def set_exten(self, host, exten, password):
  648. if host and exten and password:
  649. try:
  650. speaker_cf.read(SPEAKER_CONFIG_FILE, encoding='utf-8')
  651. speaker_cf.set("account_info_1", "username", exten)
  652. speaker_cf.set("account_info_1", "passwd", password)
  653. speaker_cf.set("account_info_1", "server", host)
  654. with open(SPEAKER_CONFIG_FILE, "w") as f:
  655. speaker_cf.write(f, space_around_delimiters=False)
  656. os.system("sync")
  657. except ERROR:
  658. log.logger.error("Set exten error:\n%s" % (ERROR))
  659. return False
  660. else:
  661. log.logger.error("Set exten value not full")
  662. return False
  663. return True
  664. """
  665. desc:
  666. vlc播放指定数据
  667. Parameters:
  668. param1 - 播放数据
  669. """
  670. def play(self, data):
  671. if "url" in data:
  672. url = data.get("url")
  673. self.publish_uri = self._handle_url(url)
  674. if self.publish_uri_flag == 1:
  675. self.publish_uri_flag = 0
  676. else:
  677. self.publish_uri_flag = 1
  678. # if url.startswith("x10-"):
  679. # url_type=1
  680. # else:
  681. # url_type=0
  682. if url.startswith("rtp"):
  683. pass
  684. elif url.startswith("rtsp"):
  685. pass
  686. else:
  687. if not url.startswith("http"):
  688. url = ''.join(["http://", self.server_ipaddr, ":", SERVER_ICE_PORT, "/", url])
  689. else:
  690. log.logger.warning("Url not found!")
  691. return False
  692. if "soft-volume" in data:
  693. if "type" in data:
  694. if data.get("type") == "task":
  695. self.set_task_soft_volume(int(data.get("soft-volume")))
  696. else:
  697. self.set_soft_volume(int(data.get("soft-volume")))
  698. else:
  699. self.set_soft_volume(int(data.get("soft-volume")))
  700. if "hard-volume" in data:
  701. self.set_hard_volume(int(data.get("hard-volume")))
  702. if "hard-volume-control" in data:
  703. self.set_hard_volume_control(data.get("hard-volume-control"))
  704. if "type" in data:
  705. if data.get("type") == "task":
  706. self.task_player_state = 3
  707. self.task_uri = url
  708. self.task_flag = "task"
  709. else:
  710. self.init_player_state = 3
  711. self.current_uri = url
  712. self.task_flag = "normal"
  713. else:
  714. self.init_player_state = 3
  715. self.current_uri = url
  716. self.task_flag = "normal"
  717. try:
  718. if not self.player.running:
  719. self.player.start_vlc()
  720. self.player.play(url=url)
  721. else:
  722. self.player.play(url=url)
  723. self.player.set_volume(self.player_publish_volume)
  724. if "type" in data and data.get("type") == "task":
  725. if data.get("type") != "task":
  726. if "soft-volume" in data:
  727. self.task_soft_volume = int(data.get("soft-volume"))
  728. else:
  729. try:
  730. project_cf.read(PROJECT_CONFIG, encoding='utf-8')
  731. project_cf.set("general", "init_player_state", str(self.init_player_state))
  732. project_cf.set("general", "current_uri", str(self.current_uri))
  733. with open(PROJECT_CONFIG, "w") as f:
  734. project_cf.write(f, space_around_delimiters=False)
  735. os.system("sync")
  736. except ERROR:
  737. log.logger.error("Save init player state or current uri error:\n%s" % (ERROR))
  738. return False
  739. except:
  740. log.logger.error("Player play uri:%s is error" % (url))
  741. return False
  742. return True
  743. """
  744. desc:
  745. 播放器暂停
  746. Parameters:
  747. param1 - 暂停模式
  748. """
  749. def pause(self, value):
  750. if self.audioControlStatus:
  751. return True
  752. self.init_player_state = 0
  753. self.task_player_state = -1
  754. try:
  755. self.player.stop()
  756. except:
  757. log.logger.error("Player pause(stop) is error")
  758. try:
  759. project_cf.read(PROJECT_CONFIG, encoding='utf-8')
  760. project_cf.set("general", "init_player_state", str(self.init_player_state))
  761. with open(PROJECT_CONFIG, "w") as f:
  762. project_cf.write(f, space_around_delimiters=False)
  763. os.system("sync")
  764. except ERROR:
  765. log.logger.error("Save init player state or current uri error:\n%s" % (ERROR))
  766. return True
  767. """
  768. desc:
  769. 播放器恢复播放
  770. Parameters:
  771. param1 - 恢复数据
  772. """
  773. def resume(self, value):
  774. if self.audioControlStatus:
  775. return True
  776. self.init_player_state = 3
  777. self.task_player_state = -1
  778. self.task_soft_volume = -1
  779. self.task_uri = ""
  780. self.set_soft_volume(self.player_current_volume)
  781. try:
  782. project_cf.read(PROJECT_CONFIG, encoding='utf-8')
  783. project_cf.set("general", "init_player_state", str(self.init_player_state))
  784. with open(PROJECT_CONFIG, "w") as f:
  785. project_cf.write(f, space_around_delimiters=False)
  786. os.system("sync")
  787. except ERROR:
  788. log.logger.error("Save init player state or current uri error:\n%s" % (ERROR))
  789. if value == "play":
  790. data = {}
  791. if self.current_uri != "" and self.init_player_state == 3:
  792. data = {}
  793. data.setdefault("url", self.current_uri)
  794. try:
  795. self.play(data)
  796. except:
  797. log.logger.error("Player resume(play) is error")
  798. else:
  799. self.stop()
  800. else:
  801. try:
  802. self.player.start_vlc()
  803. self.player.play()
  804. except:
  805. log.logger.error("Player resume is error")
  806. return True
  807. def _publish_stop_event(self):
  808. data = {}
  809. event = {}
  810. event.setdefault(ACTION_NAME, TOPIC_UPDATE)
  811. event.setdefault(DATA, data)
  812. data.setdefault(STATUS, PLAYER_IDLE)
  813. try:
  814. self.mqttClient.publish(TOPIC_EVENT, json.dumps(event).encode('utf-8'), MQTT_QOS)
  815. log.logger.info("Publish event:%s" % (event))
  816. except ERROR:
  817. log.logger.error("Publish stop event error:\n%s" % (ERROR))
  818. """
  819. desc:
  820. 播放器停止播放
  821. """
  822. def stop(self):
  823. self.init_player_state = -1
  824. self.current_uri = ""
  825. self.task_player_state = -1
  826. self.task_soft_volume = -1
  827. self.task_uri = ""
  828. try:
  829. self.player.quit()
  830. try:
  831. self.t = threading.Thread(target = self._publish_stop_event, args = ())
  832. self.t.setDaemon(True)
  833. self.t.start()
  834. except ERROR:
  835. log.logger.error(ERROR)
  836. try:
  837. project_cf.read(PROJECT_CONFIG, encoding='utf-8')
  838. project_cf.set("general", "init_player_state", str(self.init_player_state))
  839. project_cf.set("general", "current_uri", "")
  840. with open(PROJECT_CONFIG, "w") as f:
  841. project_cf.write(f, space_around_delimiters=False)
  842. os.system("sync")
  843. except ERROR:
  844. log.logger.error("Save init player state or current uri error:\n%s" % (ERROR))
  845. return False
  846. except:
  847. log.logger.error("Player stop is error")
  848. return False
  849. return True
  850. def reconnect_loop(self):
  851. while True:
  852. try:
  853. log.logger.info("Attempting reconnect...")
  854. self.mqttClient.reconnect()
  855. log.logger.info("Reconnected successfully.")
  856. break
  857. except Exception as e:
  858. log.logger.error("Reconnect failed:", e)
  859. sleep(3)
  860. def on_subcribe(self, client, userdata, mid, granted_qos):
  861. pass
  862. def on_publish(self, client, userdata, mid):
  863. pass
  864. def on_disconnect(self, client, userdata, rc):
  865. log.logger.error("on_disconnect: %d" % (rc))
  866. redisObj.logpush("MQTT,STATUS,Mqtt disconnect")
  867. #mqtt重连时,是否恢复播放
  868. music_auto_resume = speaker_cf.get("system", "music_auto_resume")
  869. if music_auto_resume == "no":
  870. self.stop()
  871. log.logger.info("Not need resume play, stop play")
  872. # if rc != 0:
  873. # # 异步启动重连
  874. # threading.Thread(target=self.reconnect_loop, daemon=True).start()
  875. # else:
  876. # log.logger.info("normal disconnect")
  877. """
  878. desc:
  879. 检测系统的必要配置信息
  880. """
  881. def _check_config(self):
  882. if not self.model:
  883. log.logger.error("Model not found!")
  884. return False
  885. elif not self.mac:
  886. log.logger.error("Mac not found!")
  887. return False
  888. elif not self.server_ipaddr:
  889. log.logger.error("Server Ipaddr not found!")
  890. return False
  891. elif not self.exten:
  892. log.logger.error("Extension not found!")
  893. return False
  894. elif self.hard_volume < 0:
  895. log.logger.error("Hard Volume error!")
  896. return False
  897. else:
  898. return True
  899. @time_out(2, callback_timeout, "Read volume out timeout!")
  900. def _read_volume_out(self):
  901. volume_cf.read(VOLUME_CONFIG_FILE, encoding='utf-8')
  902. return int(volume_cf.get("volume", "volume_out"))
  903. def _get_volume_out(self):
  904. volume_out = self._read_volume_out()
  905. if volume_out:
  906. return volume_out
  907. else:
  908. return 0
  909. @time_out(2, callback_timeout, "Read volume control timeout!")
  910. def _read_hard_volume_control(self):
  911. volume_cf.read(VOLUME_CONFIG_FILE, encoding='utf-8')
  912. return volume_cf.get("volume", "hard_volume_control")
  913. def _get_hard_volume_control(self):
  914. hard_volume_control = self._read_hard_volume_control()
  915. if hard_volume_control:
  916. return hard_volume_control
  917. else:
  918. return "on"
  919. @time_out(5, callback_timeout, "Publish message timeout!")
  920. def _publish_msg(self, event):
  921. self.mqttClient.publish(TOPIC_EVENT, json.dumps(event).encode('utf-8'), MQTT_QOS)
  922. log.logger.info("Publish event:%s" % (event))
  923. """
  924. desc:
  925. 监测系统状态变化,如音量,播放状态等
  926. """
  927. def _check_variable(self):
  928. old_soft_volume = self.player_publish_volume
  929. old_hard_volume = self.hard_volume
  930. old_exten = self.exten
  931. #old_player_state = self.plaer.get_state()
  932. old_hard_volume_control = self.hard_volume_control
  933. old_pull_rtsp = self.pull_rtsp
  934. old_publish_uri_flag = self.publish_uri_flag
  935. old_upgrade_status = ""
  936. while True:
  937. sleep(CHECK_INTERVAL)
  938. data = {}
  939. event = {}
  940. event.setdefault(ACTION_NAME, TOPIC_UPDATE)
  941. event.setdefault(DATA, data)
  942. if self.upgradeFlag:
  943. new_upgrade_status = self.getUpgradeStatusFromFile()
  944. #UpgradeFailed VerifyFailed downloadError MissArgs
  945. if new_upgrade_status == "UpgradeFailed" or new_upgrade_status == "VerifyFailed" or new_upgrade_status == "downloadError" or new_upgrade_status == "MissArgs":
  946. self.upgradeFlag = False
  947. if new_upgrade_status != old_upgrade_status:
  948. old_upgrade_status = new_upgrade_status
  949. data.setdefault("upgrade-status", new_upgrade_status)
  950. try:
  951. new_soft_volume = self.player_publish_volume
  952. if old_soft_volume != new_soft_volume:
  953. old_soft_volume = new_soft_volume
  954. data.setdefault(SOLF_VOLUME, new_soft_volume)
  955. except ERROR:
  956. log.logger.error("Checkout soft volume:%s" % (ERROR))
  957. try:
  958. new_hard_volume = self._get_volume_out()
  959. if old_hard_volume != new_hard_volume:
  960. old_hard_volume = new_hard_volume
  961. data.setdefault(HARD_VOLUME, new_hard_volume)
  962. except ERROR:
  963. log.logger.error("Checkout hard volume:%s" % (ERROR))
  964. try:
  965. new_player_state = self.player.get_state()
  966. if self.old_player_state != new_player_state:
  967. self.old_player_state = new_player_state
  968. if new_player_state == -1 or new_player_state == 0:
  969. player_status = PLAYER_IDLE
  970. elif new_player_state == 4:
  971. player_status = PLAYER_PAUSE
  972. elif new_player_state == 3 or new_player_state == 2:
  973. player_status = PLAYER_PLAYING
  974. data.setdefault("sourceId", self.publish_uri)
  975. data.setdefault(SOLF_VOLUME, self.player_publish_volume)
  976. else:
  977. player_status = PLAYER_ERROR
  978. data.setdefault(STATUS, player_status)
  979. except ERROR:
  980. log.logger.error("Checkout player state:%s" % (ERROR))
  981. try:
  982. new_hard_volume_control = self._get_hard_volume_control()
  983. if old_hard_volume_control != new_hard_volume_control:
  984. old_hard_volume_control = new_hard_volume_control
  985. data.setdefault(HARD_VOLUME_CONTROL, new_hard_volume_control)
  986. except ERROR:
  987. log.logger.error("Checkout hard volume control:%s" % (ERROR))
  988. try:
  989. new_publish_uri_flag = self.publish_uri_flag
  990. if old_publish_uri_flag != new_publish_uri_flag:
  991. old_publish_uri_flag = new_publish_uri_flag
  992. data.setdefault("sourceId", self.publish_uri)
  993. data.setdefault(SOLF_VOLUME, self.player_publish_volume)
  994. except ERROR:
  995. log.logger.error("Checkout publish_uri:%s" % (ERROR))
  996. try:
  997. new_pull_rtsp = self.pull_rtsp
  998. if old_pull_rtsp != new_pull_rtsp:
  999. old_pull_rtsp = new_pull_rtsp
  1000. if new_pull_rtsp != 0:
  1001. data.setdefault("pull-rtsp", 1)
  1002. else:
  1003. data.setdefault("pull-rtsp", 0)
  1004. except ERROR:
  1005. log.logger.error("Checkout rtsp:%s" % (ERROR))
  1006. if event.get(DATA) != {}:
  1007. try:
  1008. self._publish_msg(event)
  1009. except ERROR:
  1010. log.logger.error("Publish event:\n%s" % (ERROR))
  1011. redisObj.logpush("MQTT,STATUS,%s" % json.dumps(data).replace(",", ";").replace('"', ''))
  1012. def _handle_url(self, origin_url):
  1013. if origin_url:
  1014. if origin_url.startswith("rtp"):
  1015. target_uri = origin_url
  1016. elif origin_url.startswith("rtsp"):
  1017. target_uri = origin_url
  1018. else:
  1019. if "/" in origin_url:
  1020. target_uri = origin_url.rsplit("/", 1)[1]
  1021. else:
  1022. target_uri = origin_url
  1023. return target_uri
  1024. else:
  1025. return ""
  1026. """
  1027. desc:
  1028. 监测fifo
  1029. """
  1030. def _fifo(self):
  1031. if os.path.exists(FIFO_PATH):
  1032. os.remove(FIFO_PATH)
  1033. os.mkfifo(FIFO_PATH)
  1034. while True:
  1035. rf = os.open(FIFO_PATH, os.O_RDONLY)
  1036. data = os.read(rf, 64)
  1037. data = data.decode("utf-8")
  1038. log.logger.info("received msg from fifo:%s" % (data))
  1039. if data == "0":
  1040. self.old_player_state = -1
  1041. if self.player.get_state() == 3:
  1042. self.fifo_flag = 1
  1043. self.fifo_uri = self.current_uri
  1044. self.stop()
  1045. # os.system("/etc/scripts/pa_mute.sh 0 > /dev/null 2>&1 &")
  1046. elif data == "1":
  1047. if self.fifo_flag == 1:
  1048. self.fifo_flag = 0
  1049. play_data = {}
  1050. play_data.setdefault("url", self.fifo_uri)
  1051. try:
  1052. self.play(play_data)
  1053. except:
  1054. log.logger.error("Player play is error")
  1055. else:
  1056. log.logger.error("No support this action!")
  1057. os.close(rf)
  1058. """
  1059. desc:
  1060. 启动监测线程
  1061. """
  1062. def check_start(self):
  1063. try:
  1064. self.t = threading.Thread(target = self._check_variable, args = ())
  1065. self.t.setDaemon(True)
  1066. self.t.start()
  1067. return True
  1068. except ERROR:
  1069. log.logger.error(ERROR)
  1070. """
  1071. desc:
  1072. DAEMON
  1073. """
  1074. def daemon(self):
  1075. try:
  1076. if not self.t.is_alive():
  1077. log.logger.info("Data check is restarting...!")
  1078. self.t = threading.Thread(target = self._check_variable, args = ())
  1079. self.t.setDaemon(True)
  1080. self.t.start()
  1081. log.logger.info("Data check is restarted!")
  1082. return True
  1083. except ERROR:
  1084. log.logger.error(ERROR)
  1085. """
  1086. desc:
  1087. 启动fifo监测
  1088. """
  1089. def check_fifo_start(self):
  1090. try:
  1091. t = threading.Thread(target = self._fifo, args = ())
  1092. t.setDaemon(True)
  1093. t.start()
  1094. return True
  1095. except ERROR:
  1096. log.logger.error(ERROR)
  1097. """
  1098. desc:
  1099. socket断线回调
  1100. """
  1101. def on_socket_close(self, client, userdata, sock):
  1102. log.logger.error("Socket error(disconnect) occur!")
  1103. redisObj.logpush("MQTT,STATUS,Mqtt disconnect")
  1104. def handleRedisVolumeData(self, data):
  1105. if data:
  1106. if "broadcast_volume" in data:
  1107. self.set_event_volume(data["broadcast_volume"])
  1108. if data["broadcast_volume"] == -1:
  1109. log.logger.info("Set broadcast_volume:0")
  1110. else:
  1111. log.logger.info("Set broadcast_volume:%d" % data["broadcast_volume"])
  1112. else:
  1113. pass
  1114. def startParseRedisSubMsg(self):
  1115. log.logger.info("Start parse redis sub...")
  1116. while True:
  1117. msg = self.redis_sub_volume.parse_response()
  1118. # log.logger.info("msg:%s" % msg)
  1119. try:
  1120. data = json.loads(msg[2])
  1121. except:
  1122. log.logger.error("msg is not a json format:%s" % (msg[2]))
  1123. continue
  1124. t = threading.Thread(target=self.handleRedisVolumeData, args=[data])
  1125. t.setDaemon(True)
  1126. t.start()
  1127. def startRedisSubMsg(self):
  1128. t = threading.Thread(target=self.startParseRedisSubMsg, args=())
  1129. t.setDaemon(True)
  1130. t.start()