# coding:utf-8
# !/usr/bin/env python3
__author__ = "Wenjian Long"
__version__ = "0.0.1"
__email__ = "Wenjian.Long@lnxall.com"

import threading
import paho.mqtt.client as mqtt
#from queue import Queue
#import serial
import time
import json
import base64

import struct
import types
import syslog
import os
import sys
from time import sleep
from onvif import ONVIFCamera
from onvif.exceptions import ONVIFError

MQTT_BROKER = "localhost"
MQTT_PORT = 1883
MQTT_USER = None
MQTT_PASSWD = None
MQTT_QoS = 2
MQTT_CONN_TIMEOUT = 10
MQTT_PUB_TIMEOUT = 6000

GW_SN = "218806000001"

IPC_CONFIG_NAME = "/app/config/ip_camera_cfg.json"
NODE_CONFIG_NAME = "/app/node/nodes_cfg.json"
FAC_INI_FILE = "/app/config/fac.ini"
BOARD_NAME_PATH = "/tmp/sysinfo/board_name"

ipc_objects = []
ipc_config = []
node_config = []
mqtt_client = None
data_list = []
mqtt_msg_list = []
pgrep_ffmpeg_fl = "pgrep -fl ffmpeg"
pgrep_ffmpeg_afl = "pgrep -afl ffmpeg"
mqtt_sub_topic = "ipc/+/TCP_CLIENT/device/+/data/Set_Rglt_Raw"
ffmpeg_str = "ffmpeg -rtsp_transport tcp -nostdin"


class IPCamera:
	def __init__(self, host, port, user, password, nvrAddr=None, wsdl_dir=None):
		self.host = host
		self.port = port
		self.user = user
		self.password = password
		self.wsdl_dir = '/usr/wsdl'
		self.cam = None
		self.media = None
		self.media_profile = None
		self.ptz = None
		self.invalid = 0
		self.onvif_error_info = 0
		self.streamCnt = 1
		
		self.ipc_InitEnv(host, port, user, password)
		if self.invalid == 0 and nvrAddr != None:
			self.event_init()
	def event_listen(self, req):
		syslog.syslog("===============================event_listen===================================")
		cnt = 0
		while True:
			event_info = {}
			cnt = cnt +1
			sleep(0.3)
			syslog.syslog("===============================cnt %d start===================================" %cnt)
			pull_msg = self.pullpoint.PullMessages(req)
			#if cnt == 1:
			#	continue
			syslog.syslog("===pull_msg:%s" %pull_msg)
			syslog.syslog("len pull_msg:%d" %len(pull_msg))
			syslog.syslog("CurrentTime:%s TerminationTime:%s" %(pull_msg["CurrentTime"],pull_msg["TerminationTime"]))
			#syslog.syslog("find NotificationMessage:%d" %pull_msg.find("NotificationMessage"))
			if "NotificationMessage" not in pull_msg:
				syslog.syslog("==---==pull_msg:%s" %pull_msg)
				continue
			syslog.syslog("len NotificationMessage:%d" %(len(pull_msg["NotificationMessage"])))
			for index in range(len(pull_msg["NotificationMessage"])):
				syslog.syslog("----------------------index %d len %d start----------------------" %(index,len(pull_msg["NotificationMessage"])))
				syslog.syslog("Topic value:%s" %pull_msg["NotificationMessage"][index]["Topic"].value)
				syslog.syslog("Message:%s" %pull_msg["NotificationMessage"][index]["Message"].Message)
				event_info["Topic_value"] = pull_msg["NotificationMessage"][index]["Topic"].value
				if pull_msg["NotificationMessage"][index]["Topic"].value.find("AudioAnalytics") < 0:
					event_info["_UtcTime"] = pull_msg["NotificationMessage"][index]["Message"].Message["_UtcTime"]
					event_info["_PropertyOperation"] = pull_msg["NotificationMessage"][index]["Message"].Message["_PropertyOperation"]
					event_info["_Name"] = pull_msg["NotificationMessage"][index]["Message"].Message["Data"].SimpleItem["_Name"]
					event_info["_Value"] = pull_msg["NotificationMessage"][index]["Message"].Message["Data"].SimpleItem["_Value"]
					syslog.syslog("_UtcTime:%s _PropertyOperation:%s" %(pull_msg["NotificationMessage"][index]["Message"].Message["_UtcTime"],pull_msg["NotificationMessage"][index]["Message"].Message["_PropertyOperation"]))
					syslog.syslog("_Name:%s _Value:%s" %(pull_msg["NotificationMessage"][index]["Message"].Message["Data"].SimpleItem["_Name"],pull_msg["NotificationMessage"][index]["Message"].Message["Data"].SimpleItem["_Value"]))
				else:
					event_info["_UtcTime"] = pull_msg["NotificationMessage"][index]["Message"].Message["_UtcTime"]
					event_info["_Name"] = pull_msg["NotificationMessage"][index]["Message"].Message["Data"].SimpleItem[0]["_Name"]
					event_info["_Value"] = pull_msg["NotificationMessage"][index]["Message"].Message["Data"].SimpleItem[0]["_Value"]
					syslog.syslog("_UtcTime:%s" %pull_msg["NotificationMessage"][index]["Message"].Message["_UtcTime"])
					syslog.syslog("==_Name:%s _Value:%s" %(pull_msg["NotificationMessage"][index]["Message"].Message["Data"].SimpleItem[0]["_Name"], pull_msg["NotificationMessage"][index]["Message"].Message["Data"].SimpleItem[0]["_Value"]))
				event_msg_ctrl(self.host, event_info)
				syslog.syslog("----------------------index %d end----------------------" %index)
				#syslog.syslog("_Name:%s" %pull_msg["NotificationMessage"][index]["Message"]["data"]["SimpleItem"]._Name)
				
			#syslog.syslog(pull_msg)
			syslog.syslog("===============================cnt %d end=====================================" %cnt)
		
	def ipc_InitEnv(self, host, port, user, password):
		try:
			syslog.syslog("==============(%s %d %s %s)" %(host, port, user, password))
			if self.cam != None and (host != self.host or port != self.port or user != self.user or password != self.password):
				#self.host = host
				#self.port = port
				#self.user = user
				#self.password = password
				#syslog.syslog("self.cam type %s" %(type(self.cam)))
				syslog.syslog("python ipcamera update auth url 1")
				self.cam.update_auth(user,password)
				syslog.syslog("python ipcamera update auth url 2")
				self.cam.update_url(host, port)
				syslog.syslog("python ipcamera update auth url 3")
				
			syslog.syslog("python ipcamera ONVIFCamera in...")
			if self.cam == None:
				self.cam = ONVIFCamera(self.host, self.port, self.user, self.password, self.wsdl_dir, no_cache=True)
			syslog.syslog("python ipcamera ONVIFCamera out...")
			# Create media service object
			self.media = self.cam.create_media_service(from_template=False)

			# Get target profile
			self.media_profile = self.media.GetProfiles()[0]
			try:
				Profiles = self.media.GetProfiles()
				self.streamCnt = len(Profiles)
				for index in range(len(Profiles)):
					if index < 3 and (Profiles[index]["VideoEncoderConfiguration"]["Resolution"].Width >= 1280 or Profiles[index]["VideoEncoderConfiguration"]["Resolution"].Height >= 720):
						self.streamCnt = index+1
				syslog.syslog("self.streamCnt:%d" %self.streamCnt)
				
				# Create ptz service object
				self.ptz = self.cam.create_ptz_service(from_template=False)
				request = self.ptz.create_type('GetConfigurationOptions')
				request.ConfigurationToken = self.media_profile.PTZConfiguration._token
				ptz_configuration_options = self.ptz.GetConfigurationOptions(request)

				self.ptz.Stop({'ProfileToken': self.media_profile._token})
			except ONVIFError,e:
				syslog.syslog("python ipcamera ptz except:%s" %(e.reason))
				self.ptz_error_info = e.reason
				self.ptz = 0
			else:
				self.ptz_error_info = 0
				syslog.syslog("python ipcamera  ptz ok...")
		except ONVIFError,e:
			syslog.syslog("python ipcamera exceptions:%s" %(e.reason))
			self.onvif_error_info = e.reason
			self.media_profile = 0
			self.invalid = 1
		else:
			self.invalid = 0
			syslog.syslog("python ipcamera ONVIFCamera init ok...")
			# Get PTZ configuration options for getting continuous move range
			
	def event_init(self):
		syslog.syslog("------1111---self.cam %s---" %type(self.cam))
		
		event_service = self.cam.create_events_service()
		syslog.syslog("------2222 1111---event_service:%s---" %type(event_service))
		event_properties = event_service.GetEventProperties()
		PullPointSubscription = event_service.CreatePullPointSubscription()
		syslog.syslog("CreatePullPointSubscription:%s" %PullPointSubscription)

		self.pullpoint = self.cam.create_pullpoint_service()
		req = self.pullpoint.create_type('PullMessages')
		req.MessageLimit=180
		
		self.event_thread = threading.Thread(target=self.event_listen, args=(req,))
		self.event_thread.setDaemon(True)
		self.event_thread.start()
		
	def ipc_GetStreamUri(self):		
		syslog.syslog("ipc_GetStreamUri...")
		request = self.media.create_type('GetStreamUri')
		request.ProfileToken = self.media_profile._token
		rtspUrl = 'rtsp://' + self.host + ':554/Streaming/Channels/101?transportmode=unicast&profile=Profile_1'
		try:
		    url = self.media.GetStreamUri(request)
		    rtspUrl = url.Uri
		except ONVIFError,e:
		    syslog.syslog("python ipcamera GetStreamUri except:%s" %(e.reason))
		    self.ptz_error_info = e.reason
		    self.ptz = 0
		else:
		    syslog.syslog("rtspUrl:%s ok" %rtspUrl)
		syslog.syslog("rtspUrl:%s" %rtspUrl)
		obj_result = {}
		obj_result['rtspUrl'] = rtspUrl
		obj_result['streamCnt'] = self.streamCnt
		obj_result['result'] = 0
		data_json = json.dumps(obj_result)
		return data_json

	def perform_move(self, request, timeout=1):
		# Start continuous move
		self.ptz.ContinuousMove(request)
		# Wait a certain time
		sleep(timeout)
		# Stop continuous move
		self.ptz.Stop({'ProfileToken': request.ProfileToken})

	def move_ContinuousMove(self, x, y, z=0, timeout=1):
		syslog.syslog("move_ContinuousMove...")
		request = self.ptz.create_type('ContinuousMove')
		request.ProfileToken = self.media_profile._token
		request.Velocity.PanTilt._x = x
		request.Velocity.PanTilt._y = y
		request.Velocity.Zoom._x = z
		perform_move(request, timeout)

	def perform_RelativeMove(self, request, timeout):
		# Start continuous move
		self.ptz.RelativeMove(request)
		# Wait a certain time
		sleep(timeout)
		# Stop continuous move
		self.ptz.Stop({'ProfileToken': request.ProfileToken})

	def move_RelativeMove(self, x, y, z=0, timeout=1):
		syslog.syslog('move_RelativeMove...')
		request = self.ptz.create_type('RelativeMove')
		request.ProfileToken = self.media_profile._token
		request.Translation.PanTilt._x = x
		request.Translation.PanTilt._y = y
		request.Translation.Zoom._x = z
		self.perform_RelativeMove(request, timeout)

	def ptz_GetPresets(self):
		syslog.syslog('ptz_GetPresets...')
		request = self.ptz.create_type('GetPresets')
		request.ProfileToken = self.media_profile._token
		presets = self.ptz.GetPresets(request)
		obj_result = {}
		data = []
		for index in range(len(presets)):
			tmp_data = {}
			tmp_data['token'] = presets[index]._token
			tmp_data['name'] = presets[index].Name
			data.append(tmp_data)

		obj_result['result'] = 0
		obj_result['presets'] = data
		data_json = json.dumps(obj_result)
		return data_json

	def ptz_SetPreset(self, name):
		syslog.syslog('ptz_SetPreset...')
		request = self.ptz.create_type('SetPreset')
		request.ProfileToken = self.media_profile._token
		request.PresetName = name
		token = None
		try:
			token = self.ptz.SetPreset(request)
		except ONVIFError,e:
			token = None
		else:
			return token
		return token

	def ptz_GotoPreset(self, token):
		syslog.syslog('ptz_GotoPreset...')
		request = self.ptz.create_type('GotoPreset')
		request.ProfileToken = self.media_profile._token
		request.PresetToken = token
		preset = self.ptz.GotoPreset(request)

	def ptz_RemovePreset(self, token):
		syslog.syslog('ptz_RemovePreset...')
		request = self.ptz.create_type('RemovePreset')
		request.ProfileToken = self.media_profile._token
		request.PresetToken = token
		preset = ptz.RemovePreset(request)

	def ptz_GotoHomePosition(self):
		syslog.syslog('ptz_GotoHomePosition...')
		request = self.ptz.create_type('GotoHomePosition')
		request.ProfileToken = self.media_profile._token
		preset = self.ptz.GotoHomePosition(request)

	def ptz_SetHomePosition(self):
		syslog.syslog('ptz_SetHomePosition...')
		request = self.ptz.create_type('SetHomePosition')
		request.ProfileToken = self.media_profile._token
		preset = self.ptz.SetHomePosition(request)

	def perform_AbsoluteMove(self, request, timeout):
		# Start continuous move
		self.ptz.RelativeMove(request)
		# Wait a certain time
		sleep(timeout)
		# Stop continuous move
		self.ptz.Stop({'ProfileToken': request.ProfileToken})

	def move_AbsoluteMove(self, x, y, z=0, timeout=1):
		syslog.syslog("move_AbsoluteMove...")
		request = self.ptz.create_type('AbsoluteMove')
		request.ProfileToken = self.media_profile._token
		request.Position.PanTilt._x = x
		request.Position.PanTilt._y = y
		request.Position.Zoom._x = z
		self.perform_RelativeMove(request, timeout)
	def ipc_CheckPtz(self):
		if self.ptz_error_info != 0 or self.ptz == 0:
			return 1
		return 0
	def protocol_encode(self, json_str):
		err_code=0
		#parse
		obj=json.loads(json_str)
		obj_result={}
		#encode
		identifier = obj['identifier']
		syslog.syslog("python ipcamera protocol_encode in...")
		if self.media_profile == 0:
			err_code = 1
			obj_result['result'] = err_code
			obj_result['error_info'] = self.onvif_error_info
			json_str=json.dumps(obj_result)
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'RelativeMove':
			err_code = self.ipc_CheckPtz()
			syslog.syslog("err_code %d ptz_error_info %s self.ptz %s" %(err_code,type(self.ptz_error_info), type(self.ptz)))
			if err_code != 0:
				obj_result['error_info'] = self.ptz_error_info
			else:
				self.move_RelativeMove(obj['x'], obj['y'])
			obj_result['result'] = err_code
			json_str=json.dumps(obj_result)
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'GetStreamUri':
			json_str = self.ipc_GetStreamUri()
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'GetPresets':
			err_code = self.ipc_CheckPtz()
			if err_code != 0:
				obj_result['error_info'] = self.ptz_error_info
				obj_result['result'] = err_code
				json_str=json.dumps(obj_result)
			else:
				json_str = self.ptz_GetPresets()
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'SetPreset':
			err_code = self.ipc_CheckPtz()
			if err_code != 0:
				obj_result['error_info'] = self.ptz_error_info
			else:
				preset_token = self.ptz_SetPreset(obj['preset_name'])
				if preset_token == None:
					err_code = 1
				else:
					obj_result['preset_token'] = preset_token
			obj_result['result'] = err_code
			json_str=json.dumps(obj_result)
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'GotoPreset':
			err_code = self.ipc_CheckPtz()
			if err_code != 0:
				obj_result['error_info'] = self.ptz_error_info
			else:
				preset_token = self.ptz_GotoPreset(obj['preset_token'])
			obj_result['result'] = err_code
			json_str=json.dumps(obj_result)
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'RemovePreset':
			err_code = self.ipc_CheckPtz()
			if err_code != 0:
				obj_result['error_info'] = self.ptz_error_info
			else:
				preset_token = self.ptz_RemovePreset(obj['preset_token'])
			obj_result['result'] = err_code
			json_str=json.dumps(obj_result)
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'GotoHomePosition':
			err_code = self.ipc_CheckPtz()
			if err_code != 0:
				obj_result['error_info'] = self.ptz_error_info
			else:
				preset_token = self.ptz_GotoHomePosition()
			obj_result['result'] = err_code
			json_str=json.dumps(obj_result)
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'SetHomePosition':
			err_code = self.ipc_CheckPtz()
			if err_code != 0:
				obj_result['error_info'] = self.ptz_error_info
			else:
				preset_token = self.ptz_SetHomePosition()
			obj_result['result'] = err_code
			json_str=json.dumps(obj_result)
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		elif identifier == 'ContinuousMove':
			err_code = self.ipc_CheckPtz()
			if err_code != 0:
				obj_result['error_info'] = self.ptz_error_info
			else:
				self.move_ContinuousMove(obj['x'], obj['y'])
			obj_result['result'] = err_code
			json_str=json.dumps(obj_result)
			syslog.syslog("json_str:%s" %json_str)
			return json_str
		else:
			syslog.syslog("ERROR can't find cmd")

		syslog.syslog("python ipcamera protocol_encode out...")
		obj_result['result'] = 1
		json_str=json.dumps(obj_result)
		return json_str


class MyEncoder(json.JSONEncoder):

    def default(self, obj):
        """
        只要检查到了是bytes类型的数据就把它转为str类型
        :param obj:
        :return:
        """
        if isinstance(obj, bytes):
            return str(obj, encoding='utf-8')
        return json.JSONEncoder.default(self, obj)
		
	
class IPCConfig:
	def __init__(self, file_name, list_name, mode):
		self.file_name = file_name
		self.list_name = list_name
		self.node_cnt = 0
		self.node_json = {}
		
		self.file_object = open(file_name, mode)
		self.file_data = self.file_object.read()
		syslog.syslog(self.file_data)
		if self.file_data is not None and len(self.file_data) > 0:
			self.node_json = json.loads(self.file_data)
			self.node_cnt = len(self.node_json[self.list_name])
			syslog.syslog("self.node_cnt:%d" % self.node_cnt)
		
	def get_node_by_sn(self, sn):
		for node in self.node_json[self.list_name]:
			if node["sn"] == sn:
				return node
	
	def get_node_by_index(self, index):
		syslog.syslog("--sn %s" % self.node_json[self.list_name][index]["sn"])
		return self.node_json[self.list_name][index]
	
	def delete_node_by_index(self, index):
		del self.node_json[self.list_name][index]
		self.node_cnt = len(self.node_json[self.list_name])
		self.file_data = json.dumps(self.node_json)
		tmp_object = open(self.file_name, "w")
		#self.file_object.seek(0, 0)
		tmp_object.write(self.file_data)
		tmp_object.close()
		
	def add_update_node(self, node):		
		syslog.syslog("sn:%s" %(node["sn"]))
		find = 0
		if len(self.node_json) > 0:
			for index in range(len(self.node_json[self.list_name])):
				syslog.syslog("index:%d" %(index))
				syslog.syslog("sn:%s %s" %(node["sn"],self.node_json[self.list_name][index]["sn"]))
				if self.node_json[self.list_name][index]["sn"] == node["sn"]:
					find = 1
					syslog.syslog("self.file_data:%s" %self.file_data)
					del self.node_json[self.list_name][index]
					self.node_json[self.list_name].append(node)
					self.file_data = json.dumps(self.node_json)
					syslog.syslog("self.file_data:%s" %self.file_data)
					tmp_object = open(self.file_name, "w")
					#self.file_object.seek(0, 0)
					tmp_object.write(self.file_data)
					tmp_object.close()
					syslog.syslog("add ok...")
		
		if find == 0:
			if len(self.node_json) < 1:
				self.node_json[self.list_name] = []
			self.node_json[self.list_name].append(node)
			self.node_cnt = len(self.node_json[self.list_name])
			
			self.file_data = json.dumps(self.node_json)
			tmp_object = open(self.file_name, "w")
			#self.file_object.seek(0, 0)
			tmp_object.write(self.file_data)
			tmp_object.close()
		
	def update_node_config(self, node):
		syslog.syslog("sn:%s" %(node["sn"]))
		for index in range(len(self.node_json[self.list_name])):
			syslog.syslog("index:%d" %(index))
			syslog.syslog("sn:%s %s" %(node["sn"],self.node_json[self.list_name][index]["sn"]))
			if self.node_json[self.list_name][index]["sn"] == node["sn"]:
				syslog.syslog("self.file_data:%s" %self.file_data)
				del self.node_json[self.list_name][index]
				self.node_json[self.list_name].append(node)
				self.file_data = json.dumps(self.node_json)
				syslog.syslog("self.file_data:%s" %self.file_data)
				tmp_object = open(self.file_name, "w")
				#self.file_object.seek(0, 0)
				tmp_object.write(self.file_data)
				tmp_object.close()
				

class MQTTClient:
	def __init__(self, host, port, qos, timeout=60, user=None, passwd=None):
		self.host = host
		self.port = port
		self.qos = qos
		self.timeout = timeout
		#self.ser = ser

		self.mqtt_client = mqtt.Client()
		if user is not None and passwd is not None:
			self.mqtt_client.username_pw_set(user, passwd)
		self.mqtt_client.on_message = self.on_message
		self.mqtt_client.on_disconnect = self.on_disconnect
		self.mqtt_client.on_connect = self.on_connect
		self.mqtt_client.connect(self.host, self.port, self.timeout)

	def on_message(self, client, userdata, msg):
		payload = msg.payload.decode().strip().replace('\\n', '').replace('\\t', '')
		mqtt_recv_msg(msg.topic.decode(), payload)

	def on_disconnect(self, client, userdata, rc):
		syslog.syslog("disconnect with result code: " + str(rc))
		self.mqtt_client.reconnect()
	
	def on_connect(self, client, userdata, flags, rc):
		syslog.syslog("connect with result code: " + str(rc))
		sub_mqtt_topc(self.mqtt_client)

	def subscribe(self, topic):
		self.mqtt_client.subscribe(topic, self.qos)
		syslog.syslog("subscribe %s" % topic)

	def unsubscribe(self, topic):
		self.mqtt_client.unsubscribe(topic)
		syslog.syslog('unsubscribe %s' % topic)

	def publish(self, topic, blob):
		self.mqtt_client.publish(topic, blob)

	def loop_start(self):
		if self.mqtt_client is not None:
			self.mqtt_client.loop_forever()

	
def init_ipcamera(ipc_object, ipc_json):
	#初始化IPC实例
	if ipc_object != None:
		ipc_object["ipc_client"].ipc_InitEnv(host=ipc_json["ip_addr"], port=ipc_json["port"], user=ipc_json["user"], password=ipc_json["password"])
		ipc_object["user"] = ipc_json["user"]
		ipc_object["password"] = ipc_json["password"]
		ipc_object["status_time"] = 0
		
		if ipc_object["ipc_client"].invalid == 0:
			raw_rtspUrl = ipc_object["ipc_client"].protocol_encode("{\"identifier\":\"GetStreamUri\"}")
			ipc_object["rtspUrl"],ipc_object["wan_rtspUrl"] = generate_rtsp_url(raw_rtspUrl, ipc_object["ip_addr"], ipc_object["user"], ipc_object["password"])
			ipc_object["online"] = True
			syslog.syslog("IPCamera ReInit rtsp %s Connect OK..." %ipc_object["rtspUrl"])
		else:
			syslog.syslog("IPCamera Connect invalid:%d..." %ipc_object["ipc_client"].invalid)
		
		return ipc["ipc_client"].invalid
	else:
		ipc = {}
		if "nvrAddr" in ipc_json:
			ipc["ipc_client"] = IPCamera(host=ipc_json["ip_addr"], port=ipc_json["port"], user=ipc_json["user"], password=ipc_json["password"], nvrAddr=ipc_json["nvrAddr"])
		else:
			ipc["ipc_client"] = IPCamera(host=ipc_json["ip_addr"], port=ipc_json["port"], user=ipc_json["user"], password=ipc_json["password"])
		syslog.syslog("invalid:%d" %(ipc["ipc_client"].invalid))
		if ipc["ipc_client"] != None:
			ipc["sn"] = ipc_json["sn"]
			ipc["ip_addr"] = ipc_json["ip_addr"]
			ipc["port"] = ipc_json["port"]
			ipc["user"] = ipc_json["user"]
			ipc["password"] = ipc_json["password"]
			ipc["online"] = False
			ipc["status_time"] = 0
			if "nvrUser" in ipc_json:
				ipc["nvrUser"] = ipc_json["nvrUser"]
				ipc["nvrPassword"] = ipc_json["nvrPassword"]
				ipc["nvrAddr"] = ipc_json["nvrAddr"]
				ipc["nvrChannel"] = ipc_json["nvrChannel"]
			if ipc["ipc_client"].invalid == 0:
				raw_rtspUrl = ipc["ipc_client"].protocol_encode("{\"identifier\":\"GetStreamUri\"}")
				ipc["rtspUrl"],ipc["wan_rtspUrl"] = generate_rtsp_url(raw_rtspUrl, ipc["ip_addr"], ipc["user"], ipc["password"])
				ipc["online"] = True
				syslog.syslog("IPCamera rtsp %s Connect OK..." %ipc["rtspUrl"])
			else:
				syslog.syslog("IPCamera Connect invalid:%d..." %ipc["ipc_client"].invalid)
				
			ipc_objects.append(ipc)
			
			return ipc["ipc_client"].invalid
		else:
			return 1

#数据上报
def data_report(data, type, result_data):
	send_data = {}
	send_data["sn"] = data["sn"]
	send_data["identifier"] = data["identifier"]
	send_data["time"] = int(time.time())
	send_data["mi"] = data["mi"]
	send_data["port"] = "TCP_CLIENT"
	send_data["tag_node"] = result_data
	
	send_data["data_type"] = type
	send_json = json.dumps(send_data, cls=MyEncoder, indent=4, ensure_ascii=False)
	if type == 0:
		publish_topic = "ipc/" + GW_SN + "/TCP_CLIENT/device/" + data["sn"] + "/data/property/" + data["identifier"]
	elif type == 1:
		publish_topic = "ipc/" + GW_SN + "/TCP_CLIENT/device/" + data["sn"] + "/data/event/" + data["identifier"]
	elif type == 2:
		publish_topic = "ipc/" + GW_SN + "/TCP_CLIENT/device/" + data["sn"] + "/data/service/" + data["identifier"]
	
	topic_payload = {}
	topic_payload["topic"] = publish_topic
	topic_payload["payload"] = send_json
	data_list.append(topic_payload)
	
#数据上报
def status_report(ipc_obj, now_time):
	ipc_status = {}
	ipc_status["status"] = []
	status = {}
	status["sn"] = ipc_obj["sn"]
	status["online"] = ipc_obj["online"]
	status["last_rcv"] = now_time
	status["login_time"] = 0
	ipc_status["status"].append(status)
	
	send_json = json.dumps(ipc_status, cls=MyEncoder, indent=4, ensure_ascii=False)
	publish_topic = "ipc/" + GW_SN + "/TCP_CLIENT/Evt_NodesStatus"
	
	topic_payload = {}
	topic_payload["topic"] = publish_topic
	topic_payload["payload"] = send_json
	data_list.append(topic_payload)

#MQTT订阅
def sub_mqtt_topc(mqtt_client):
	mqtt_client.subscribe(mqtt_sub_topic)
	syslog.syslog("ipcamera sub_mqtt_topc %s" % mqtt_sub_topic)

	
#检查IPC是否在线
def ipcamera_online_check(ip_addr):
	ping_str = "ping {0} -c 3".format(ip_addr)
	find_str = "bytes from {0}".format(ip_addr)
	f = os.popen(ping_str, "r")

	ping_status = f.read()
	if ping_status.find(find_str) > 0:
		syslog.syslog("ping %s result 1" %(ip_addr))
		return 1
	else:
		syslog.syslog("ping %s result 0" %(ip_addr))
		return 0

def MQTT_listen(mqtt_client):
    mqtt_client.loop_start()

#IPC事件处理消息处理	
def event_msg_ctrl(ip_addr, event_info):
	data = {}
	syslog.syslog("==ip_addr %s event_info:%s" %(ip_addr,event_info))
	for index in range(len(ipc_objects)):
		if ip_addr == ipc_objects[index]["ip_addr"]:
			data["mi"] = 0
			data["sn"] = ipc_objects[index]["sn"]
			data["identifier"] = "IpcAlarm"
			result_data = json.dumps(event_info)
			data_report(data, 1, result_data)
					
#mqtt消息处理	
def ipc_msg_ctrl(mqtt_client):
	status_time_5m = 0
	while True:
		find = 0
		now_time = int(time.time())
		#syslog.syslog("==node_cnt %d ipc_cnt:%d" %(node_config.node_cnt,len(ipc_objects)))
		for msg_index in range(len(mqtt_msg_list)):
			topic = mqtt_msg_list[msg_index]["topic"]
			payload = mqtt_msg_list[msg_index]["payload"]
			syslog.syslog("==len(mqtt_msg_list):%d" %(len(mqtt_msg_list)))
			syslog.syslog("ipc_msg_ctrl topic:%s" %topic)
			syslog.syslog("ipc_msg_ctrl payload:%s" %payload)
			
			try:
				tmp_data = json.loads(payload)
				data = json.loads(tmp_data["data_b64"])
				result = 0
			except Exception,err:
				syslog.syslog("error data_b64 json.loads:%s" %tmp_data["data_b64"])
				mqtt_msg_list.pop(msg_index)
				break;
				
			for index in range(len(ipc_objects)):
				if data["sn"] == ipc_objects[index]["sn"]:
					find = 1
					syslog.syslog("find connected sn:%s" %(ipc_objects[index]["sn"]))
					#IPC初始化
					if data["identifier"] == "InitIPCamera":
						result_data = {}
						#更新用户名密码
						if ipc_objects[index]["ipc_client"].invalid == 1 or ipc_objects[index]["online"] == False:
							#初始化
							if ipc_objects[index]["ipc_client"].onvif_error_info.find("Host is unreachable") > 0 and ipcamera_online_check(ipc_objects[index]["ip_addr"]) == 1:
								syslog.syslog("sn:%s init_ipcamera" %(ipc_objects[index]["sn"]))
								result = init_ipcamera(ipc_objects[index], ipc_objects[index])
							else:
								result = 1
								
							if result == 1:
								result_data['error_info'] = ipc_objects[index]["ipc_client"].onvif_error_info			
						else:
							#初始化成功，直接返回成功
							result = 0
						result_data["result"] = result				
						result_data = json.dumps(result_data)
					elif ipc_objects[index]["ipc_client"].invalid == 1:
						result_data = {}
						result_data["result"] = 1
						result_data['error_info'] = ipc_objects[index]["ipc_client"].onvif_error_info		
						result_data = json.dumps(result_data)
						#待验证
						if ipc_objects[index]["ipc_client"].onvif_error_info.find("Host is unreachable") > 0 and ipcamera_online_check(ipc_objects[index]["ip_addr"]) == 1:							
							syslog.syslog("sn:%s restart ipcamera sleep 20" %(ipc_objects[index]["sn"]))
							sleep(20)
							os.system("/etc/init.d/ipcamera restart &")
							#result = init_ipcamera(ipc_objects[index], ipc_objects[index])
					#开始推流
					elif data["identifier"] == "PushVideoStreaming":
						#检查是否正在推流
						push = get_push_video_status(ipc_objects[index]["ip_addr"])
						#没有推流，再开户推流
						if push == 0:
							push_video_streaming(ipc_objects[index]["rtspUrl"], data["serverUrl"])
							sleep(1)
							push = get_push_video_status(ipc_objects[index]["ip_addr"])
						
						if push == 0:
							result = 1
						else:
							result = 0
							ipc_objects[index]["push_time"] = now_time
							syslog.syslog("push_time startTime %d..." %ipc_objects[index]["push_time"])
						#组回应包
						result_data = {}
						result_data["result"] = result			
						result_data = json.dumps(result_data)
					#停止推流
					elif data["identifier"] == "StopVideoStreaming":
						#检查是否正在推流
						ffmpeg_pid = get_push_video_status(ipc_objects[index]["ip_addr"])
						ipc_objects[index]["push_time"] =  0
						#停止推流
						if ffmpeg_pid != 0:
							stop_video_streaming(ffmpeg_pid)
						#组回应包
						result_data = {}
						result_data["result"] = 0				
						result_data = json.dumps(result_data)
					#获取rtspUrl
					elif data["identifier"] == "GetStreamUri":
						result_data = {}
						result_data["rtspUrl"] = ipc_objects[index]["wan_rtspUrl"]
						result_data["result"] = 0
						
						result_data = json.dumps(result_data)
					#开始推NVR回放流
					elif data["identifier"] == "PushNvrReplayStreaming":
						#生成端口映射
						if get_port_mapping(554, ipc_objects[index]["nvrAddr"]) == 0:
							generate_port_mapping(555, ipc_objects[index]["nvrAddr"], 554)
						#组NVR rtspUrl
						#rtsp://admin:a12345678@10.3.1.46:554/Streaming/tracks/101?starttime=20200721t103000z&endtime=20200721t104000z
						#检查是否正在推流
						push = get_push_video_status(ipc_objects[index]["nvrAddr"])
						
						nvrRtspUrl = "rtsp://{0}:{1}@{2}:554/Streaming/tracks/10{3}?starttime={4}z&endtime={5}z".format(ipc_objects[index]["nvrUser"],ipc_objects[index]["nvrPassword"],ipc_objects[index]["nvrAddr"],ipc_objects[index]["nvrChannel"],data["startTime"].replace(" ", "t"),data["endTime"].replace(" ", "t"))
						#没有推流，再开户推流
						if push == 0:
							push_video_streaming(nvrRtspUrl, data["serverUrl"])
						#组回应包
						result_data = {}
						result_data["result"] = 0				
						result_data = json.dumps(result_data)
					#停止推NVR回放流
					elif data["identifier"] == "StopNvrReplayStreaming":
						#检查是否正在推流
						ffmpeg_pid = get_push_video_status(ipc_objects[index]["nvrAddr"])
						#停止推流
						if ffmpeg_pid != 0:
							stop_video_streaming(ffmpeg_pid)
						#组回应包
						result_data = {}
						result_data["result"] = 0				
						result_data = json.dumps(result_data)
					#执行相应摄像机控制操作
					else:
						result_data = ipc_objects[index]["ipc_client"].protocol_encode(tmp_data["data_b64"])
						
					#上位机消息应答	
					data_report(data, 0, result_data)
					data_report(data, 2, result_data)
					break
			mqtt_msg_list.pop(msg_index)
			break;
			
		if find == 0:
			sleep(1)
		
		for index in range(len(ipc_objects)):
			if "push_time" in ipc_objects[index] and ipc_objects[index]["push_time"] > 0 and now_time - ipc_objects[index]["push_time"] >= 300:
				#检查是否正在推流
				ffmpeg_pid = get_push_video_status(ipc_objects[index]["ip_addr"])
				#停止推流
				if ffmpeg_pid != 0:
					syslog.syslog("StopVideoStreaming Auto startTime %d..." %ipc_objects[index]["push_time"])
					stop_video_streaming(ffmpeg_pid)
					
				ipc_objects[index]["push_time"] =  0
			#5分钟检测一下设备状态
			if now_time - status_time_5m > 300 and ipc_objects[index]["online"] == True:
				status_time_5m = now_time
				if ipcamera_online_check(ipc_objects[index]["ip_addr"]) == 0:
					ipc_objects[index]["online"] = False
					status_report(ipc_objects[index], now_time)
			#1小时更新一下设备状态
			if now_time - ipc_objects[index]["status_time"] > 3600 or ipc_objects[index]["status_time"] == 0:
				ipc_objects[index]["status_time"] = now_time
				status_report(ipc_objects[index], now_time)
				
			

#接收MQTT消息，加入到mqtt消息队列	
def mqtt_recv_msg(topic, payload):
	#syslog.syslog("topic:%s payload:%s" %(topic, payload))
	mqtt_msg = {}
	mqtt_msg["topic"] = topic
	mqtt_msg["payload"] = payload
	mqtt_msg_list.append(mqtt_msg)
	return

#生成端口映射
def generate_port_mapping(out_port, ip_addr, port):
	mapping = "uci add firewall redirect;uci set firewall.@redirect[-1].src=wan;uci set firewall.@redirect[-1].src_dport={0};uci set firewall.@redirect[-1].dest_ip={1};uci set firewall.@redirect[-1].dest=lan;uci set firewall.@redirect[-1].dest_port={2};uci set firewall.@redirect[-1].proto=tcp;uci commit firewall;/etc/init.d/firewall restart;".format(out_port, ip_addr, port)
	f = os.popen(mapping, "r")
	d = f.read()
	f.close()
	
	if d == None:
		syslog.syslog("generate_port_mapping 0")
		return 0
	else:
		syslog.syslog("generate_port_mapping 1")
		return 1

#获取当前端口是否已映射		
def get_port_mapping(port, ip_addr):
	mapping = "grep -A 5 -B 5 \"src_dport '{0}'\" /etc/config/firewall | grep \"dest_ip '{1}'\"".format(port, ip_addr)
	f = os.popen(mapping, "r")
	d = f.read()
	f.close()
	
	if d == None:
		syslog.syslog("get_port_mapping 0")
		return 0
	else:
		syslog.syslog("get_port_mapping 1")
		return 1

#生成rtsp url		
def generate_rtsp_url(raw_rtspUrl, ip_addr, user, password):
	#raw_rtspUrl = "{\"streamCnt\": 3, \"rtspUrl\": \"rtsp://172.16.254.102:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif\", \"result\": 0}"
	data = json.loads(raw_rtspUrl)
	if data["rtspUrl"] == None:
		return None,None
		
	#获取wan ip address
	f = os.popen(r"ubus call network.interface.wan status | grep \"address\" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}';", "r")
	wan_ip = f.read()
	f.close()
	
	syslog.syslog("raw_rtspUrl:%s wan_ip:%s" %(data["rtspUrl"],wan_ip))
	
	#rtsp = user + ":" + password + "@" + wan_ip[0:-1]
	rtsp = user + ":" + password + "@" + ip_addr
	rtspUrl = data["rtspUrl"].replace(ip_addr,rtsp)
	
	subtype_tmp = "subtype={0}".format(data["streamCnt"]-1)
	Hik_subtype = "/10{0}?".format(data["streamCnt"])
	
	rtspUrl = rtspUrl.replace("subtype=0", subtype_tmp)
	rtspUrl = rtspUrl.replace("/101?", Hik_subtype)
	#生成端口映射
	if get_port_mapping(554, ip_addr) == 0:
		generate_port_mapping(554, ip_addr, 554)
		
	syslog.syslog("rtspUrl:%s" %rtspUrl)
	return rtspUrl,rtspUrl.replace(ip_addr, wan_ip[0:-1])

#换取当前推流状态,返回pid
def get_push_video_pid(ip_addr, cmd):
	ffmpeg_status = cmd
	f = os.popen(ffmpeg_status, "r")

	ffmpeg_start = f.read()
	#try:
	sh_index = ffmpeg_start.find(cmd)
	if sh_index >= 0 and sh_index < 30:
		syslog.syslog("strip cmd:%s" %(cmd))
		ffmpeg_start = ffmpeg_start[sh_index+len(cmd)+1:]
		ffmpeg_start.strip()
	ip_index = ffmpeg_start.find(ip_addr)
	syslog.syslog("cmd:%s ip_index:%d %s" %(cmd, ip_index, ffmpeg_start))
	pid_index = -1
	if ip_index > 100:
		tmp_string = ffmpeg_start[ip_index-100:]
		tmp_index = tmp_string.find("logger -t ffmpeg") + len("logger -t ffmpeg")
		ffmpeg_start = tmp_string[tmp_index+1:]
		syslog.syslog("ffmpeg_start:%s" %(ffmpeg_start))
		
	pid_index = ffmpeg_start.find("ffmpeg -rtsp_transport")
	if ffmpeg_start.find(ip_addr) < 0 or pid_index < 0:
		syslog.syslog("get_push_video_status 0")
		return 0
	else:
		syslog.syslog("pid_index:%d" %pid_index)
		ffmpeg_pid = int(ffmpeg_start[0:(pid_index-1)])
		syslog.syslog("get_push_video_status 1 ffmpeg_pid:%d" %ffmpeg_pid)
		return ffmpeg_pid
			
	#except TypeError,err:
		#syslog.syslog("err %s " %err)
		
#换取当前推流状态,返回pid
def get_push_video_status(ip_addr):
	ffmpeg_pid = get_push_video_pid(ip_addr, pgrep_ffmpeg_afl)
	if ffmpeg_pid == 0:
		ffmpeg_pid = get_push_video_pid(ip_addr, pgrep_ffmpeg_fl)
		
	return ffmpeg_pid
		
#停止推流	
def stop_video_streaming(ffmpeg_pid):
	stop_video = "kill -9 {0}".format(ffmpeg_pid)
	syslog.syslog("push:%s" %stop_video)
	os.system(stop_video)
	return 1
	
#推流	
def push_video_streaming(rtsp_url, server_url):
	push_video = "{0} -i \"{1}\" -vcodec copy -acodec copy -f flv \"{2}\" 2>&1 | logger -t 'ffmpeg' & ".format(ffmpeg_str, rtsp_url, server_url)
	syslog.syslog("push_video_streaming:%s" %push_video)
	os.system(push_video)
	return 0

def get_board_name():
	global ffmpeg_str
	file_object = open(BOARD_NAME_PATH, "r+")
	file_data = file_object.read()
	sn_index = file_data.find("WOOLINK-MT7628-128M-32M")
	syslog.syslog("file_data:%s sn_index:%d" %(file_data,sn_index))
	if sn_index >= 0:
		ffmpeg_str = ffmpeg_str + " -rtbufsize 512000"
		syslog.syslog("ffmpeg_str:%s" %ffmpeg_str)		
	file_object.close()

def get_sn():
	global GW_SN
	file_object = open(FAC_INI_FILE, "r+")
	file_data = file_object.read()
	sn_index = file_data.find("sn")
	if sn_index > 0:
		sn_tmp = file_data[sn_index:]
		sn_list = sn_tmp.split('=')
		GW_SN = sn_list[-1].strip()
		syslog.syslog("GW_SN:%s" %GW_SN)
	file_object.close()
	
def main_loop():
	syslog.syslog("*******************start ipcamera python*******************")	
	global ipc_config,node_config
	#加载IPC配置文件
	get_sn()
	get_board_name()
	#加载节点配置文件
	node_config = IPCConfig(NODE_CONFIG_NAME, "nodes_cfg", "r")
	
	#ipc消息处理线程
	ipc_msg_thread = threading.Thread(target=ipc_msg_ctrl, args=(None,))
	ipc_msg_thread.setDaemon(True)
	ipc_msg_thread.start()
	#杀掉所有ffmpeg	
	os.system("killall -9 ffmpeg")
	
	for node_index in range(node_config.node_cnt):
			node_json = node_config.get_node_by_index(node_index)
			if node_json["connect_port"] == "TCP_CLIENT" and "ext_data" in node_json:
				ext_data=json.loads(node_json["ext_data"])
				if "user" in ext_data and "password" in ext_data:
					ipc_json = {}
					ipc_json["sn"] = node_json["sn"]
					ipc_json["ip_addr"] = node_json["tcp_ip_addr"]
					ipc_json["port"] = int(node_json["tcp_port"])
					ipc_json["user"] = ext_data["user"]
					ipc_json["password"] = ext_data["password"]
					if "nvrUser" in ext_data:
						ipc_json["nvrUser"] = ext_data["nvrUser"]
						ipc_json["nvrPassword"] = ext_data["nvrPassword"]
						ipc_json["nvrAddr"] = ext_data["nvrAddr"]
						ipc_json["nvrChannel"] = ext_data["nvrChannel"]
						
					ipc_config.append(ipc_json)
					#初始化IPC实例
					init_ipcamera(None, ipc_json)
	
	#建立MQTT连接
	mqtt_client = MQTTClient(MQTT_BROKER, MQTT_PORT, MQTT_QoS, timeout=MQTT_CONN_TIMEOUT, user=MQTT_USER,
						 passwd=MQTT_PASSWD)
	#topic = "ipc/+/TCP_CLIENT/device/+/data/Set_Rglt_Raw"
	#topic = "G/" + GW_SN + "/Rsp_ServiceData"
	#订阅
	#mqtt_client.subscribe(topic)
	#MQTT线程
	mqtt_thread = threading.Thread(target=MQTT_listen, args=(mqtt_client,))
	mqtt_thread.setDaemon(True)
	mqtt_thread.start()
	
	#发布MQTT消息
	while True:
		for index in range(len(data_list)):
			syslog.syslog("publish topic:%s payload:%s" %(data_list[index]["topic"],data_list[index]["payload"]))
			mqtt_client.publish(data_list[index]["topic"], data_list[index]["payload"])
			data_list.pop(index)
			break;
		sleep(1)
	


if __name__ == '__main__':
    main_loop()
    syslog.syslog("finished")

