Browse Source

Merge branch 'test' of http://192.168.136.99:3000/servers/ASJServer into test

lang 3 years ago
parent
commit
be78412b30
47 changed files with 5191 additions and 718 deletions
  1. 189 27
      AdminController/DeviceManagementController.py
  2. 5 28
      AdminController/LogManagementController.py
  3. 5 3
      AdminController/SerialManageController.py
  4. 13 5
      AdminController/ServeManagementController.py
  5. 3 0
      Ansjer/cn_config/config_formal.py
  6. 3 0
      Ansjer/cn_config/config_test.py
  7. 36 2
      Ansjer/config.py
  8. 3 0
      Ansjer/eur_config/config_formal.py
  9. 3 0
      Ansjer/local_config/config_local.py
  10. 4 4
      Ansjer/local_config/local_settings.py
  11. 21 0
      Ansjer/server_urls/loocam_url.py
  12. 15 0
      Ansjer/server_urls/unicom_url.py
  13. 16 6
      Ansjer/urls.py
  14. 3 0
      Ansjer/us_config/config_formal.py
  15. 204 116
      Controller/AiController.py
  16. 62 10
      Controller/AppSetController.py
  17. 31 190
      Controller/CloudStorage.py
  18. 59 38
      Controller/CouponController.py
  19. 21 6
      Controller/DetectControllerV2.py
  20. 31 31
      Controller/DeviceConfirmRegion.py
  21. 23 1
      Controller/EquipmentInfo.py
  22. 4 1
      Controller/EquipmentManagerV2.py
  23. 24 54
      Controller/IotCoreController.py
  24. 119 0
      Controller/MessagePush/EquipmentMessagePush.py
  25. 3 1
      Controller/OrderContrller.py
  26. 5 1
      Controller/PaymentCycle.py
  27. 948 0
      Controller/SensorGateway/EquipmentFamilyController.py
  28. 263 0
      Controller/SensorGateway/GatewayDeviceController.py
  29. 551 0
      Controller/SensorGateway/GatewayFamilyMemberController.py
  30. 253 0
      Controller/SensorGateway/GatewayFamilyRoomController.py
  31. 0 0
      Controller/SensorGateway/SensorGatewayController.py
  32. 362 0
      Controller/SensorGateway/SubDeviceController.py
  33. 41 43
      Controller/SerialNumberController.py
  34. 74 35
      Controller/TestApi.py
  35. 264 0
      Controller/UnicomCombo/UnicomComboController.py
  36. 1 1
      Controller/UserBrandController.py
  37. 471 71
      Model/models.py
  38. 8 16
      Object/IOTCore/IotObject.py
  39. 3 1
      Object/ResponseObject.py
  40. 256 0
      Object/UnicomObject.py
  41. 237 0
      Object/utils/SM3Util.py
  42. 216 0
      Object/utils/SymmetricCryptoUtil.py
  43. 66 22
      Service/CommonService.py
  44. 90 4
      Service/EquipmentInfoService.py
  45. 1 1
      Service/MiscellService.py
  46. 181 0
      Service/PayService.py
  47. BIN
      requirements.txt

+ 189 - 27
AdminController/DeviceManagementController.py

@@ -5,18 +5,18 @@ import time
 
 
 import oss2
 import oss2
 from django.db import transaction
 from django.db import transaction
-from django.db.models import Q
+from django.db.models import Q, F
+from django.views.generic.base import View
 
 
 from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET
 from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET
+from Model.models import Device_Info, UidSetModel, LogModel, UID_Bucket, Unused_Uid_Meal, Order_Model, StsCrdModel, \
+    VodHlsModel, ExperienceContextModel, DeviceTypeModel, Equipment_Info, UidUserModel, ExperienceAiModel, AiService, \
+    AppBundle, App_Info, AppDeviceType, DeviceNameLanguage
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
-from django.views.generic.base import View
-
+from Service.CommonService import CommonService
 from Service.EquipmentInfoService import EquipmentInfoService
 from Service.EquipmentInfoService import EquipmentInfoService
 from Service.ModelService import ModelService
 from Service.ModelService import ModelService
-from Service.CommonService import CommonService
-from Model.models import Device_Info, UidSetModel, LogModel, UID_Bucket, Unused_Uid_Meal, Order_Model, StsCrdModel, \
-    VodHlsModel, ExperienceContextModel, DeviceTypeModel, Equipment_Info, UidUserModel
 
 
 
 
 class DeviceManagement(View):
 class DeviceManagement(View):
@@ -35,8 +35,11 @@ class DeviceManagement(View):
         response = ResponseObject(language, 'pc')
         response = ResponseObject(language, 'pc')
         if operation == 'addDeviceType':
         if operation == 'addDeviceType':
             return self.addDeviceType(request, request_dict, response)
             return self.addDeviceType(request, request_dict, response)
-        elif operation == 'delDeviceData':
-            return self.delDeviceData(request_dict, response)
+        elif operation == 'delDeviceData':  # 删除设备数据
+            return self.del_device_data(request_dict, response)
+        elif operation == 'getDeviceIcon':  # app获取设备图标
+            response = ResponseObject(language)
+            return self.get_device_icon(request_dict, response)
         else:
         else:
             tko = TokenObject(
             tko = TokenObject(
                 request.META.get('HTTP_AUTHORIZATION'),
                 request.META.get('HTTP_AUTHORIZATION'),
@@ -47,23 +50,33 @@ class DeviceManagement(View):
             userID = tko.userID
             userID = tko.userID
             if not userID:
             if not userID:
                 return response.json(444, 'userID')
                 return response.json(444, 'userID')
-            if operation == 'getDeviceInfoList':
-                return self.getDeviceInfoList(request_dict, response)
+            if operation == 'getDeviceInfoList':  # 获取设备信息数据
+                return self.get_device_info_list(request_dict, response)
             elif operation == 'deleteDevice':
             elif operation == 'deleteDevice':
                 return self.deleteDevice(request_dict, response)
                 return self.deleteDevice(request_dict, response)
-            elif operation == 'resetVod':
+            elif operation == 'resetVod':  # 重置云存
                 return self.resetVod(request, request_dict, response)
                 return self.resetVod(request, request_dict, response)
+            elif operation == 'resetAi':  # 重置AI
+                return self.reset_ai(request, request_dict, response)
             elif operation == 'resetPrimaryUser':
             elif operation == 'resetPrimaryUser':
                 return self.resetPrimaryUser(request, request_dict, response)
                 return self.resetPrimaryUser(request, request_dict, response)
             elif operation == 'getDeviceTypeList':
             elif operation == 'getDeviceTypeList':
                 return self.getDeviceTypeList(request_dict, response)
                 return self.getDeviceTypeList(request_dict, response)
             elif operation == 'deleteDeviceType':
             elif operation == 'deleteDeviceType':
                 return self.deleteDeviceType(request_dict, response)
                 return self.deleteDeviceType(request_dict, response)
+            elif operation == 'getAppDeviceTypeList':  # 获取app设备类型数据
+                return self.get_app_device_type_list(request_dict, response)
+            elif operation == 'getAppBundleIdList':  # 获取app包id数据
+                return self.get_app_bundle_id_list(response)
+            elif operation == 'editAppDeviceType':  # 编辑app设备类型数据
+                return self.edit_app_device_type(request_dict, response)
+            elif operation == 'deleteAppDeviceType':  # 删除app设备类型数据
+                return self.delete_app_device_type(request_dict, response)
             else:
             else:
                 return response.json(444, 'operation')
                 return response.json(444, 'operation')
 
 
-    # 获取设备信息数据
-    def getDeviceInfoList(self, request_dict, response):
+    @staticmethod
+    def get_device_info_list(request_dict, response):
         pageNo = request_dict.get('pageNo', None)
         pageNo = request_dict.get('pageNo', None)
         pageSize = request_dict.get('pageSize', None)
         pageSize = request_dict.get('pageSize', None)
         UID = request_dict.get('UID', None)
         UID = request_dict.get('UID', None)
@@ -78,7 +91,7 @@ class DeviceManagement(View):
         line = int(pageSize)
         line = int(pageSize)
 
 
         try:
         try:
-            if UID or serialNumber or NickName or username:    # 条件查询
+            if UID or serialNumber or NickName or username:  # 条件查询
                 if UID:
                 if UID:
                     device_info_qs = Device_Info.objects.filter(UID__contains=UID)
                     device_info_qs = Device_Info.objects.filter(UID__contains=UID)
                 if serialNumber:
                 if serialNumber:
@@ -89,11 +102,11 @@ class DeviceManagement(View):
                     device_info_qs = Device_Info.objects.filter(Q(userID__username__contains=username) |
                     device_info_qs = Device_Info.objects.filter(Q(userID__username__contains=username) |
                                                                 Q(userID__userEmail__contains=username) |
                                                                 Q(userID__userEmail__contains=username) |
                                                                 Q(userID__phone__contains=username))
                                                                 Q(userID__phone__contains=username))
-                total = len(device_info_qs)
+                total = device_info_qs.count()
                 if not total:
                 if not total:
                     return response.json(0, {'list': {}, 'total': 0})
                     return response.json(0, {'list': {}, 'total': 0})
                 device_info_qs = device_info_qs[(page - 1) * line:page * line]
                 device_info_qs = device_info_qs[(page - 1) * line:page * line]
-            else:   # 查询全部
+            else:  # 查询全部
                 total = Device_Info.objects.filter().count()
                 total = Device_Info.objects.filter().count()
                 device_info_qs = Device_Info.objects.filter()[(page - 1) * line:page * line]
                 device_info_qs = Device_Info.objects.filter()[(page - 1) * line:page * line]
                 if not device_info_qs.exists():
                 if not device_info_qs.exists():
@@ -106,17 +119,20 @@ class DeviceManagement(View):
                         # 设备的用户名和主用户
                         # 设备的用户名和主用户
                         username = ModelService.get_user_name(device_info_list["datas"][k]['fields']['userID'])
                         username = ModelService.get_user_name(device_info_list["datas"][k]['fields']['userID'])
                         device_info_list["datas"][k]['fields']['username'] = username
                         device_info_list["datas"][k]['fields']['username'] = username
-                        device_info_list["datas"][k]['fields']['vodPrimaryMaster'] = device_info_list["datas"][k]['fields']['vodPrimaryMaster']
+                        device_info_list["datas"][k]['fields']['vodPrimaryMaster'] = \
+                            device_info_list["datas"][k]['fields']['vodPrimaryMaster']
                         # 设备类型,是否支持Alexa和ip
                         # 设备类型,是否支持Alexa和ip
                         type = device_info_list["datas"][k]['fields']['Type']
                         type = device_info_list["datas"][k]['fields']['Type']
                         device_type_qs = DeviceTypeModel.objects.filter(type=type).values('name')
                         device_type_qs = DeviceTypeModel.objects.filter(type=type).values('name')
                         if device_type_qs.exists():
                         if device_type_qs.exists():
                             device_info_list["datas"][k]['fields']['Type'] = device_type_qs[0]['name']
                             device_info_list["datas"][k]['fields']['Type'] = device_type_qs[0]['name']
-                        uid_set_qs = UidSetModel.objects.filter(uid=device_info_list["datas"][k]['fields']['UID']).values('is_alexa', 'ip')
+                        uid_set_qs = UidSetModel.objects.filter(
+                            uid=device_info_list["datas"][k]['fields']['UID']).values('is_alexa', 'ip', 'version')
                         if uid_set_qs.exists():
                         if uid_set_qs.exists():
                             isAlexa = '是' if uid_set_qs[0]['is_alexa'] else '否'
                             isAlexa = '是' if uid_set_qs[0]['is_alexa'] else '否'
                             device_info_list["datas"][k]['fields']['isAlexa'] = isAlexa
                             device_info_list["datas"][k]['fields']['isAlexa'] = isAlexa
                             device_info_list["datas"][k]['fields']['ip'] = uid_set_qs[0]['ip']
                             device_info_list["datas"][k]['fields']['ip'] = uid_set_qs[0]['ip']
+                            device_info_list["datas"][k]['fields']['version'] = uid_set_qs[0]['version']
             return response.json(0, {'list': device_info_list, 'total': total})
             return response.json(0, {'list': device_info_list, 'total': total})
         except Exception as e:
         except Exception as e:
             print(e)
             print(e)
@@ -135,7 +151,7 @@ class DeviceManagement(View):
                 Device_Info.objects.filter(id=deviceID).delete()
                 Device_Info.objects.filter(id=deviceID).delete()
                 # 删除推送消息
                 # 删除推送消息
                 for val in range(1, 8):
                 for val in range(1, 8):
-                    EquipmentInfoService.get_equipment_info_model('', val).\
+                    EquipmentInfoService.get_equipment_info_model('', val). \
                         filter(device_user_id=userID, device_uid=uid).delete()
                         filter(device_user_id=userID, device_uid=uid).delete()
             return response.json(0)
             return response.json(0)
         except Exception as e:
         except Exception as e:
@@ -182,14 +198,14 @@ class DeviceManagement(View):
                 'time': int(time.time()),
                 'time': int(time.time()),
                 'url': 'deviceManagement/resetVod',
                 'url': 'deviceManagement/resetVod',
                 'content': json.dumps(content),
                 'content': json.dumps(content),
-                'operation': '{}重置设备云存'.format(uid),
+                'operation': '{}重置云存'.format(uid),
             }
             }
             with transaction.atomic():
             with transaction.atomic():
                 LogModel.objects.create(**log)
                 LogModel.objects.create(**log)
                 # 删除和更新设备云存相关数据
                 # 删除和更新设备云存相关数据
                 UID_Bucket.objects.filter(uid=uid).delete()
                 UID_Bucket.objects.filter(uid=uid).delete()
                 Unused_Uid_Meal.objects.filter(uid=uid).delete()
                 Unused_Uid_Meal.objects.filter(uid=uid).delete()
-                Order_Model.objects.filter(UID=uid).delete()
+                Order_Model.objects.filter(UID=uid, order_type=0).delete()
                 StsCrdModel.objects.filter(uid=uid).delete()
                 StsCrdModel.objects.filter(uid=uid).delete()
                 VodHlsModel.objects.filter(uid=uid).delete()
                 VodHlsModel.objects.filter(uid=uid).delete()
                 ExperienceContextModel.objects.filter(uid=uid).delete()
                 ExperienceContextModel.objects.filter(uid=uid).delete()
@@ -199,6 +215,34 @@ class DeviceManagement(View):
             print(e)
             print(e)
             return response.json(500, repr(e))
             return response.json(500, repr(e))
 
 
+    @staticmethod
+    def reset_ai(request, request_dict, response):
+        uid = request_dict.get('uid', None)
+        if not uid:
+            return response.json(444)
+        try:
+            # 记录操作日志
+            ip = CommonService.get_ip_address(request)
+            content = json.loads(json.dumps(request_dict))
+            log = {
+                'ip': ip,
+                'user_id': 2,
+                'status': 200,
+                'time': int(time.time()),
+                'url': 'deviceManagement/resetAi',
+                'content': json.dumps(content),
+                'operation': '{}重置AI'.format(uid),
+            }
+            with transaction.atomic():
+                LogModel.objects.create(**log)
+                # 删除和更新设备AI相关数据
+                ExperienceAiModel.objects.filter(uid=uid).delete()
+                AiService.objects.filter(uid=uid).delete()
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
     # 获取设备类型数据
     # 获取设备类型数据
     def getDeviceTypeList(self, request_dict, response):
     def getDeviceTypeList(self, request_dict, response):
         name = request_dict.get('name', None)
         name = request_dict.get('name', None)
@@ -263,7 +307,7 @@ class DeviceManagement(View):
             # 上传文件到阿里云OSS
             # 上传文件到阿里云OSS
             auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
             auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
             bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'ansjer-static-resources')
             bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'ansjer-static-resources')
-            key = 'device_type/' + icon     # 图片文件存放于 device_type 目录下
+            key = 'device_type/' + icon  # 图片文件存放于 device_type 目录下
             # https://oss.console.aliyun.com/bucket/oss-cn-shenzhen/ansjer-static-resources/object?path=device_type%2F
             # https://oss.console.aliyun.com/bucket/oss-cn-shenzhen/ansjer-static-resources/object?path=device_type%2F
             bucket.put_object(key=key, data=iconFile)
             bucket.put_object(key=key, data=iconFile)
             DeviceTypeModel.objects.create(name=name, model=model, type=type, ptz_type=ptz_type, icon=icon,
             DeviceTypeModel.objects.create(name=name, model=model, type=type, ptz_type=ptz_type, icon=icon,
@@ -273,8 +317,8 @@ class DeviceManagement(View):
             print(e)
             print(e)
             return response.json(500, repr(e))
             return response.json(500, repr(e))
 
 
-    # 删除设备数据
-    def delDeviceData(self, request_dict, response):
+    @staticmethod
+    def del_device_data(request_dict, response):
         uidList = request_dict.get('uidList', None)
         uidList = request_dict.get('uidList', None)
         delDataOptions = request_dict.get('delDataOptions', None)
         delDataOptions = request_dict.get('delDataOptions', None)
 
 
@@ -282,7 +326,7 @@ class DeviceManagement(View):
             return response.json(444)
             return response.json(444)
         try:
         try:
             with transaction.atomic():
             with transaction.atomic():
-                uidList = uidList.splitlines()      # 按行('\r', '\r\n', \n')切割字符串返回列表
+                uidList = uidList.splitlines()  # 按行('\r', '\r\n', \n')切割字符串返回列表
                 # 根据删除项删除相关数据
                 # 根据删除项删除相关数据
                 if '设备信息数据' in delDataOptions:
                 if '设备信息数据' in delDataOptions:
                     Device_Info.objects.filter(UID__in=uidList).delete()
                     Device_Info.objects.filter(UID__in=uidList).delete()
@@ -292,15 +336,133 @@ class DeviceManagement(View):
                     Equipment_Info.objects.filter(devUid__in=uidList).delete()
                     Equipment_Info.objects.filter(devUid__in=uidList).delete()
                 if '设备AP信息数据' in delDataOptions:
                 if '设备AP信息数据' in delDataOptions:
                     UidUserModel.objects.filter(UID__in=uidList).delete()
                     UidUserModel.objects.filter(UID__in=uidList).delete()
+                if '设备AI数据' in delDataOptions:
+                    ExperienceAiModel.objects.filter(uid__in=uidList).delete()
+                    Order_Model.objects.filter(UID__in=uidList, order_type=1).delete()
                 if '设备云存数据' in delDataOptions:
                 if '设备云存数据' in delDataOptions:
                     UID_Bucket.objects.filter(uid__in=uidList).delete()
                     UID_Bucket.objects.filter(uid__in=uidList).delete()
-                    Unused_Uid_Meal.objects.filter(uid__in=uidList).delete()
-                    Order_Model.objects.filter(UID__in=uidList).delete()
                     StsCrdModel.objects.filter(uid__in=uidList).delete()
                     StsCrdModel.objects.filter(uid__in=uidList).delete()
                     VodHlsModel.objects.filter(uid__in=uidList).delete()
                     VodHlsModel.objects.filter(uid__in=uidList).delete()
+                    Unused_Uid_Meal.objects.filter(uid__in=uidList).delete()
                     ExperienceContextModel.objects.filter(uid__in=uidList).delete()
                     ExperienceContextModel.objects.filter(uid__in=uidList).delete()
+                    Order_Model.objects.filter(UID__in=uidList, order_type=0).delete()
                     Device_Info.objects.filter(UID__in=uidList).update(vodPrimaryUserID='', vodPrimaryMaster='')
                     Device_Info.objects.filter(UID__in=uidList).update(vodPrimaryUserID='', vodPrimaryMaster='')
             return response.json(0)
             return response.json(0)
         except Exception as e:
         except Exception as e:
             print(e)
             print(e)
             return response.json(500, repr(e))
             return response.json(500, repr(e))
+
+    @staticmethod
+    def get_device_icon(request_dict, response):
+        lang = request_dict.get('lang', None)
+        app_bundle_id = request_dict.get('appBundleId', None)
+
+        if not all([lang, app_bundle_id]):
+            return response.json(444)
+        try:
+            app_bundle_qs = AppBundle.objects.filter(app_bundle_id=app_bundle_id,
+                                                     app_device_type__devicenamelanguage__lang=lang).annotate(
+                model=F('app_device_type__model'), type=F('app_device_type__type'), icon=F('app_device_type__icon'),
+                name=F('app_device_type__devicenamelanguage__name'),
+                sort=F('app_device_type__devicenamelanguage__sort')).order_by(
+                'app_device_type__devicenamelanguage__sort').values('model', 'type', 'icon', 'name', 'sort')
+            dvr_list = [app_bundle for app_bundle in app_bundle_qs if app_bundle['model'] == 1]
+            ipc_list = [app_bundle for app_bundle in app_bundle_qs if app_bundle['model'] == 2]
+            print(dvr_list, ipc_list)
+            res = {
+                'deviceDvr': dvr_list,
+                'deviceIpc': ipc_list,
+            }
+            return response.json(0, res)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_app_device_type_list(request_dict, response):
+        app_bundle_id = request_dict.get('appBundleId', None)
+        lang = request_dict.get('lang', 'cn')
+
+        pageNo = request_dict.get('pageNo', None)
+        pageSize = request_dict.get('pageSize', None)
+
+        if not all([pageNo, pageSize]):
+            return response.json(444)
+
+        page = int(pageNo)
+        line = int(pageSize)
+        try:
+            if not app_bundle_id:
+                app_bundle_id = 'com.ansjer.zccloud'
+            app_bundle_qs = AppBundle.objects.filter(app_bundle_id=app_bundle_id)
+            if lang:
+                app_bundle_qs = app_bundle_qs.filter(app_device_type__devicenamelanguage__lang=lang)
+
+            app_bundle_qs = app_bundle_qs.annotate(
+                model=F('app_device_type__model'), type=F('app_device_type__type'), icon=F('app_device_type__icon'),
+                lang=F('app_device_type__devicenamelanguage__lang'),
+                name=F('app_device_type__devicenamelanguage__name'),
+                sort=F('app_device_type__devicenamelanguage__sort')).values('id', 'app_device_type__id', 'model',
+                                                                            'type', 'icon',
+                                                                            'app_device_type__devicenamelanguage__id',
+                                                                            'lang', 'name', 'sort').order_by(
+                'app_device_type__devicenamelanguage__sort')
+            if not app_bundle_qs.exists():
+                return response.json(0)
+            total = app_bundle_qs.count()
+            app_bundle_qs = app_bundle_qs[(page - 1) * line:page * line]
+            app_device_type_list = [app_bundle for app_bundle in app_bundle_qs]
+            return response.json(0, {'list': app_device_type_list, 'total': total})
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_app_bundle_id_list(response):
+        try:
+            app_info_qs = App_Info.objects.filter().values('id', 'appBundleId', 'appName')
+            appBundleIdList = list(app_info_qs)
+            return response.json(0, {'list': appBundleIdList})
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def edit_app_device_type(request_dict, response):
+        # app_device_type表数据
+        app_device_type_id = request_dict.get('app_device_type__id', None)
+        model = request_dict.get('model', None)
+        type = request_dict.get('type', None)
+        icon = request_dict.get('icon', None)
+        # device_name_language表数据
+        device_name_language_id = request_dict.get('app_device_type__devicenamelanguage__id', None)
+        lang = request_dict.get('lang', None)
+        name = request_dict.get('name', None)
+        sort = request_dict.get('sort', None)
+
+        if not all([app_device_type_id, model, type, icon, device_name_language_id, lang, name, sort]):
+            return response.json(444)
+
+        try:
+            with transaction.atomic():
+                AppDeviceType.objects.filter(id=app_device_type_id).update(model=model, type=type, icon=icon)
+                DeviceNameLanguage.objects.filter(id=device_name_language_id).update(lang=lang, name=name, sort=sort)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def delete_app_device_type(request_dict, response):
+        app_bundle_id = request_dict.get('appBundleId', None)
+        app_device_type_id = request_dict.get('appDeviceTypeId', None)
+        if not all([app_bundle_id, app_device_type_id]):
+            return response.json(444)
+        try:
+            app_bundle_qs = AppBundle.objects.get(id=app_bundle_id)
+            app_device_type_qs = AppDeviceType.objects.filter(id=app_device_type_id)
+            app_bundle_qs.app_device_type.remove(*app_device_type_qs)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))

+ 5 - 28
AdminController/LogManagementController.py

@@ -154,8 +154,9 @@ class LogManagementView(View):
             print(e)
             print(e)
             return response.json(500, repr(e))
             return response.json(500, repr(e))
 
 
-    def requestPublishMqtt(self, request_dict, response):
-        # 通用发布MQTT主题通知
+    # 通用发布MQTT通知
+    @staticmethod
+    def requestPublishMqtt(request_dict, response):
         msg = request_dict.get('msg', None)
         msg = request_dict.get('msg', None)
         thing_name = request_dict.get('thing_name', None)
         thing_name = request_dict.get('thing_name', None)
         topic_name = request_dict.get('topic_name', None)
         topic_name = request_dict.get('topic_name', None)
@@ -163,34 +164,10 @@ class LogManagementView(View):
             return response.json(444)
             return response.json(444)
 
 
         try:
         try:
-            # 获取数据组织将要请求的url
-            iot = iotdeviceInfoModel.objects.filter(
-                thing_name=thing_name).values(
-                'endpoint', 'token_iot_number')
-            if not iot.exists():
-                return response.json(10043)
-            endpoint = iot[0]['endpoint']
-            Token = iot[0]['token_iot_number']
-
-            # api doc: https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/http.html
-            # url: https://IoT_data_endpoint/topics/url_encoded_topic_name?qos=1
-            # post请求url发布MQTT消息
-            url = 'https://{}/topics/{}'.format(endpoint, topic_name)
-            authorizer_name = 'Ansjer_Iot_Auth'
-            signature = CommonService.rsa_sign(Token)  # Token签名
-            headers = {
-                'x-amz-customauthorizer-name': authorizer_name,
-                'Token': Token,
-                'x-amz-customauthorizer-signature': signature}
             msg = eval(msg)
             msg = eval(msg)
-            r = requests.post(url=url, headers=headers, json=msg, timeout=2)
-            if r.status_code == 200:
-                res = r.json()
-                if res['message'] == 'OK':
-                    return response.json(0)
-                return response.json(10044)
-            else:
+            if not CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg):
                 return response.json(10044)
                 return response.json(10044)
+            return response.json(0)
         except Exception as e:
         except Exception as e:
             return response.json(500, repr(e))
             return response.json(500, repr(e))
 
 

+ 5 - 3
AdminController/SerialManageController.py

@@ -15,7 +15,7 @@ from django.utils.decorators import method_decorator
 from django.views.decorators.csrf import csrf_exempt
 from django.views.decorators.csrf import csrf_exempt
 from django.views.generic.base import View
 from django.views.generic.base import View
 
 
-from Model.models import CompanyModel, SerialNumberModel, VPGModel, UIDModel, UIDCompanySerialModel, CompanySerialModel, \
+from Model.models import CompanyModel, VPGModel, UIDModel, UIDCompanySerialModel, CompanySerialModel, \
     LogModel
     LogModel
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
@@ -182,7 +182,7 @@ class SerialView(View):
             if not company_serial_qs.exists():
             if not company_serial_qs.exists():
                 return response.json(0, {'list': '', 'total': 0})
                 return response.json(0, {'list': '', 'total': 0})
             total = company_serial_qs.count()
             total = company_serial_qs.count()
-            serial_number_page = company_serial_qs.order_by('-serial_number')[(page - 1) * line:page * line].\
+            serial_number_page = company_serial_qs.order_by('-serial_number')[(page - 1) * line:page * line]. \
                 values('serial_number', 'company__name', 'status', 'add_time', 'update_time')
                 values('serial_number', 'company__name', 'status', 'add_time', 'update_time')
             return response.json(0, {'list': list(serial_number_page), 'total': total})
             return response.json(0, {'list': list(serial_number_page), 'total': total})
         except Exception as e:
         except Exception as e:
@@ -241,7 +241,7 @@ class SerialView(View):
         try:
         try:
             query = UIDModel.objects.filter()
             query = UIDModel.objects.filter()
             if serial_number:
             if serial_number:
-                company_serial_qs = CompanySerialModel.objects.filter(serial_number=serial_number).values()
+                company_serial_qs = CompanySerialModel.objects.filter(serial_number__contains=serial_number).values()
                 if company_serial_qs.exists():
                 if company_serial_qs.exists():
                     cs_id = str(company_serial_qs[0]['id'])
                     cs_id = str(company_serial_qs[0]['id'])
                     uid_company_serial_qs = UIDCompanySerialModel.objects.filter(company_serial_id=cs_id).values(
                     uid_company_serial_qs = UIDCompanySerialModel.objects.filter(company_serial_id=cs_id).values(
@@ -249,6 +249,8 @@ class SerialView(View):
                     if uid_company_serial_qs.exists():
                     if uid_company_serial_qs.exists():
                         uid_id = uid_company_serial_qs[0]['uid_id']
                         uid_id = uid_company_serial_qs[0]['uid_id']
                         query = query.filter(id=uid_id)
                         query = query.filter(id=uid_id)
+                else:
+                    return response.json(0, {'list': '', 'total': 0})
             if vpg_id:
             if vpg_id:
                 query = query.filter(vpg_id=int(vpg_id))
                 query = query.filter(vpg_id=int(vpg_id))
             if status:
             if status:

+ 13 - 5
AdminController/ServeManagementController.py

@@ -14,7 +14,7 @@ from boto3.session import Session
 from django.http import JsonResponse, HttpResponseRedirect, HttpResponse, StreamingHttpResponse
 from django.http import JsonResponse, HttpResponseRedirect, HttpResponse, StreamingHttpResponse
 from django.views.generic.base import View
 from django.views.generic.base import View
 from Model.models import Device_Info, Role, MenuModel, VodBucketModel, CDKcontextModel, Store_Meal, Order_Model, \
 from Model.models import Device_Info, Role, MenuModel, VodBucketModel, CDKcontextModel, Store_Meal, Order_Model, \
-    UID_Bucket, ExperienceContextModel, Lang, Device_User, CloudLogModel, UidSetModel
+    UID_Bucket, ExperienceContextModel, Lang, Device_User, CloudLogModel, UidSetModel, Unused_Uid_Meal
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
 from Object.UidTokenObject import UidTokenObject
 from Object.UidTokenObject import UidTokenObject
@@ -845,16 +845,24 @@ class serveManagement(View):
             uid_bucket_qs = uid_bucket_qs.order_by('-addTime')[(page - 1) * line:page * line]
             uid_bucket_qs = uid_bucket_qs.order_by('-addTime')[(page - 1) * line:page * line]
 
 
             for uid_bucket in uid_bucket_qs:
             for uid_bucket in uid_bucket_qs:
+                # 套餐到期时间累加未使用套餐
+                unused_qs = Unused_Uid_Meal.objects.filter(uid=uid_bucket.uid).values('num', 'expire')
+                if unused_qs.exists():
+                    addMonth = 0
+                    for unused in unused_qs:
+                        addMonth += unused['num'] * unused['expire']
+                    endTime = CommonService.calcMonthLater(addMonth, uid_bucket.endTime)
+                    endTime = time.strftime("%Y--%m--%d %H:%M:%S", time.localtime(endTime))
+                else:
+                    endTime = time.strftime("%Y--%m--%d %H:%M:%S", time.localtime(uid_bucket.endTime))
+
                 uid = uid_bucket.uid.upper()
                 uid = uid_bucket.uid.upper()
                 data = {
                 data = {
                     'id': uid_bucket.id,
                     'id': uid_bucket.id,
                     'uid': uid,
                     'uid': uid,
                     'channel': uid_bucket.channel,
                     'channel': uid_bucket.channel,
                     'status': uid_bucket.status,
                     'status': uid_bucket.status,
-                    'endTime': time.strftime(
-                        "%Y--%m--%d %H:%M:%S",
-                        time.localtime(
-                            uid_bucket.endTime)),
+                    'endTime': endTime,
                     'addTime': time.strftime(
                     'addTime': time.strftime(
                         "%Y--%m--%d %H:%M:%S",
                         "%Y--%m--%d %H:%M:%S",
                         time.localtime(
                         time.localtime(

+ 3 - 0
Ansjer/cn_config/config_formal.py

@@ -13,6 +13,9 @@
 """
 """
 import os
 import os
 
 
+# 配置信息
+CONFIG_INFO = 'cn'
+
 NGINX_RTMP_STAT = 'http://www.zositechc.cn/stat'
 NGINX_RTMP_STAT = 'http://www.zositechc.cn/stat'
 SERVER_DOMAIN_SSL = 'https://www.zositechc.cn/'
 SERVER_DOMAIN_SSL = 'https://www.zositechc.cn/'
 SERVER_DOMAIN = 'http://www.zositechc.cn/'
 SERVER_DOMAIN = 'http://www.zositechc.cn/'

+ 3 - 0
Ansjer/cn_config/config_test.py

@@ -13,6 +13,9 @@
 """
 """
 import os
 import os
 
 
+# 配置信息
+CONFIG_INFO = 'test'
+
 NGINX_RTMP_STAT = 'http://test.zositechc.cn/stat/'
 NGINX_RTMP_STAT = 'http://test.zositechc.cn/stat/'
 SERVER_DOMAIN = 'http://test.zositechc.cn/'
 SERVER_DOMAIN = 'http://test.zositechc.cn/'
 SERVER_DOMAIN_SSL = 'https://test.zositechc.cn/'
 SERVER_DOMAIN_SSL = 'https://test.zositechc.cn/'

+ 36 - 2
Ansjer/config.py

@@ -12,7 +12,14 @@
 @Contact: chanjunkai@163.com
 @Contact: chanjunkai@163.com
 """
 """
 # 主要静态变量配置文件
 # 主要静态变量配置文件
-import datetime, os
+import os
+import datetime
+
+# 配置信息
+CONFIG_TEST = 'test'
+CONFIG_CN = 'cn'
+CONFIG_US = 'us'
+CONFIG_EUR = 'eur'
 
 
 SERVER_TYPE = os.environ.get('DJANGO_SETTINGS_MODULE')
 SERVER_TYPE = os.environ.get('DJANGO_SETTINGS_MODULE')
 print(SERVER_TYPE)
 print(SERVER_TYPE)
@@ -364,6 +371,9 @@ JPUSH_CONFIG = {
     'com.ansjer.customizedc_a': {
     'com.ansjer.customizedc_a': {
         'Key': 'ecdde95cd272f410ee029139',
         'Key': 'ecdde95cd272f410ee029139',
         'Secret': '9ddca1e92bfa331126fd8826'},
         'Secret': '9ddca1e92bfa331126fd8826'},
+    'com.ansjer.customizedf_a': {
+        'Key': '6ddbfb8fd7a0984dfba74a00',
+        'Secret': '971ee5c5facfbe76cb31a686'},
 }
 }
 # type =1
 # type =1
 FCM_CONFIG = {
 FCM_CONFIG = {
@@ -377,6 +387,7 @@ FCM_CONFIG = {
     'com.ansjer.accloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
     'com.ansjer.accloud_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
     'com.ansjer.zccloud_ab': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
     'com.ansjer.zccloud_ab': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
     'com.ansjer.customizedc_a': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
     'com.ansjer.customizedc_a': 'AAAAb9YP3rk:APA91bHu8u-CTpcd0g6lKPo0WNVqCi8jZub1cPPbSAY9AucT1HxlF65ZDUko9iG8q2ch17bwu9YWHpK1xI1gHSRXCslLvZlXEmHZC0AG3JKg15XuUvlFKACIajUFV-pOeGRT8tM6-31I',
+    'com.ansjer.customizedf_a': 'AAAAb9YP3rk:APA91bFm06w8b9OKQ0gz0iaWFuRqRIkvgAz6z7Gp3dBU_X-LNGJQd1hc1QR2W7QzBglF8SHtERA45a2lbdLRa5qv7hxfd6W_sJLBK7dA8jklsOQBvy505oUzTwMKWy4TwH-exps9KrhO',
 }
 }
 APNS_CONFIG = {
 APNS_CONFIG = {
     'com.ansjer.loocamccloud': {
     'com.ansjer.loocamccloud': {
@@ -403,6 +414,9 @@ APNS_CONFIG = {
     'com.ansjer.customizede': {
     'com.ansjer.customizede': {
         'pem_path': 'AnsjerPush/file/apns_pem/customizede.pem',
         'pem_path': 'AnsjerPush/file/apns_pem/customizede.pem',
     },
     },
+    'com.ansjer.customizedh': {
+        'pem_path': 'AnsjerPush/file/apns_pem/customizedh.pem',
+    },
 }
 }
 APNS_MODE = 'dev'
 APNS_MODE = 'dev'
 SERVER_TYPE = os.environ.get('DJANGO_SETTINGS_MODULE')
 SERVER_TYPE = os.environ.get('DJANGO_SETTINGS_MODULE')
@@ -433,4 +447,24 @@ APNS_CODE = {
 APP_TYPE = {
 APP_TYPE = {
     1: 'ios',
     1: 'ios',
     2: 'android'
     2: 'android'
-}
+}
+
+# 联通Unicom config
+# 应用地址,请向开发人员索取
+unicomAppUrl = 'https://chinaunicom-iot.unimip.cn'
+# 应用id,请向开发人员创建应用,分配appId
+unicomAppId = 'LNO7ojB7mZU5ep9IuiHvygVWbwaO9vt0'
+# 应用密匙,请向开发人员创建应用,分配appSecret
+unicomAppSecret = 'p8MT1CS4QAVl0xb4cp7VOCgMvtQp2O43'
+# 租户/产品ID,请向开发人员索取
+unicomTenantId = '1469181295663300608'
+# 密码加密密匙,请向开发人员索取
+unicomEncodeKey = 'uBdUx82vPHkDKb284d7NkjFoNcKWBuka'
+# 密码加密参数,请向开发人员索取
+unicomIvKey = 'oCRU0D1wKfBlNeTz'
+# 用户名,如无请联系客户经理开通
+unicomUserName = 'zh-zhasjdz'
+# 登录密码,如无请联系客户经理
+unicomPassword = 'XoROL1vCl5@_'
+# 回调签名验证加密密匙,请向开发人员索取
+unicomPushKey = 'NVVDQMBSOJTXA'

+ 3 - 0
Ansjer/eur_config/config_formal.py

@@ -13,6 +13,9 @@
 """
 """
 import os
 import os
 
 
+# 配置信息
+CONFIG_INFO = 'eur'
+
 NGINX_RTMP_STAT = 'http://www.dvema.com/stat'
 NGINX_RTMP_STAT = 'http://www.dvema.com/stat'
 SERVER_DOMAIN_SSL = 'https://www.dvema.com/'
 SERVER_DOMAIN_SSL = 'https://www.dvema.com/'
 SERVER_DOMAIN = 'http://www.dvema.com/'
 SERVER_DOMAIN = 'http://www.dvema.com/'

+ 3 - 0
Ansjer/local_config/config_local.py

@@ -3,6 +3,9 @@
 
 
 import os
 import os
 
 
+# 配置信息
+CONFIG_INFO = 'test'
+
 OAUTH_ACCESS_TOKEN_SECRET = 'local_a+jbgnw%@1%zy^=@dn62%'
 OAUTH_ACCESS_TOKEN_SECRET = 'local_a+jbgnw%@1%zy^=@dn62%'
 OAUTH_REFRESH_TOKEN_SECRET = 'local_r+jbgnw%@1%zy^=@dn62%'
 OAUTH_REFRESH_TOKEN_SECRET = 'local_r+jbgnw%@1%zy^=@dn62%'
 
 

+ 4 - 4
Ansjer/local_config/local_settings.py

@@ -97,16 +97,16 @@ WSGI_APPLICATION = 'Ansjer.local_config.local_wsgi.application'
 # DATABASES_PASS = 'UKv78ezQhiGMmSef5U5s'
 # DATABASES_PASS = 'UKv78ezQhiGMmSef5U5s'
 
 
 # 本地数据库
 # 本地数据库
-DATABASE_DATA = 'ansjer_test'
+DATABASE_DATA = 'ansjer'
 SERVER_HOST = '127.0.0.1'
 SERVER_HOST = '127.0.0.1'
 DATABASES_USER = 'root'
 DATABASES_USER = 'root'
-DATABASES_PASS = 'root'
+DATABASES_PASS = '123456'
 
 
 # 推送数据库
 # 推送数据库
-DATABASE_DATA2 = 'ansjerpush'
+DATABASE_DATA2 = 'push'
 SERVER_HOST2 = '127.0.0.1'
 SERVER_HOST2 = '127.0.0.1'
 DATABASES_USER2 = 'root'
 DATABASES_USER2 = 'root'
-DATABASES_PASS2 = 'root'
+DATABASES_PASS2 = '123456'
 
 
 # 序列号公共数据库
 # 序列号公共数据库
 # DATABASE_DATA3 = 'ansjer_test'
 # DATABASE_DATA3 = 'ansjer_test'

+ 21 - 0
Ansjer/server_urls/loocam_url.py

@@ -0,0 +1,21 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : loocam_url.py
+@Time    : 2022/5/20 11:44
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+from django.urls import re_path
+
+from Controller.SensorGateway import GatewayFamilyRoomController, SubDeviceController, GatewayFamilyMemberController, \
+    EquipmentFamilyController, GatewayDeviceController
+
+urlpatterns = [
+    re_path(r'^sensor/gateway/(?P<operation>.*)$', EquipmentFamilyController.EquipmentFamilyView.as_view()),
+    re_path(r'^gateway/family/room/(?P<operation>.*)$', GatewayFamilyRoomController.GatewayFamilyRoomView.as_view()),
+    re_path(r'^gateway/family/member/(?P<operation>.*)$',
+            GatewayFamilyMemberController.GatewayFamilyMemberView.as_view()),
+    re_path(r'^gateway/subdevice/(?P<operation>.*)$', SubDeviceController.GatewaySubDeviceView.as_view()),
+    re_path(r'^gateway/device/info/(?P<operation>.*)$', GatewayDeviceController.GatewayDeviceView.as_view()),
+]

+ 15 - 0
Ansjer/server_urls/unicom_url.py

@@ -0,0 +1,15 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : unicom_url.py
+@Time    : 2022/6/23 9:50
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+from django.urls import re_path
+
+from Controller.UnicomCombo import UnicomComboController
+
+urlpatterns = [
+    re_path(r'^api/(?P<operation>.*)$', UnicomComboController.UnicomComboView.as_view()),
+]

+ 16 - 6
Ansjer/urls.py

@@ -1,7 +1,10 @@
-from django.contrib import admin
 from django.conf.urls import url
 from django.conf.urls import url
+from django.contrib import admin
 from django.urls import path, re_path
 from django.urls import path, re_path
 
 
+from AdminController import UserManageController, RoleController, MenuController, TestServeController, \
+    ServeManagementController, LogManagementController, DeviceManagementController, VersionManagementController, \
+    AiServeController, SurveysManageController, SerialManageController
 from Controller import FeedBack, EquipmentOTA, EquipmentInfo, AdminManage, AppInfo, \
 from Controller import FeedBack, EquipmentOTA, EquipmentInfo, AdminManage, AppInfo, \
     AccessLog, DynamoDBLog, Test, MealManage, DeviceManage, EquipmentStatus, SysManage, DeviceLog, LogAccess, \
     AccessLog, DynamoDBLog, Test, MealManage, DeviceManage, EquipmentStatus, SysManage, DeviceLog, LogAccess, \
     AppColophon, DateController, \
     AppColophon, DateController, \
@@ -20,12 +23,11 @@ from Controller import FeedBack, EquipmentOTA, EquipmentInfo, AdminManage, AppIn
     RegionController, VPGController, LanguageController, TestController, DeviceConfirmRegion, S3GetStsController, \
     RegionController, VPGController, LanguageController, TestController, DeviceConfirmRegion, S3GetStsController, \
     DetectControllerV2, ShadowController, TestDetectController, PcInfo, PctestController, DeviceDebug, PaymentCycle, \
     DetectControllerV2, ShadowController, TestDetectController, PcInfo, PctestController, DeviceDebug, PaymentCycle, \
     DeviceLogController, CouponController, AiController
     DeviceLogController, CouponController, AiController
-from Controller.Surveys import CloudStorageController
 from Controller.Cron import CronTaskController
 from Controller.Cron import CronTaskController
-from AdminController import UserManageController, RoleController, MenuController, TestServeController, \
-    ServeManagementController, LogManagementController, DeviceManagementController, VersionManagementController, \
-    AiServeController, SurveysManageController, SerialManageController
-from SensorGateway import SensorGatewayController
+from Controller.MessagePush import EquipmentMessagePush
+from Controller.Surveys import CloudStorageController
+from Controller.SensorGateway import SensorGatewayController, EquipmentFamilyController
+from django.urls import include
 
 
 urlpatterns = [
 urlpatterns = [
     url(r'^testApi/(?P<operation>.*)$', TestApi.testView.as_view()),
     url(r'^testApi/(?P<operation>.*)$', TestApi.testView.as_view()),
@@ -242,6 +244,8 @@ urlpatterns = [
 
 
     # AI服务
     # AI服务
     url(r'^AiService/(?P<operation>.*)$', AiController.AiView.as_view()),
     url(r'^AiService/(?P<operation>.*)$', AiController.AiView.as_view()),
+    # 消息提醒
+    url(r'^app/setting/notification/(?P<operation>.*)$', EquipmentMessagePush.EquipmentMessagePushView.as_view()),
 
 
     # 新增解密的接口
     # 新增解密的接口
     url(r'^v3/account/changePwd$', UserController.v3ChangePwdView.as_view()),
     url(r'^v3/account/changePwd$', UserController.v3ChangePwdView.as_view()),
@@ -359,6 +363,12 @@ urlpatterns = [
     # 问卷调查
     # 问卷调查
     url(r'^api/surveys/(?P<operation>.*)$', CloudStorageController.CloudStorageView.as_view()),
     url(r'^api/surveys/(?P<operation>.*)$', CloudStorageController.CloudStorageView.as_view()),
 
 
+    # 网关家庭模块
+    url(r'^app/sensor/gateway/(?P<operation>.*)$', EquipmentFamilyController.EquipmentFamilyView.as_view()),
+    url(r'^loocam/', include("Ansjer.server_urls.loocam_url")),
+    # 联通4G套餐模块
+    url(r'^unicom/', include("Ansjer.server_urls.unicom_url")),
+
     # 传感器网关
     # 传感器网关
     re_path('sensorGateway/(?P<operation>.*)', SensorGatewayController.SensorGateway.as_view()),
     re_path('sensorGateway/(?P<operation>.*)', SensorGatewayController.SensorGateway.as_view()),
 
 

+ 3 - 0
Ansjer/us_config/config_formal.py

@@ -13,6 +13,9 @@
 """
 """
 import os
 import os
 
 
+# 配置信息
+CONFIG_INFO = 'us'
+
 NGINX_RTMP_STAT = 'http://www.dvema.com/stat'
 NGINX_RTMP_STAT = 'http://www.dvema.com/stat'
 SERVER_DOMAIN_SSL = 'https://www.dvema.com/'
 SERVER_DOMAIN_SSL = 'https://www.dvema.com/'
 SERVER_DOMAIN = 'http://www.dvema.com/'
 SERVER_DOMAIN = 'http://www.dvema.com/'

+ 204 - 116
Controller/AiController.py

@@ -11,62 +11,37 @@
 @file: cloudstorage.py
 @file: cloudstorage.py
 @Contact: chanjunkai@163.com
 @Contact: chanjunkai@163.com
 """
 """
-import base64
-import json
+import logging
 import os
 import os
 import time
 import time
-import glob
-import urllib
 from urllib.parse import quote, parse_qs, unquote
 from urllib.parse import quote, parse_qs, unquote
 
 
 import apns2
 import apns2
 import boto3
 import boto3
+import botocore
 import jpush
 import jpush
-import oss2
 import paypalrestsdk
 import paypalrestsdk
-import threading
-import calendar
-import datetime
-import logging
-import sys
-import requests
-from aliyunsdkcore import client
-from aliyunsdksts.request.v20150401 import AssumeRoleRequest
 from boto3.session import Session
 from boto3.session import Session
-from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
+from botocore import client
 from django.db import transaction
 from django.db import transaction
+from django.db.models import Q, F, Sum
+from django.http import HttpResponseRedirect, HttpResponse
 from django.views.generic.base import View
 from django.views.generic.base import View
-import jwt
-from Object.ETkObject import ETkObject
 from pyfcm import FCMNotification
 from pyfcm import FCMNotification
-from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, OSS_ROLE_ARN, SERVER_DOMAIN, PAYPAL_CRD, \
-    SERVER_DOMAIN_SSL, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ARN, APNS_MODE, APNS_CONFIG, BASE_DIR, \
-    JPUSH_CONFIG, FCM_CONFIG, OAUTH_ACCESS_TOKEN_SECRET, DETECT_PUSH_DOMAINS
-from Controller.CheckUserData import DataValid
-from Model.models import Device_Info, Order_Model, Store_Meal, VodHlsModel, OssCrdModel, UID_Bucket, StsCrdModel, \
-    ExperienceContextModel, Pay_Type, CDKcontextModel, Device_User, SysMassModel, SysMsgModel, UidPushModel, \
-    Unused_Uid_Meal, UIDMainUser, UserModel, PromotionRuleModel, VideoPlaybackTimeModel, CloudLogModel, CouponModel, \
-    AiStoreMeal, AiService, UidSetModel, Ai_Push_Info, iotdeviceInfoModel, AiProcessTime, Equipment_Info
-from Object.AWS.S3Email import S3Email
+
+from Ansjer.config import PAYPAL_CRD, \
+    SERVER_DOMAIN_SSL, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, APNS_MODE, APNS_CONFIG, BASE_DIR, \
+    JPUSH_CONFIG, FCM_CONFIG, DETECT_PUSH_DOMAINS
+from Model.models import Device_Info, Order_Model, ExperienceAiModel, Pay_Type, CDKcontextModel, UidPushModel, \
+    AiStoreMeal, AiService, UidSetModel, Ai_Push_Info
 from Object.AliPayObject import AliPayObject
 from Object.AliPayObject import AliPayObject
-from Object.AliSmsObject import AliSmsObject
+from Object.ETkObject import ETkObject
 from Object.RedisObject import RedisObject
 from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
-from Object.UidTokenObject import UidTokenObject
-from Service.CommonService import CommonService
-from Object.m3u8generate import PlaylistGenerator
 from Object.WechatPayObject import WechatPayObject
 from Object.WechatPayObject import WechatPayObject
-from django.db.models import Q, F, Count, Sum
-from Controller.PaymentCycle import Paypal
-from decimal import Decimal
-from Ansjer.config import SERVER_TYPE
+from Service.CommonService import CommonService
 from Service.ModelService import ModelService
 from Service.ModelService import ModelService
-from Object import MergePic
-import boto3
-import botocore
-from botocore import client
-
 
 
 
 
 # AI服务
 # AI服务
@@ -106,7 +81,7 @@ class AiView(View):
             elif operation == 'getAiStatus':  # 获取AI开关状态
             elif operation == 'getAiStatus':  # 获取AI开关状态
                 return self.getAiStatus(userID, request_dict, response)
                 return self.getAiStatus(userID, request_dict, response)
             elif operation == 'commoditylist':  # 获取AI套餐列表
             elif operation == 'commoditylist':  # 获取AI套餐列表
-                return self.do_commodity_list(userID, request_dict, response)
+                return self.do_commodity_list(request_dict, response)
             elif operation == 'queryInfo':  # 查询消息列表
             elif operation == 'queryInfo':  # 查询消息列表
                 return self.queryInfo(userID, request_dict, response)
                 return self.queryInfo(userID, request_dict, response)
             elif operation == 'readInfo':  # 消息已读
             elif operation == 'readInfo':  # 消息已读
@@ -117,6 +92,8 @@ class AiView(View):
                 return self.do_querylist(userID, request_dict, response)
                 return self.do_querylist(userID, request_dict, response)
             elif operation == 'getUsingPackage':  # 获取当前使用的ai套餐
             elif operation == 'getUsingPackage':  # 获取当前使用的ai套餐
                 return self.getUsingPackage(request_dict, userID, response)
                 return self.getUsingPackage(request_dict, userID, response)
+            elif operation == 'experienceOrder':  # 体验AI套餐
+                return self.experience_order(request_dict, userID, response)
             else:
             else:
                 return response.json(414)
                 return response.json(414)
 
 
@@ -163,21 +140,23 @@ class AiView(View):
             if nowTime > endTime:
             if nowTime > endTime:
                 return response.json(10054)
                 return response.json(10054)
 
 
-            dvqs = Device_Info.objects.filter(userID_id=userID, UID=uid)
+            # 查询设备是否属于该用户
+            device_info_qs = Device_Info.objects.filter(userID_id=userID, UID=uid)
+            if not device_info_qs.exists():
+                return response.json(14)
             status = int(status)
             status = int(status)
             nowTime = int(time.time())
             nowTime = int(time.time())
-            if not dvqs.exists():
-                return response.json(14)
+
             uid_set_qs = UidSetModel.objects.filter(uid=uid)
             uid_set_qs = UidSetModel.objects.filter(uid=uid)
             if uid_set_qs.exists():
             if uid_set_qs.exists():
                 uid_set_id = uid_set_qs[0].id
                 uid_set_id = uid_set_qs[0].id
+                interval = uid_set_qs[0].new_detect_interval if not interval else interval
                 qs_data = {
                 qs_data = {
                     'updTime': nowTime,
                     'updTime': nowTime,
                 }
                 }
                 if interval:
                 if interval:
                     qs_data['detect_interval'] = int(interval)
                     qs_data['detect_interval'] = int(interval)
-                if detect_group:
-                    qs_data['detect_group'] = detect_group
+                    qs_data['detect_group'] = detect_group if detect_group else ''
                 uid_set_qs.update(**qs_data)
                 uid_set_qs.update(**qs_data)
             else:
             else:
                 qs_data = {
                 qs_data = {
@@ -187,23 +166,23 @@ class AiView(View):
                 }
                 }
                 if interval:
                 if interval:
                     qs_data['detect_interval'] = int(interval)
                     qs_data['detect_interval'] = int(interval)
-                if detect_group:
-                    qs_data['detect_group'] = detect_group
+                qs_data['detect_group'] = detect_group if detect_group else ''
                 # 添加设备配置
                 # 添加设备配置
                 uid_set_qs = UidSetModel.objects.create(**qs_data)
                 uid_set_qs = UidSetModel.objects.create(**qs_data)
                 uid_set_id = uid_set_qs.id
                 uid_set_id = uid_set_qs.id
 
 
-            qs_data['detect_status'] = status       # ai开关状态
+            qs_data['detect_status'] = status  # ai开关状态
             ai_service_qs.update(**qs_data)
             ai_service_qs.update(**qs_data)
-            topic_name = 'ansjer/generic/{}'.format(uid)
-            if status == 0:     # 关闭
+            thing_name = CommonService.query_serial_with_uid(uid)   # 存在序列号则为使用序列号作为物品名
+            topic_name = 'ansjer/generic/{}'.format(thing_name)
+            if status == 0:  # 关闭
                 # mqtt通知设备关闭AI识别功能
                 # mqtt通知设备关闭AI识别功能
                 msg = {'commandType': 'AIDisable'}
                 msg = {'commandType': 'AIDisable'}
-                req_success = CommonService.req_publish_mqtt_msg(uid, topic_name, msg)
+                req_success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
                 if not req_success:
                 if not req_success:
                     return response.json(10044)
                     return response.json(10044)
                 return response.json(0)
                 return response.json(0)
-            elif status == 1:       # 开启
+            elif status == 1:  # 开启
                 uid_push_qs = UidPushModel.objects.filter(userID_id=userID, m_code=m_code, uid_set__uid=uid)
                 uid_push_qs = UidPushModel.objects.filter(userID_id=userID, m_code=m_code, uid_set__uid=uid)
 
 
                 if uid_push_qs.exists():
                 if uid_push_qs.exists():
@@ -237,7 +216,8 @@ class AiView(View):
                 etkObj = ETkObject(etk='')
                 etkObj = ETkObject(etk='')
                 etk = etkObj.encrypt(uid)
                 etk = etkObj.encrypt(uid)
 
 
-                aiIdentificationUrl = "{DETECT_PUSH_DOMAIN}AiService/identification".format(DETECT_PUSH_DOMAIN=DETECT_PUSH_DOMAINS)
+                aiIdentificationUrl = "{DETECT_PUSH_DOMAIN}AiService/identification".format(
+                    DETECT_PUSH_DOMAIN=DETECT_PUSH_DOMAINS)
 
 
                 # mqtt通知设备开启AI识别功能
                 # mqtt通知设备开启AI识别功能
                 msg = {
                 msg = {
@@ -248,7 +228,7 @@ class AiView(View):
                               'aiIdentificationUrl': aiIdentificationUrl,
                               'aiIdentificationUrl': aiIdentificationUrl,
                           }
                           }
                       },
                       },
-                req_success = CommonService.req_publish_mqtt_msg(uid, topic_name, msg)
+                req_success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
                 if not req_success:
                 if not req_success:
                     return response.json(10044)
                     return response.json(10044)
                 return response.json(0, {'aiIdentificationUrl': aiIdentificationUrl, 'endTime': endTime, 'etk': etk})
                 return response.json(0, {'aiIdentificationUrl': aiIdentificationUrl, 'endTime': endTime, 'etk': etk})
@@ -273,7 +253,9 @@ class AiView(View):
         except Exception as e:
         except Exception as e:
             return response.json(500, repr(e))
             return response.json(500, repr(e))
 
 
-    def do_commodity_list(self, userID, request_dict, response):
+    # 获取AI套餐列表
+    @staticmethod
+    def do_commodity_list(request_dict, response):
         uid = request_dict.get('uid', None)
         uid = request_dict.get('uid', None)
         lang = request_dict.get('lang', 'en')
         lang = request_dict.get('lang', 'en')
 
 
@@ -283,10 +265,18 @@ class AiView(View):
             if device_info_qs.exists():
             if device_info_qs.exists():
                 return response.json(0)
                 return response.json(0)
 
 
+            # 没免费体验过的设备只返回体验套餐数据,体验过的不再返回
+            exc_ai_qs = ExperienceAiModel.objects.filter(uid=uid, experience_type=0)
+            if exc_ai_qs.exists():
+                ai_meal_qs = AiStoreMeal.objects.filter(~Q(pay_type=10))
+            else:
+                ai_meal_qs = AiStoreMeal.objects.filter(pay_type=10)
+
             # 查询套餐数据
             # 查询套餐数据
-            ai_meal_qs = AiStoreMeal.objects.filter(is_show=1, lang__lang=lang).\
-                annotate(ai_meal_id=F('id'), title=F('lang__title'), content=F('lang__content')).\
-                values("ai_meal_id", "title", "content", "price", "effective_day", "currency", "virtual_price", "symbol")
+            ai_meal_qs = ai_meal_qs.filter(is_show=1, lang__lang=lang). \
+                annotate(ai_meal_id=F('id'), title=F('lang__title'), content=F('lang__content')). \
+                values("ai_meal_id", "title", "content", "price", "effective_day", "currency", "virtual_price",
+                       "symbol")
             if not ai_meal_qs.exists():
             if not ai_meal_qs.exists():
                 return response.json(0)
                 return response.json(0)
 
 
@@ -323,8 +313,10 @@ class AiView(View):
             count = omqs.count()
             count = omqs.count()
             omqs = omqs.annotate(rank__title=F('ai_rank__lang__title'), rank__content=F('ai_rank__lang__content'),
             omqs = omqs.annotate(rank__title=F('ai_rank__lang__title'), rank__content=F('ai_rank__lang__content'),
                                  rank__day=F('ai_rank__effective_day'), rank__price=F('ai_rank__price'),
                                  rank__day=F('ai_rank__effective_day'), rank__price=F('ai_rank__price'),
-                                 rank__expire=F('ai_rank__effective_day'), rank__id=F('ai_rank_id'), rank__currency=F('ai_rank__currency'))
-            order_ql = omqs[(page - 1) * line:page * line].values("orderID", "UID", "channel", "desc", "price", "currency",
+                                 rank__expire=F('ai_rank__effective_day'), rank__id=F('ai_rank_id'),
+                                 rank__currency=F('ai_rank__currency'))
+            order_ql = omqs[(page - 1) * line:page * line].values("orderID", "UID", "channel", "desc", "price",
+                                                                  "currency",
                                                                   "addTime",
                                                                   "addTime",
                                                                   "updTime", "paypal", "rank__day", "payType",
                                                                   "updTime", "paypal", "rank__day", "payType",
                                                                   "rank__price", "status",
                                                                   "rank__price", "status",
@@ -366,23 +358,119 @@ class AiView(View):
                 return response.json(0, [])
                 return response.json(0, [])
 
 
             # 计算套餐过期时间
             # 计算套餐过期时间
-            sum_end_time = AiService.objects.filter(Q(uid=uid), ~Q(use_status=2)).aggregate(Sum('endTime'))['endTime__sum']
-            ai_service_qs = ai_service_qs.order_by('addTime').annotate(bucket__content=F('orders__ai_rank__lang__title')).\
+            sum_end_time = AiService.objects.filter(Q(uid=uid), ~Q(use_status=2)).aggregate(Sum('endTime'))[
+                'endTime__sum']
+            ai_service_qs = ai_service_qs.order_by('addTime').annotate(
+                bucket__content=F('orders__ai_rank__lang__title')). \
                 values('uid', 'use_status', 'bucket__content')
                 values('uid', 'use_status', 'bucket__content')
+
             ai_service_data = ai_service_qs[0]
             ai_service_data = ai_service_qs[0]
+            # 如果存在序列号返回完整序列号
+            device_info_qs = Device_Info.objects.filter(UID=uid).values('serial_number', 'Type')
+            serial_number = device_info_qs[0]['serial_number']
+            if serial_number:
+                ai_service_data['uid'] = CommonService.get_full_serial_number(uid, serial_number, device_info_qs[0]['Type'])
+
             ai_service_data['endTime'] = sum_end_time
             ai_service_data['endTime'] = sum_end_time
             return response.json(0, [ai_service_data])
             return response.json(0, [ai_service_data])
         except Exception as e:
         except Exception as e:
             print(e)
             print(e)
             return response.json(500, repr(e))
             return response.json(500, repr(e))
 
 
+    # 体验AI套餐
+    @staticmethod
+    def experience_order(request_dict, userID, response):
+        uid = request_dict.get('uid', None)
+        channel = request_dict.get('channel', None)
+        pay_type = int(request_dict.get('pay_type', None))
+        rank = request_dict.get('rank', None)
+        cdk = request_dict.get('cdk', None)
+        lang = request_dict.get('lang', 'en')
+
+        # 使用redis设置唯一key加锁
+        redisObj = RedisObject()
+        redis_key = uid + 'do_experience_ai_order'
+        isLock = redisObj.CONN.setnx(redis_key, 1)
+        redisObj.CONN.expire(redis_key, 60)
+        if not isLock:
+            return response.json(5)
+        try:
+            if pay_type == 10:  # 判断是否已体验过套餐
+                exc_ai_qs = ExperienceAiModel.objects.filter(uid=uid, experience_type=0)
+                if exc_ai_qs.exists():
+                    return response.json(5)
+
+            if cdk is not None and pay_type == 11:
+                cdk_qs = CDKcontextModel.objects.filter(cdk=cdk).values('is_activate', 'rank__id', 'rank__commodity_code')
+                if not cdk_qs.exists():
+                    return response.json(10040)
+                if cdk_qs[0]['is_activate'] == 1:
+                    return response.json(10039)
+                rank = cdk_qs[0]['rank__id']
+
+            if uid is None or channel is None or pay_type is None or rank is None:
+                redisObj.del_data(key=redis_key)
+                return response.json(444)
+
+            # 判断是否为主用户操作
+            device_info_qs = Device_Info.objects.filter(Q(UID=uid) & ~Q(vodPrimaryUserID='')).values('vodPrimaryUserID')
+            if device_info_qs.exists():
+                if device_info_qs[0]['vodPrimaryUserID'] != userID:
+                    if pay_type == 10:
+                        return response.json(10035)
+                    if pay_type == 11:
+                        return response.json(10036)
+
+            dv_qs = Device_Info.objects.filter(userID_id=userID, UID=uid, isShare=False, isExist=1)
+            if not dv_qs.exists():
+                return response.json(12)
+
+            orderID = CommonService.createOrderID()
+            nowTime = int(time.time())
+            ai_store_meal_qs = AiStoreMeal.objects.filter(id=rank, lang__lang=lang, is_show=1). \
+                values('lang__content', 'price', 'currency', 'effective_day')
+            if not ai_store_meal_qs.exists():
+                return response.json(173)
+
+            effective_day = ai_store_meal_qs[0]['effective_day']
+            endTime = nowTime + effective_day * 24 * 60 * 60  # 套餐结束时间
+
+            with transaction.atomic():
+                # 订单表创建数据
+                Order_Model.objects.create(orderID=orderID, UID=uid, channel=channel, userID_id=userID,
+                                           desc=ai_store_meal_qs[0]['lang__content'], payType=pay_type, payTime=nowTime,
+                                           price=ai_store_meal_qs[0]['price'], currency=ai_store_meal_qs[0]['currency'],
+                                           addTime=nowTime, updTime=nowTime, pay_url='AI体验',
+                                           rank_id=1, ai_rank_id=rank, status=1)
+                # ai服务表创建数据
+                AiService.objects.create(uid=uid, channel=channel, orders_id=orderID, detect_status=1, endTime=endTime,
+                                         addTime=nowTime, updTime=nowTime, use_status=1)
+
+                if pay_type == 10:
+                    ExperienceAiModel.objects.create(
+                        experience_type=0,
+                        uid=uid,
+                        do_time=nowTime
+                    )
+
+                elif pay_type == 11:
+                    CDKcontextModel.objects.filter(cdk=cdk).update(is_activate=1, order=orderID)
+
+                redisObj.del_data(key=redis_key)
+                pay_ok_url = "{}cloudstorage/payOK?paytype={}&lang={}".format(SERVER_DOMAIN_SSL, pay_type, lang)
+                return response.json(0, pay_ok_url)
+        except Exception as e:
+            print(e)
+            redisObj.del_data(key=redis_key)
+            return response.json(474)
+
     def do_create_pay_order(self, request_dict, request, userID, response):
     def do_create_pay_order(self, request_dict, request, userID, response):
         uid = request_dict.get('uid', None)
         uid = request_dict.get('uid', None)
         channel = request_dict.get('channel', None)
         channel = request_dict.get('channel', None)
         pay_type = int(request_dict.get('pay_type', 1))
         pay_type = int(request_dict.get('pay_type', 1))
-        ai_meal_id = request_dict.get('ai_meal_id', None)
+        rank = request_dict.get('rank', None)
         lang = request_dict.get('lang', 'en')
         lang = request_dict.get('lang', 'en')
-        if not uid or not channel or not pay_type or not ai_meal_id:
+        if not uid or not channel or not pay_type or not rank:
             return response.json(444)
             return response.json(444)
 
 
         try:
         try:
@@ -400,7 +488,7 @@ class AiView(View):
             #         return response.json(10033)
             #         return response.json(10033)
 
 
             # 获取ai套餐数据
             # 获取ai套餐数据
-            ai_sm_qs = AiStoreMeal.objects.filter(id=ai_meal_id, pay_type=pay_type, is_show=1, lang__lang=lang). \
+            ai_sm_qs = AiStoreMeal.objects.filter(id=rank, pay_type=pay_type, is_show=1, lang__lang=lang). \
                 values('lang__title', 'lang__content', 'currency', 'price')
                 values('lang__title', 'lang__content', 'currency', 'price')
             if not ai_sm_qs.exists():
             if not ai_sm_qs.exists():
                 return response.json(173)
                 return response.json(173)
@@ -425,20 +513,22 @@ class AiView(View):
                 'currency': currency,
                 'currency': currency,
                 'addTime': nowTime,
                 'addTime': nowTime,
                 'updTime': nowTime,
                 'updTime': nowTime,
-                'ai_rank_id': ai_meal_id,
+                'ai_rank_id': rank,
                 'rank_id': 1,
                 'rank_id': 1,
                 'order_type': 1,
                 'order_type': 1,
             }
             }
 
 
-            if pay_type == 1:       # PayPal支付
-                order_dict['paymentID'], order_dict['pay_url'] = self.create_paypal_payment(lang, orderID, price, currency, content, response)
+            if pay_type == 1:  # PayPal支付
+                order_dict['paymentID'], order_dict['pay_url'] = self.create_paypal_payment(lang, orderID, price,
+                                                                                            currency, content, response)
                 res_data = {'redirectUrl': order_dict['pay_url'], 'orderID': orderID}
                 res_data = {'redirectUrl': order_dict['pay_url'], 'orderID': orderID}
-            elif pay_type == 2:     # 支付宝
+            elif pay_type == 2:  # 支付宝
                 order_dict['pay_url'] = self.create_alipay_payment(lang, orderID, price, title, content, response)
                 order_dict['pay_url'] = self.create_alipay_payment(lang, orderID, price, title, content, response)
                 res_data = {'redirectUrl': order_dict['pay_url'], 'orderID': orderID}
                 res_data = {'redirectUrl': order_dict['pay_url'], 'orderID': orderID}
-            elif pay_type == 3:     # 微信支付
+            elif pay_type == 3:  # 微信支付
                 ip = CommonService.get_ip_address(request)
                 ip = CommonService.get_ip_address(request)
-                order_dict['pay_url'], sign_params = self.create_wechat_payment(lang, orderID, price, ip, content, response)
+                order_dict['pay_url'], sign_params = self.create_wechat_payment(lang, orderID, price, ip, content,
+                                                                                response)
                 res_data = {'redirectUrl': order_dict['pay_url'], 'orderID': orderID, 'result': sign_params}
                 res_data = {'redirectUrl': order_dict['pay_url'], 'orderID': orderID, 'result': sign_params}
             else:
             else:
                 return response.json(444, {'param': 'pay_type'})
                 return response.json(444, {'param': 'pay_type'})
@@ -591,8 +681,8 @@ class AiView(View):
             attach = data["attach"]
             attach = data["attach"]
             parmap = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
             parmap = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
             lang = parmap['lang']
             lang = parmap['lang']
-            trade_status = data['result_code']      # 业务结果  SUCCESS/FAIL
-            orderID = data['out_trade_no']          # 商户订单号
+            trade_status = data['result_code']  # 业务结果  SUCCESS/FAIL
+            orderID = data['out_trade_no']  # 商户订单号
             order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
             order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
             if not order_qs.exists():
             if not order_qs.exists():
                 return response.json(173)
                 return response.json(173)
@@ -634,7 +724,6 @@ class AiView(View):
                            'detect_status': 1,
                            'detect_status': 1,
                            'addTime': nowTime,
                            'addTime': nowTime,
                            'updTime': nowTime,
                            'updTime': nowTime,
-                           'detect_group': '1'
                            }
                            }
         if ai_service_qs.exists():  # 有正在使用的套餐,套餐结束时间保存为套餐有效期
         if ai_service_qs.exists():  # 有正在使用的套餐,套餐结束时间保存为套餐有效期
             ai_service_dict['endTime'] = effective_day * 24 * 60 * 60
             ai_service_dict['endTime'] = effective_day * 24 * 60 * 60
@@ -672,13 +761,13 @@ class AiView(View):
             '2': ['Dog', 'Pet', 'Canine', 'Animal', 'Puppy'],  # 动物
             '2': ['Dog', 'Pet', 'Canine', 'Animal', 'Puppy'],  # 动物
             '3': ['Car', 'Vehicle', 'Transportation', 'Automobile']  # 车
             '3': ['Car', 'Vehicle', 'Transportation', 'Automobile']  # 车
         }
         }
-        #找出识别的所有标签
+        # 找出识别的所有标签
         for label in labels:
         for label in labels:
             label_name.append(label['Name'])
             label_name.append(label['Name'])
             for Parents in label['Parents']:
             for Parents in label['Parents']:
                 label_name.append(Parents['Name'])
                 label_name.append(Parents['Name'])
 
 
-        #删除用户没有选择的ai识别类型, 并且得出最终识别结果
+        # 删除用户没有选择的ai识别类型, 并且得出最终识别结果
         user_detect_list = user_detect_group.split(',')
         user_detect_list = user_detect_group.split(',')
         user_detect_list = [i.strip() for i in user_detect_list]
         user_detect_list = [i.strip() for i in user_detect_list]
         label_result_list = []
         label_result_list = []
@@ -690,56 +779,56 @@ class AiView(View):
                     if label in label_name:
                     if label in label_name:
                         label_result_list.append(label)
                         label_result_list.append(label)
 
 
-        #找出标签边框线位置信息
+        # 找出标签边框线位置信息
         boundingBoxList = []
         boundingBoxList = []
         for label in labels:
         for label in labels:
             if label['Name'] in label_result_list:
             if label['Name'] in label_result_list:
                 for boundingBox in label['Instances']:
                 for boundingBox in label['Instances']:
                     boundingBoxList.append(boundingBox['BoundingBox'])
                     boundingBoxList.append(boundingBox['BoundingBox'])
 
 
-        #找出边框位置信息对应的单图位置并重新计算位置比
+        # 找出边框位置信息对应的单图位置并重新计算位置比
         merge_image_height = image_size['height']
         merge_image_height = image_size['height']
         merge_image_width = image_size['width']
         merge_image_width = image_size['width']
-        single_height = merge_image_height//image_size['num']
+        single_height = merge_image_height // image_size['num']
         new_bounding_box_dict = {}
         new_bounding_box_dict = {}
-        new_bounding_box_dict[n_time+'_0'] = []
-        new_bounding_box_dict[n_time+'_1'] = []
-        new_bounding_box_dict[n_time+'_2'] = []
-        new_bounding_box_dict[n_time+'_3'] = []
+        new_bounding_box_dict[n_time + '_0'] = []
+        new_bounding_box_dict[n_time + '_1'] = []
+        new_bounding_box_dict[n_time + '_2'] = []
+        new_bounding_box_dict[n_time + '_3'] = []
         for k, val in enumerate(boundingBoxList):
         for k, val in enumerate(boundingBoxList):
             boundingBoxTop = merge_image_height * val['Top']
             boundingBoxTop = merge_image_height * val['Top']
-            #找出当前边框属于哪张图片范围
+            # 找出当前边框属于哪张图片范围
             boxDict = {}
             boxDict = {}
             for i in range(image_size['num']):
             for i in range(image_size['num']):
-                min = i*single_height       #第n张图
-                max = (i+1)*single_height
+                min = i * single_height  # 第n张图
+                max = (i + 1) * single_height
                 if boundingBoxTop >= min and boundingBoxTop <= max:
                 if boundingBoxTop >= min and boundingBoxTop <= max:
                     # print("属于第{i}张图".format(i=i+1))
                     # print("属于第{i}张图".format(i=i+1))
                     boxDict['Width'] = val['Width']
                     boxDict['Width'] = val['Width']
-                    boxDict['Height'] = merge_image_height*val['Height']/single_height
-                    boxDict['Top'] = ((merge_image_height*val['Top'])-(i*single_height))/single_height #减去前i张图片的高度
+                    boxDict['Height'] = merge_image_height * val['Height'] / single_height
+                    boxDict['Top'] = ((merge_image_height * val['Top']) - (
+                                i * single_height)) / single_height  # 减去前i张图片的高度
                     boxDict['Left'] = val['Left']
                     boxDict['Left'] = val['Left']
-                    boxDict['picName'] = "{n_time}_{i}".format(n_time=n_time,i=i)
+                    boxDict['picName'] = "{n_time}_{i}".format(n_time=n_time, i=i)
                     # new_bounding_box_list.append(boxDict)
                     # new_bounding_box_list.append(boxDict)
                     # new_bounding_box_list.append(boxDict)
                     # new_bounding_box_list.append(boxDict)
-                    new_bounding_box_dict["{n_time}_{i}".format(n_time=n_time,i=i)].append(boxDict)
+                    new_bounding_box_dict["{n_time}_{i}".format(n_time=n_time, i=i)].append(boxDict)
         # exit(new_bounding_box_list)
         # exit(new_bounding_box_list)
         user_labels_list = list(new_labels_type.keys())
         user_labels_list = list(new_labels_type.keys())
         user_labels_list.sort()
         user_labels_list.sort()
         return {'label_type': user_labels_list, 'label_list': label_result_list,
         return {'label_type': user_labels_list, 'label_list': label_result_list,
-                'new_bounding_box_dict':new_bounding_box_dict}
-
+                'new_bounding_box_dict': new_bounding_box_dict}
 
 
     def upload_s3(self, file_path, upload_path):
     def upload_s3(self, file_path, upload_path):
         try:
         try:
-            aws_key = "AKIA2E67UIMD45Y3HL53" #【你的 aws_access_key】
-            aws_secret = "ckYLg4Lo9ZXJIcJEAKkzf2rWvs8Xth1FCjqiAqUw" # 【你的 aws_secret_key】
+            aws_key = "AKIA2E67UIMD45Y3HL53"  # 【你的 aws_access_key】
+            aws_secret = "ckYLg4Lo9ZXJIcJEAKkzf2rWvs8Xth1FCjqiAqUw"  # 【你的 aws_secret_key】
             session = Session(aws_access_key_id=aws_key,
             session = Session(aws_access_key_id=aws_key,
                               aws_secret_access_key=aws_secret,
                               aws_secret_access_key=aws_secret,
                               region_name="us-east-1")
                               region_name="us-east-1")
             s3 = session.resource("s3")
             s3 = session.resource("s3")
             # client = session.client("s3")
             # client = session.client("s3")
-            bucket = "foreignpush" # 【你 bucket 的名字】 # 首先需要保.证 s3 上已经存在该存储桶,否则报错
+            bucket = "foreignpush"  # 【你 bucket 的名字】 # 首先需要保.证 s3 上已经存在该存储桶,否则报错
             upload_data = open(file_path, "rb")
             upload_data = open(file_path, "rb")
             # upload_key = "test"
             # upload_key = "test"
             s3.Bucket(bucket).put_object(Key=upload_path, Body=upload_data)
             s3.Bucket(bucket).put_object(Key=upload_path, Body=upload_data)
@@ -768,7 +857,7 @@ class AiView(View):
             return nickname
             return nickname
 
 
     def get_msg_text(self, channel, n_time, lang, tz, label_list):
     def get_msg_text(self, channel, n_time, lang, tz, label_list):
-        n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz,lang=lang)
+        n_date = CommonService.get_now_time_str(n_time=n_time, tz=tz, lang=lang)
         if lang == 'cn':
         if lang == 'cn':
             msg = '摄像头AI识别到了{}'.format(label_list)
             msg = '摄像头AI识别到了{}'.format(label_list)
             send_text = '{msg} 通道:{channel} 日期:{date}'.format(msg=msg, channel=channel, date=n_date)
             send_text = '{msg} 通道:{channel} 日期:{date}'.format(msg=msg, channel=channel, date=n_date)
@@ -815,7 +904,6 @@ class AiView(View):
         except Exception as e:
         except Exception as e:
             return 'serverKey abnormal'
             return 'serverKey abnormal'
 
 
-
     def do_apns(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
     def do_apns(self, uid, channel, appBundleId, token_val, event_type, n_time, msg_title, msg_text):
         logger = logging.getLogger('info')
         logger = logging.getLogger('info')
         logger.info("进来do_apns函数了")
         logger.info("进来do_apns函数了")
@@ -823,7 +911,8 @@ class AiView(View):
         logger.info(APNS_MODE)
         logger.info(APNS_MODE)
         logger.info(os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
         logger.info(os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
         try:
         try:
-            cli = apns2.APNSClient(mode=APNS_MODE, client_cert=os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
+            cli = apns2.APNSClient(mode=APNS_MODE,
+                                   client_cert=os.path.join(BASE_DIR, APNS_CONFIG[appBundleId]['pem_path']))
             push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
             push_data = {"alert": "Motion ", "event_time": n_time, "event_type": event_type, "msg": "",
                          "received_at": n_time, "sound": "", "uid": uid, "zpush": "1", "channel": channel}
                          "received_at": n_time, "sound": "", "uid": uid, "zpush": "1", "channel": channel}
             alert = apns2.PayloadAlert(body=msg_text, title=msg_title)
             alert = apns2.PayloadAlert(body=msg_text, title=msg_title)
@@ -854,7 +943,7 @@ class AiView(View):
         eventType = request_dict.get('eventType', None)
         eventType = request_dict.get('eventType', None)
 
 
         now_time = int(time.time())
         now_time = int(time.time())
-        seven_days_ago = now_time - 7 * 24 * 3600   # 查询7天内的数据
+        seven_days_ago = now_time - 7 * 24 * 3600  # 查询7天内的数据
         qs = Ai_Push_Info.objects.filter(userID_id=userID, eventTime__gt=seven_days_ago).order_by('-eventTime')
         qs = Ai_Push_Info.objects.filter(userID_id=userID, eventTime__gt=seven_days_ago).order_by('-eventTime')
 
 
         if startTime and endTime:
         if startTime and endTime:
@@ -903,17 +992,17 @@ class AiView(View):
                 s3_img_cover = '{uid}/{channel}/cover{time}.jpg'.format(uid=devUid, channel=channel, time=eventTime)
                 s3_img_cover = '{uid}/{channel}/cover{time}.jpg'.format(uid=devUid, channel=channel, time=eventTime)
                 s3_img_desc = '{uid}/{channel}/desc{time}.jpg'.format(uid=devUid, channel=channel, time=eventTime)
                 s3_img_desc = '{uid}/{channel}/desc{time}.jpg'.format(uid=devUid, channel=channel, time=eventTime)
                 response_url_cover = aws_s3_client.generate_presigned_url('get_object',
                 response_url_cover = aws_s3_client.generate_presigned_url('get_object',
-                                                                    ExpiresIn=300,
-                                                                    Params={
-                                                                        'Bucket': 'aipush', 'Key': s3_img_cover
-                                                                    },
-                                                                    )
-                response_url_desc = aws_s3_client.generate_presigned_url('get_object',
                                                                           ExpiresIn=300,
                                                                           ExpiresIn=300,
                                                                           Params={
                                                                           Params={
-                                                                              'Bucket': 'aipush', 'Key': s3_img_desc
+                                                                              'Bucket': 'aipush', 'Key': s3_img_cover
                                                                           },
                                                                           },
                                                                           )
                                                                           )
+                response_url_desc = aws_s3_client.generate_presigned_url('get_object',
+                                                                         ExpiresIn=300,
+                                                                         Params={
+                                                                             'Bucket': 'aipush', 'Key': s3_img_desc
+                                                                         },
+                                                                         )
                 p['img'] = response_url_cover
                 p['img'] = response_url_cover
                 p['img_list'] = [response_url_desc]
                 p['img_list'] = [response_url_desc]
 
 
@@ -923,13 +1012,14 @@ class AiView(View):
                 # 列表装载回放时间戳标记
                 # 列表装载回放时间戳标记
                 p['img_list'] = []
                 p['img_list'] = []
                 for i in range(4):
                 for i in range(4):
-                    thumbspng = '{uid}/{channel}/{time}_{st}.jpg'.format(uid=devUid, channel=p['Channel'], time=eventTime, st=i)
+                    thumbspng = '{uid}/{channel}/{time}_{st}.jpg'.format(uid=devUid, channel=p['Channel'],
+                                                                         time=eventTime, st=i)
                     response_url = aws_s3_client.generate_presigned_url('get_object',
                     response_url = aws_s3_client.generate_presigned_url('get_object',
-                                                                             ExpiresIn=300,
-                                                                             Params={
-                                                                                 'Bucket': 'aipush', 'Key': thumbspng
-                                                                             },
-                                                                             )
+                                                                        ExpiresIn=300,
+                                                                        Params={
+                                                                            'Bucket': 'aipush', 'Key': thumbspng
+                                                                        },
+                                                                        )
                     p['img_list'].append(response_url)
                     p['img_list'].append(response_url)
 
 
             if devUid in uid_type_dict.keys():
             if devUid in uid_type_dict.keys():
@@ -944,18 +1034,18 @@ class AiView(View):
         is_update_all = request_dict.get('is_update_all', 0)
         is_update_all = request_dict.get('is_update_all', 0)
 
 
         try:
         try:
-            if int(is_update_all) == 1:     # 全部已读
+            if int(is_update_all) == 1:  # 全部已读
                 is_update = Ai_Push_Info.objects.filter(userID_id=userID).update(status=1)
                 is_update = Ai_Push_Info.objects.filter(userID_id=userID).update(status=1)
                 return response.json(0, {'update_count': is_update})
                 return response.json(0, {'update_count': is_update})
             else:
             else:
                 id_list = request_dict.get('id_list', None)
                 id_list = request_dict.get('id_list', None)
                 if not id_list:
                 if not id_list:
-                    request_dict.getlist('id_list[]', None)     # 获取IOS数组传参
+                    request_dict.getlist('id_list[]', None)  # 获取IOS数组传参
                 logger = logging.getLogger('info')
                 logger = logging.getLogger('info')
                 logger.info('已读ai消息id_list:{}'.format(id_list))
                 logger.info('已读ai消息id_list:{}'.format(id_list))
                 if not id_list:
                 if not id_list:
                     return response.json(444)
                     return response.json(444)
-                id_list = eval(id_list)     # 字符串转列表
+                id_list = eval(id_list)  # 字符串转列表
                 param_flag = CommonService.get_param_flag(data=id_list)
                 param_flag = CommonService.get_param_flag(data=id_list)
                 if not param_flag:
                 if not param_flag:
                     return response.json(444)
                     return response.json(444)
@@ -995,5 +1085,3 @@ class AiView(View):
         except Exception as e:
         except Exception as e:
             print(e)
             print(e)
             return response.json(500, repr(e))
             return response.json(500, repr(e))
-
-

+ 62 - 10
Controller/AppSetController.py

@@ -12,13 +12,15 @@
 @Contact: chanjunkai@163.com
 @Contact: chanjunkai@163.com
 """
 """
 from Ansjer.config import SERVER_TYPE
 from Ansjer.config import SERVER_TYPE
-from Model.models import AppSetModel,PromotionRuleModel
+from Model.models import AppSetModel, PromotionRuleModel, PopupsConfig, RedDotsConfig
 from django.views.generic.base import View
 from django.views.generic.base import View
 from Object.RedisObject import RedisObject
 from Object.RedisObject import RedisObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
 from Service.ModelService import ModelService
 from Service.ModelService import ModelService
-import time,json
+import time, json
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
+
+
 class AppSetView(View):
 class AppSetView(View):
     def get(self, request, *args, **kwargs):
     def get(self, request, *args, **kwargs):
         request.encoding = 'utf-8'
         request.encoding = 'utf-8'
@@ -51,7 +53,14 @@ class AppSetView(View):
             else:
             else:
                 return response.json(tko.code)
                 return response.json(tko.code)
         else:
         else:
-            return response.json(414)
+            token = request_dict.get('token', None)
+            tko = TokenObject(token)
+            if tko.code == 0:
+                userID = tko.userID
+                if operation == 'page_set':  # app弹窗标记红点设置
+                    return self.do_page_set(userID, request_dict, response)
+            else:
+                return response.json(tko.code)
 
 
     # 查询
     # 查询
     def do_query(self, request_dict, response):
     def do_query(self, request_dict, response):
@@ -67,12 +76,13 @@ class AppSetView(View):
             if not app_set_qs[0]['content']:
             if not app_set_qs[0]['content']:
                 return response.json(0)
                 return response.json(0)
             dict_json = json.loads(app_set_qs[0]['content'])
             dict_json = json.loads(app_set_qs[0]['content'])
-            #加入促销弹窗
-            promotion = PromotionRuleModel.objects.filter(status=1).values('startTime','endTime','popups')
+
+            # 加入促销弹窗
+            promotion = PromotionRuleModel.objects.filter(status=1).values('startTime', 'endTime', 'popups')
             if promotion.exists():
             if promotion.exists():
                 dict_json['popupsStartTime'] = promotion[0]['startTime']
                 dict_json['popupsStartTime'] = promotion[0]['startTime']
                 dict_json['popupsEndTime'] = promotion[0]['endTime']
                 dict_json['popupsEndTime'] = promotion[0]['endTime']
-                dict_json['popupsContent'] = json.loads(promotion[0]['popups']).get(lang,'')
+                dict_json['popupsContent'] = json.loads(promotion[0]['popups']).get(lang, '')
                 dict_json['nowTime'] = int(time.time())
                 dict_json['nowTime'] = int(time.time())
             if 'editionUpgrading' in dict_json:
             if 'editionUpgrading' in dict_json:
                 if dict_json['editionUpgrading'] == 1:
                 if dict_json['editionUpgrading'] == 1:
@@ -82,9 +92,11 @@ class AppSetView(View):
                         dict_json['editionUpgrading'] = 'Upgrading, please sign in later'
                         dict_json['editionUpgrading'] = 'Upgrading, please sign in later'
                 else:
                 else:
                     dict_json['editionUpgrading'] = ''
                     dict_json['editionUpgrading'] = ''
+
             return response.json(0, dict_json)
             return response.json(0, dict_json)
         except Exception as e:
         except Exception as e:
-            return response.json(500, repr(e))
+            return response.json(500, "错误行数:{errLine}, 错误信息: {errmsg}".format(errLine=e.__traceback__.tb_lineno,
+                                                                              errmsg=repr(e)))
 
 
         # res = {}
         # res = {}
         # res['grade'] = 1
         # res['grade'] = 1
@@ -115,7 +127,7 @@ class AppSetView(View):
         sm_qs = AppSetModel.objects.filter(appBundleId=appBundleId)
         sm_qs = AppSetModel.objects.filter(appBundleId=appBundleId)
         count = sm_qs.count()
         count = sm_qs.count()
         nowTime = int(time.time())
         nowTime = int(time.time())
-        if count>0:
+        if count > 0:
             sm_qs = sm_qs.values('id', 'appBundleId', 'content', 'addTime', 'updTime')
             sm_qs = sm_qs.values('id', 'appBundleId', 'content', 'addTime', 'updTime')
             return response.json(0, {'data': list(sm_qs), 'count': count})
             return response.json(0, {'data': list(sm_qs), 'count': count})
         else:
         else:
@@ -137,7 +149,7 @@ class AppSetView(View):
         sm_qs = AppSetModel.objects.filter(appBundleId=appBundleId)
         sm_qs = AppSetModel.objects.filter(appBundleId=appBundleId)
         redis = RedisObject()
         redis = RedisObject()
         if SERVER_TYPE != "Ansjer.formal_settings":
         if SERVER_TYPE != "Ansjer.formal_settings":
-            key_id= "www"+appBundleId
+            key_id = "www" + appBundleId
         else:
         else:
             key_id = "test" + appBundleId
             key_id = "test" + appBundleId
         redis.del_data(key=key_id)
         redis.del_data(key=key_id)
@@ -145,4 +157,44 @@ class AppSetView(View):
             sm_qs.update(content=content, updTime=nowTime)
             sm_qs.update(content=content, updTime=nowTime)
             return response.json(0)
             return response.json(0)
         else:
         else:
-            return response.json(173)
+            return response.json(173)
+
+    def do_page_set(self, userID, request_dict, response):
+        lang = request_dict.get('lang', 'en')
+        dict_json = {}
+        now_time = int(time.time())
+        dict_json['popups'] = {
+            'title': '',
+            'content': '',
+            'status': 0,
+            'tag': 1,
+        }
+        #弹窗
+        popups_obj = PopupsConfig.objects.filter(lang=lang).values('title','content','start_time','end_time','tag')
+        if popups_obj.exists:
+            popups_status = 0
+            if now_time >= popups_obj[0]['start_time'] and now_time <= popups_obj[0]['end_time']:
+                popups_status = 1
+            dict_json['popups'] = {
+                'title': popups_obj[0]['title'],
+                'content': popups_obj[0]['content'],
+                'status': popups_status,
+                'tag': popups_obj[0]['tag'],
+            }
+
+        #红点标记
+        dict_json['red_dots'] = []
+        red_dots_obj = RedDotsConfig.objects.values('module','start_time','end_time')
+        for red_dots in red_dots_obj:
+            red_dots_status = 0
+            if now_time >= red_dots['start_time'] and now_time <= red_dots['end_time']:
+                red_dots_status = 1
+            dict_json['red_dots'].append({
+                'module': red_dots['module'],
+                'status': red_dots_status,
+            })
+
+
+
+        dict_json['red_dots'] = list(dict_json['red_dots'])
+        return response.json(0, dict_json)

+ 31 - 190
Controller/CloudStorage.py

@@ -42,7 +42,8 @@ from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, OSS_ROLE_AR
 from Controller.CheckUserData import DataValid
 from Controller.CheckUserData import DataValid
 from Model.models import Device_Info, Order_Model, Store_Meal, VodHlsModel, OssCrdModel, UID_Bucket, StsCrdModel, \
 from Model.models import Device_Info, Order_Model, Store_Meal, VodHlsModel, OssCrdModel, UID_Bucket, StsCrdModel, \
     ExperienceContextModel, Pay_Type, CDKcontextModel, Device_User, SysMassModel, SysMsgModel, UidPushModel, \
     ExperienceContextModel, Pay_Type, CDKcontextModel, Device_User, SysMassModel, SysMsgModel, UidPushModel, \
-    Unused_Uid_Meal, UIDMainUser, UserModel, PromotionRuleModel, VideoPlaybackTimeModel, CloudLogModel, CouponModel, VodBucketModel
+    Unused_Uid_Meal, UIDMainUser, UserModel, PromotionRuleModel, VideoPlaybackTimeModel, CloudLogModel, CouponModel, \
+    VodBucketModel, UIDModel
 from Object.AWS.S3Email import S3Email
 from Object.AWS.S3Email import S3Email
 from Object.AliPayObject import AliPayObject
 from Object.AliPayObject import AliPayObject
 from Object.AliSmsObject import AliSmsObject
 from Object.AliSmsObject import AliSmsObject
@@ -60,6 +61,7 @@ from Ansjer.config import SERVER_TYPE
 from Service.ModelService import ModelService
 from Service.ModelService import ModelService
 
 
 # SERVER_DOMAIN = 'http://test.dvema.com/'
 # SERVER_DOMAIN = 'http://test.dvema.com/'
+from Service.PayService import PaymentService
 
 
 '''
 '''
 生成订单
 生成订单
@@ -625,184 +627,15 @@ class CloudStorageView(View):
 
 
     def do_pay_error(self):
     def do_pay_error(self):
         response = HttpResponse()
         response = HttpResponse()
-        response.content = '''
-<!DOCTYPE html>
-<html>
-<head>
-	<!--浏览器不缓存-->
-	<meta http-equiv="Pragma" content="no-cache">
-	<meta http-equiv="Cache-Control" content="no-cache">
-	<meta http-equiv="Expires" content="0">
-	<!--utf-8-->
-    <meta http-equiv="content-type" content="text/html;charset=utf-8">
-    <!-- viewport的<meta>标签,这个标签可以修改在大部分的移动设备上面的显示,为了确保适当的绘制和触屏缩放。-->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <link rel="shortcut icon" href="https://test.zositechc.cn/web/images/favicon.ico" type="image/x-icon"  charset="utf-8"/>  
-    <title>Trading particulars</title>
-    <style>
-    	.title_head{
-    		height: 50px;
-    		border-radius: 5px;
-    		background-color: #c3c6c7; 
-    		text-align: center;
-    		line-height: 50px;
-    	}
-    	.content{
-    		text-align: center;
-    		margin-top: 50px;
-    		font-size: 20px;
-    		color : #ec7648
-    	}
-    	.content_img{
-    		width: 60px; 
-    		height: 60px;
-    	}
-    	.bottom{
-    		 margin-bottom: 10px; 
-    		 margin-top: 250px; 
-    		 color : #ec7648
-    	}
-    	.bottom_div{
-    		border: 1px solid #ec7648; 
-    		line-height: 38px; 
-    		text-align: center; 
-    		width: 100px; 
-    		height: 38px;
-    		border-radius: 5px;
-    	}
-    	
-    	.bottom_div:hover{
-    		background-color: #dde4e2;
-    	}
-    </style>
-</head>
-<body>
-	<div class="title_head">Trading particulars</div>
-    <div class="content">
-    	<p >
-    		<img src="https://test.zositechc.cn/web/images/failed.jpg" class="content_img">
-    		<br />
-    		Payment failure
-    	</p>
-    </div>
-    <center class="bottom">
-    	<div class="bottom_div" onclick="payOKButton()"> 
-    	 Finish
-    	</div>
-    </center>
-    <script> 	    // 点击付款成功按钮
-    function payOKButton() {
-        // 复杂数据
-        console.log('success')
-        window.location.href="https://www.baidu.com?page=closePage";
-    }
-	</script>
-</body> 
-</html>
-                '''
+        response.content = PaymentService.get_pay_error_content()
         return response
         return response
 
 
     def do_pay_ok(self, request_dict):  # 支付成功
     def do_pay_ok(self, request_dict):  # 支付成功
         response = HttpResponse()
         response = HttpResponse()
-        paytype = request_dict.get('paytype', None)
         lang = request_dict.get('lang', 'en')
         lang = request_dict.get('lang', 'en')
+        pay_type = request_dict.get('paytype', None)
 
 
-        showtitle = "支付成功"
-        if paytype == "10" :
-            showtitle = "成功体验云存"
-
-        if paytype == "11":
-            showtitle = "兑换成功"
-
-        wancheng = '完成'
-        if lang != 'cn':
-            showtitle = "Payment successful"
-            if paytype == "10":
-                showtitle = "Successful experience of cloud storage"
-
-            if paytype == "11":
-                showtitle = "Successful exchange"
-
-            wancheng = 'complete'
-        response.content = '''
-        
-<html>
-<head>
-        <!--浏览器不缓存-->
-        <meta http-equiv="Pragma" content="no-cache">
-        <meta http-equiv="Cache-Control" content="no-cache">
-        <meta http-equiv="Expires" content="0">
-        <!--utf-8-->
-    <meta http-equiv="content-type" content="text/html;charset=utf-8">
-    <!-- viewport的<meta>标签,这个标签可以修改在大部分的移动设备上面的显示,为了确保适当的绘制和触屏缩放。-->
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <link rel="shortcut icon" href="https://test.zositechc.cn/web/images/favicon.ico" type="image/x-icon" charset="utf-8">  
-    <title>''' + showtitle + '''</title>
-    <style>
-            .title_head{
-                    height: 50px;
-                    border-radius: 5px;
-                    background-color: #c3c6c7; 
-                    text-align: center;
-                    line-height: 50px;
-            }
-            .content{
-                    text-align: center;
-                    margin-top: 50px;
-                    font-size: 15px;
-                    color:#0000008A;
-					
-            }
-            .content_img{
-					margin-bottom:15px;
-                    width: 60px; 
-                    height: 60px;
-            }
-            .bottom{
-                     margin-bottom: 10px; 
-                     margin-top: 250px; 
-                     color : white;
-            }
-            .bottom_div{
-                    border: 1px solid #68c9c5; 
-                    line-height: 38px; 
-                    text-align: center; 
-                    width: 100px; 
-                    height: 38px;
-                    border-radius: 30px;
-					background-color:#68c9c5; 
-            }
-            
-            .bottom_div:hover{
-                    background-color: #dde4e2;
-            }
-    </style>
-</head>
-<body style="" rlt="1" inmaintabuse="true">
-        
-    <div class="content">
-            <p>
-					<img src="https://test.zositechc.cn/web/images/success.png" class="content_img">
-                    <br>
-                    ''' + showtitle + '''
-            </p>
-    </div>
-    <center class="bottom">
-            <div class="bottom_div" onclick="payOKButton()"> 
-             '''+wancheng+'''
-            </div>
-    </center>
-    <script src="//hm.baidu.com/hm.js?eaa57ca47dacb4ad4f5a257001a3457c"></script><script>             // 点击付款成功按钮
-    function payOKButton() {
-        // 复杂数据
-        console.log('success')
-        window.location.href="https://www.baidu.com?page=closePage"  
-    }
-        </script>
- 
-
-        <div id="qds" style="display:none;"></div></body></html>
-        '''
+        response.content = PaymentService.get_pay_ok_content(lang, pay_type)
         return response
         return response
 
 
     def do_pay_by_ali_callback(self, request):  # 阿里支付回调
     def do_pay_by_ali_callback(self, request):  # 阿里支付回调
@@ -902,7 +735,7 @@ class CloudStorageView(View):
 
 
                     # 核销coupon
                     # 核销coupon
                     if order_list[0]['coupon_id']:
                     if order_list[0]['coupon_id']:
-                        CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
+                        CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2, update_time=nowTime)
 
 
                     order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                     order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                     datetime = time.strftime("%Y-%m-%d", time.localtime())
                     datetime = time.strftime("%Y-%m-%d", time.localtime())
@@ -1052,7 +885,7 @@ class CloudStorageView(View):
 
 
                 # 核销coupon
                 # 核销coupon
                 if order_list[0]['coupon_id']:
                 if order_list[0]['coupon_id']:
-                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
+                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2, update_time=nowTime)
 
 
                 order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                 order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                 datetime = time.strftime("%Y-%m-%d", time.localtime())
                 datetime = time.strftime("%Y-%m-%d", time.localtime())
@@ -1182,7 +1015,7 @@ class CloudStorageView(View):
 
 
                     # 核销coupon
                     # 核销coupon
                     if order_list[0]['coupon_id']:
                     if order_list[0]['coupon_id']:
-                        CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
+                        CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2, update_time=nowTime)
 
 
                     order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                     order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id, promotion_rule_id=promotion_rule_id)
                     datetime = time.strftime("%Y-%m-%d", time.localtime())
                     datetime = time.strftime("%Y-%m-%d", time.localtime())
@@ -1271,16 +1104,16 @@ class CloudStorageView(View):
         orderID = CommonService.createOrderID()
         orderID = CommonService.createOrderID()
         #优惠券
         #优惠券
         if coupon_id:
         if coupon_id:
-            couponObj = CouponModel.objects.filter(id=coupon_id, use_status=0, distributeTime__lte=nowTime,
+            couponObj = CouponModel.objects.filter(id=coupon_id, use_status=0, distribute_time__lte=nowTime,
                                                    valid_time__gt=nowTime)
                                                    valid_time__gt=nowTime)
-            couponQuery = couponObj.values("id", "type", "coupon_discount")
+            couponQuery = couponObj.values("id", "coupon_config__type", "coupon_config__coupon_discount")
             if not couponQuery.exists():
             if not couponQuery.exists():
                 return response.json(10049)
                 return response.json(10049)
             price = Decimal(price)
             price = Decimal(price)
-            coupon_discount = Decimal(couponQuery[0]['coupon_discount'])
-            if couponQuery[0]['type'] == 1:  #打折
+            coupon_discount = Decimal(couponQuery[0]['coupon_config__coupon_discount'])
+            if couponQuery[0]['coupon_config__type'] == 1:  #打折
                 price = coupon_discount/10 * price
                 price = coupon_discount/10 * price
-            elif couponQuery[0]['type'] == 2:  #抵扣
+            elif couponQuery[0]['coupon_config__type'] == 2:  #抵扣
                 price = price - coupon_discount
                 price = price - coupon_discount
         price = float(price)
         price = float(price)
         if price < 0 or price == 0 or price < 0.01:
         if price < 0 or price == 0 or price < 0.01:
@@ -1305,7 +1138,7 @@ class CloudStorageView(View):
                                            rank_id=rank, plan_id=subInfo['plan_id'],coupon_id=coupon_id,ai_rank_id=1)
                                            rank_id=rank, plan_id=subInfo['plan_id'],coupon_id=coupon_id,ai_rank_id=1)
                 # if coupon_id:
                 # if coupon_id:
                 #     #冻结优惠券
                 #     #冻结优惠券
-                #     CouponModel.objects.filter(id=coupon_id, use_status=0, distributeTime__lte=nowTime,
+                #     CouponModel.objects.filter(id=coupon_id, use_status=0, distribute_time__lte=nowTime,
                 #                                            valid_time__gt=nowTime).update(use_status=1)
                 #                                            valid_time__gt=nowTime).update(use_status=1)
 
 
                 return response.json(0, {"redirectUrl": subInfo['url'], "orderID": orderID})
                 return response.json(0, {"redirectUrl": subInfo['url'], "orderID": orderID})
@@ -1620,7 +1453,7 @@ class CloudStorageView(View):
         uid = request_dict.get('uid', None)
         uid = request_dict.get('uid', None)
         lang = request_dict.get('lang', 'en')
         lang = request_dict.get('lang', 'en')
         dv_qs = Device_Info.objects.filter(userID_id=userID, UID=uid, isShare=False, isExist=1) \
         dv_qs = Device_Info.objects.filter(userID_id=userID, UID=uid, isShare=False, isExist=1) \
-            .values('vodPrimaryUserID')
+            .values('vodPrimaryUserID', 'serial_number', 'Type')
         if not dv_qs.exists() or dv_qs[0]['vodPrimaryUserID'] != userID:
         if not dv_qs.exists() or dv_qs[0]['vodPrimaryUserID'] != userID:
             return response.json(12)
             return response.json(12)
         now_time = int(time.time())
         now_time = int(time.time())
@@ -1630,6 +1463,14 @@ class CloudStorageView(View):
                                                                     "use_status","endTime","has_unused","bucket__id")
                                                                     "use_status","endTime","has_unused","bucket__id")
         if not uid_bucket:
         if not uid_bucket:
             return response.json(10030)
             return response.json(10030)
+
+        # 如果存在序列号返回完整序列号
+        device_id = uid
+        serial_number = dv_qs[0]['serial_number']
+        if serial_number:
+            device_id = CommonService.get_full_serial_number(uid, serial_number, dv_qs[0]['Type'])
+
+        uid_bucket[0]['uid'] = device_id
         uid_bucket[0]['storage'] = 0
         uid_bucket[0]['storage'] = 0
         has_unused = uid_bucket[0]['has_unused']
         has_unused = uid_bucket[0]['has_unused']
         del uid_bucket[0]['has_unused']
         del uid_bucket[0]['has_unused']
@@ -1645,13 +1486,13 @@ class CloudStorageView(View):
                     month += 's'
                     month += 's'
                 storage = "{storage_time}{month}".format(storage_time=storage_time, month=month)
                 storage = "{storage_time}{month}".format(storage_time=storage_time, month=month)
                 unused_dict = {
                 unused_dict = {
-                    "id":ub['unused_id'],
-                    "uid":ub['uid'],
-                    "bucket__content":ub['bucket__content'],
-                    "use_status":0,
-                    "endTime":0,
-                    "bucket__id":ub['bucket__id'],
-                    "storage":storage,
+                    "id": ub['unused_id'],
+                    "uid": device_id,
+                    "bucket__content": ub['bucket__content'],
+                    "use_status": 0,
+                    "endTime": 0,
+                    "bucket__id": ub['bucket__id'],
+                    "storage": storage,
                 }
                 }
                 store_list.append(unused_dict)
                 store_list.append(unused_dict)
                 bucket_id_list.append(ub['bucket__id'])
                 bucket_id_list.append(ub['bucket__id'])

+ 59 - 38
Controller/CouponController.py

@@ -6,7 +6,7 @@ import os
 import time
 import time
 import math
 import math
 from django.views.generic.base import View
 from django.views.generic.base import View
-from Model.models import CouponModel,Device_User
+from Model.models import CouponModel, Device_User, CouponConfigModel, CouponLang
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
 from django.db.models import Q, F, Count
 from django.db.models import Q, F, Count
@@ -41,59 +41,80 @@ class CouponView(View):
             if tko.code != 0:
             if tko.code != 0:
                 return response.json(tko.code)
                 return response.json(tko.code)
             userID = tko.userID
             userID = tko.userID
-            if operation == 'UserCoupon':  #用户优惠券
+            if operation == 'UserCoupon':  # 用户优惠券
                 return self.query_user_coupon(request_dict, userID, response)
                 return self.query_user_coupon(request_dict, userID, response)
             else:
             else:
                 return response.json(414)
                 return response.json(414)
 
 
-    def generate_coupon(self,request_dict,response):
+    def generate_coupon(self, request_dict, response):
         username = request_dict.get('username', None)
         username = request_dict.get('username', None)
         num = request_dict.get('num', None)
         num = request_dict.get('num', None)
         userID = Device_User.objects.filter(username=username).values('userID')[0]['userID']
         userID = Device_User.objects.filter(username=username).values('userID')[0]['userID']
+        coupon_config_id = request_dict.get('coupon_config_id', 1)
 
 
         try:
         try:
             data = []
             data = []
-            for i in range(int(num)):
-                if i % 2 == 0:
-                    data.append(CouponModel(
-                        userID_id=userID,
-                        use_status=0,
-                        type=1,
-                        coupon_discount=7,
-                        distributeTime=int(time.time()),
-                        valid_time=int(time.time()) + 8640000,
-                        addTime=int(time.time())
-                    ))
-                else:
-                    data.append(CouponModel(
-                        userID_id=userID,
-                        use_status=0,
-                        type=2,
-                        coupon_discount=0.01,
-                        distributeTime=int(time.time()),
-                        valid_time=int(time.time()) + 8640000,
-                        addTime=int(time.time())
-                    ))
-            CouponModel.objects.bulk_create(data)
+            # CouponConfigModel.objects.create(type=1, use_range=1, coupon_discount=8)
+            # CouponLangObj = CouponLang.objects.create(
+            #     lang='cn',
+            #     instruction='用于自动续费套餐的首月',
+            #     quota='八',
+            #     unit='折',
+            #     remark='每台摄像机上只能用一次'
+            # )
+            # CouponConfigModel.objects.get(id=1).lang.add(CouponLangObj.id)
+            now_time = int(time.time())
+            CouponModel.objects.create(
+                use_status=0,
+                distribute_time=now_time,
+                valid_time=now_time+10000000,
+                userID=userID,
+                coupon_config_id=coupon_config_id,
+                update_time=now_time,
+                create_time=now_time
+            )
             return HttpResponse('success')
             return HttpResponse('success')
         except Exception as e:
         except Exception as e:
-            return HttpResponse(repr(e))
+            return HttpResponse(
+                "错误行数:{errLine}, 错误信息: {errmsg}".format(errLine=e.__traceback__.tb_lineno, errmsg=repr(e)))
 
 
+    def query_user_coupon(self, request_dict, userID, response):  # 用户优惠券列表
+        now_time = int(time.time())
+        lang = request_dict.get('lang', 'en')
+        # couponObj = CouponModel.objects.filter(userID_id=userID, use_status=0, distributeTime__lte=now_time,
+        #                                        valid_time__gt=now_time).annotate(coupon_id=F('id')).values(
+        #     "coupon_id", "type", "coupon_discount", "valid_time")
 
 
+        coupon_obj = CouponModel.objects.filter(
+            userID=userID,
+            use_status=0,
+            distribute_time__lte=now_time,
+            valid_time__gt=now_time,
+            coupon_config__lang__lang=lang,
+        ).annotate(
+            coupon_id=F('id'),
+            type=F('coupon_config__type'),
+            coupon_discount=F('coupon_config__coupon_discount'),
+            instruction=F('coupon_config__lang__instruction'),
+            remark=F('coupon_config__lang__remark'),
+            quota=F('coupon_config__lang__quota'),
+            unit=F('coupon_config__lang__unit'),
+        ).values(
+            "coupon_id",
+            "type",
+            "coupon_discount",
+            "valid_time",
+            "instruction",
+            "remark",
+            "quota",
+            "unit",
+        )
 
 
+        for couponList in coupon_obj:
+            couponList['valid_time'] = CommonService.timestamp_to_str(couponList['valid_time'])
 
 
-
-
-
-    def query_user_coupon(self, request_dict, userID, response):  #用户优惠券列表
-        nowTime = int(time.time())
-        couponObj = CouponModel.objects.filter(userID_id=userID,use_status=0,distributeTime__lte=nowTime,
-                                               valid_time__gt=nowTime).annotate(coupon_id=F('id')).values(
-                                               "coupon_id","type","coupon_discount","valid_time")
-        for couponList in couponObj:
-            couponList['valid_time'] =  CommonService.timestamp_to_str(couponList['valid_time'])
         result = {
         result = {
-            'count':couponObj.count(),
-            'couponList':list(couponObj),
+            'count': coupon_obj.count(),
+            'couponList': list(coupon_obj),
         }
         }
         return response.json(0, result)
         return response.json(0, result)

+ 21 - 6
Controller/DetectControllerV2.py

@@ -55,10 +55,14 @@ class DetectControllerViewV2(View):
         return self.validation(request.POST, operation)
         return self.validation(request.POST, operation)
 
 
     def validation(self, request_dict, operation):
     def validation(self, request_dict, operation):
+
         response = ResponseObject()
         response = ResponseObject()
         if operation is None:
         if operation is None:
             return response.json(444, 'error path')
             return response.json(444, 'error path')
         token = request_dict.get('token', None)
         token = request_dict.get('token', None)
+        lang = request_dict.get('lang', None)
+        if lang:
+            response = ResponseObject(lang)
         tko = TokenObject(token)
         tko = TokenObject(token)
         if tko.code == 0:
         if tko.code == 0:
             userID = tko.userID
             userID = tko.userID
@@ -132,7 +136,9 @@ class DetectControllerViewV2(View):
             # 判断用户是否拥有设备
             # 判断用户是否拥有设备
             device_info_qs = Device_Info.objects.filter(userID_id=userID, UID=uid)
             device_info_qs = Device_Info.objects.filter(userID_id=userID, UID=uid)
             if not device_info_qs.exists():
             if not device_info_qs.exists():
-                return response.json(14)
+                device_info_qs = Device_Info.objects.filter(userID_id=userID, serial_number=uid)
+                if not device_info_qs.exists():
+                    return response.json(14)
 
 
             # 更新或创建uid_set数据
             # 更新或创建uid_set数据
             nowTime = int(time.time())
             nowTime = int(time.time())
@@ -147,7 +153,9 @@ class DetectControllerViewV2(View):
             # 检测类型
             # 检测类型
             if detect_group:
             if detect_group:
                 uid_set_data['detect_group'] = detect_group
                 uid_set_data['detect_group'] = detect_group
-
+            uid_set = UidSetModel.objects.filter(uid=uid).order_by('-updTime')
+            if uid_set.exists():
+                interval = uid_set.first().new_detect_interval if not interval else interval
             # 设置消息推送间隔
             # 设置消息推送间隔
             if interval:
             if interval:
                 interval = int(interval)
                 interval = int(interval)
@@ -162,9 +170,10 @@ class DetectControllerViewV2(View):
                             'IntervalTime': interval
                             'IntervalTime': interval
                         }
                         }
                     }
                     }
-                    req_success = CommonService.req_publish_mqtt_msg(uid, topic_name, msg)
-                    if not req_success:
-                        return response.json(10044)
+                    CommonService.req_publish_mqtt_msg(uid, topic_name, msg)
+                    # req_success = CommonService.req_publish_mqtt_msg(uid, topic_name, msg)
+                    # if not req_success:
+                    #     return response.json(10044)
 
 
             uid_set_qs = UidSetModel.objects.filter(uid=uid)
             uid_set_qs = UidSetModel.objects.filter(uid=uid)
             if uid_set_qs.exists():
             if uid_set_qs.exists():
@@ -351,12 +360,13 @@ class DetectControllerViewV2(View):
             region_name='us-east-1'
             region_name='us-east-1'
         )
         )
         # vod_time_list = []
         # vod_time_list = []
+        # ai消息标识所有组合标签
+        ai_all_event_type = EquipmentInfoService.get_all_comb_event_type()
         for p in qr:
         for p in qr:
             devUid = p['devUid']
             devUid = p['devUid']
             eventTime = p['eventTime']
             eventTime = p['eventTime']
             channel = p['Channel']
             channel = p['Channel']
             storage_location = p['storage_location']
             storage_location = p['storage_location']
-            p['borderCoords'] = '' if p['borderCoords'] == '' else json.loads(p['borderCoords'])
             if p['is_st'] == 1:
             if p['is_st'] == 1:
                 thumbspng = '{uid}/{channel}/{time}.jpeg'.format(uid=devUid, channel=p['Channel'], time=eventTime)
                 thumbspng = '{uid}/{channel}/{time}.jpeg'.format(uid=devUid, channel=p['Channel'], time=eventTime)
                 if storage_location == 1:  # oss
                 if storage_location == 1:  # oss
@@ -433,6 +443,11 @@ class DetectControllerViewV2(View):
                 p['devNickName'] = uid_type_dict[devUid]['NickName']
                 p['devNickName'] = uid_type_dict[devUid]['NickName']
             else:
             else:
                 p['uid_type'] = ''
                 p['uid_type'] = ''
+
+            p['borderCoords'] = '' if p['borderCoords'] == '' else json.loads(p['borderCoords'])  # ai消息坐标信息
+            p['ai_event_type_list'] = []
+            if p['eventType'] in ai_all_event_type:  # 如果是ai消息类型,则分解eventType, 如:123 -> [1,2,3]
+                p['ai_event_type_list'] = list(map(int, str(p['eventType'])))
             res.append(p)
             res.append(p)
         return response.json(0, {'datas': res, 'count': count})
         return response.json(0, {'datas': res, 'count': count})
 
 

+ 31 - 31
Controller/DeviceConfirmRegion.py

@@ -1,10 +1,11 @@
+import logging
 import time
 import time
 
 
 from django.utils.decorators import method_decorator
 from django.utils.decorators import method_decorator
 
 
 from django.views.decorators.csrf import csrf_exempt
 from django.views.decorators.csrf import csrf_exempt
 from django.views.generic import TemplateView
 from django.views.generic import TemplateView
-from Model.models import CountryModel, RegionModel, P2PIpModel, DeviceDomainModel
+from Model.models import CountryModel, RegionModel, P2PIpModel, DeviceDomainModel, DeviceDomainRegionModel
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
 from Service.CommonService import CommonService
 from Service.CommonService import CommonService
 
 
@@ -18,25 +19,29 @@ class ConfirmRegion(TemplateView):
     def get(self, request, *args, **kwargs):
     def get(self, request, *args, **kwargs):
         response = ResponseObject()
         response = ResponseObject()
         request.encoding = 'utf-8'
         request.encoding = 'utf-8'
-        # number = request.POST.get('number', None)
-        # selectRegion = CountryModel.objects.filter(number=number).values('region__api_url')
-        # if not selectRegion.exists():
-        #     return response.json(0,{"api_url":"https://test.dvema.com"})
-        # else:
-        #     return response.json(0,{"api_url":selectRegion[0]['region__api_url']})
-
-        # serial_number = request.POST.get('serial_number', None)
-        ip = CommonService.get_ip_address(request)
-        # ip = '14.102.176.0'
-        ipInfo = CommonService.getIpIpInfo(ip, "CN")
-        if ipInfo['country_code']:
-            device_request_url = CountryModel.objects.filter(country_code=ipInfo['country_code']).values("region__api")
-            if device_request_url.exists():
-                return response.json(0, {"request_api_url":device_request_url[0]['region__api']})
-
-        # 不存在默认返回美洲地区api。
-        api = RegionModel.objects.filter(continent_code='NA').values("api")
-        return response.json(0,{"request_api_url": api[0]['api']})
+        try:
+            ip = CommonService.get_ip_address(request)
+            device_domain_data = {'ip': ip}
+            ipInfo = CommonService.getIpIpInfo(ip, 'CN')
+            logger = logging.getLogger('info')
+            logger.info('设备获取域名---ip:{},country_code:{}'.format(ip, ipInfo['country_code']))
+            if ipInfo['country_code']:
+                device_domain_data['country_name'] = ipInfo['country_code']
+                device_request_url = CountryModel.objects.filter(country_code=ipInfo['country_code']).values("region__api")
+                if device_request_url.exists():
+                    device_domain_data['api'] = device_request_url[0]['region__api']
+                    DeviceDomainModel.objects.create(**device_domain_data)
+                    return response.json(0, {'request_api_url': device_request_url[0]['region__api']})
+
+            # 不存在默认返回美洲地区api。
+            api = RegionModel.objects.filter(continent_code='NA').values("api")
+            device_domain_data['country_name'] = 'NA'
+            device_domain_data['api'] = api[0]['api']
+            DeviceDomainModel.objects.create(**device_domain_data)
+            return response.json(0, {'request_api_url': api[0]['api']})
+        except Exception as e:
+            print(e)
+            return response.json(0, {'request_api_url': 'https://www.dvema.com'})
 
 
 
 
 # 根据设备的ip返回域名和地区id
 # 根据设备的ip返回域名和地区id
@@ -47,17 +52,12 @@ class ConfirmRegionV2(TemplateView):
 
 
     def get(self, request, *args, **kwargs):
     def get(self, request, *args, **kwargs):
         response = ResponseObject()
         response = ResponseObject()
-        uid = request.GET.get('uid', None)
         serial_number = request.GET.get('serial_number', None)
         serial_number = request.GET.get('serial_number', None)
-        if not uid and not serial_number:
+        if not serial_number:
             return response.json(444)
             return response.json(444)
         try:
         try:
-            if uid:
-                data_dict = {'uid': uid}
-                device_domain_qs = DeviceDomainModel.objects.filter(uid=uid)
-            else:
-                data_dict = {'serial_number': serial_number}
-                device_domain_qs = DeviceDomainModel.objects.filter(serial_number=serial_number)
+            data_dict = {'serial_number': serial_number}
+            device_domain_region_qs = DeviceDomainRegionModel.objects.filter(serial_number=serial_number)
 
 
             # 根据请求ip确认地区
             # 根据请求ip确认地区
             request.encoding = 'utf-8'
             request.encoding = 'utf-8'
@@ -82,10 +82,10 @@ class ConfirmRegionV2(TemplateView):
             # 更新或创建设备域名数据
             # 更新或创建设备域名数据
             data_dict['api'] = api
             data_dict['api'] = api
             data_dict['region_id'] = region_id
             data_dict['region_id'] = region_id
-            if device_domain_qs.exists():
-                device_domain_qs.update(**data_dict)
+            if device_domain_region_qs.exists():
+                device_domain_region_qs.update(**data_dict)
             else:
             else:
-                device_domain_qs.create(**data_dict)
+                device_domain_region_qs.create(**data_dict)
             res = {'request_api_url': api, 'region_id': region_id}
             res = {'request_api_url': api, 'region_id': region_id}
             return response.json(0, res)
             return response.json(0, res)
         except Exception as e:
         except Exception as e:

+ 23 - 1
Controller/EquipmentInfo.py

@@ -5,7 +5,7 @@ from django.utils.decorators import method_decorator
 from django.views.decorators.csrf import csrf_exempt
 from django.views.decorators.csrf import csrf_exempt
 from django.views.generic.base import View
 from django.views.generic.base import View
 
 
-from Model.models import Device_Info, Equipment_Info
+from Model.models import Device_Info, Equipment_Info, UidPushModel
 from Model.models import Device_User
 from Model.models import Device_User
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
@@ -93,6 +93,28 @@ class EquipmentInfo(View):
                 addTime=nowTime,
                 addTime=nowTime,
                 alarm=alarm)
                 alarm=alarm)
             equipment_info.save()
             equipment_info.save()
+            uid_push_qs = UidPushModel.objects.filter(uid_set__uid=devUid, uid_set__detect_status=1). \
+                values('token_val', 'app_type', 'appBundleId', 'm_code', 'push_type', 'userID_id', 'userID__NickName',
+                       'lang', 'm_code', 'tz', 'uid_set__nickname', 'uid_set__detect_interval', 'uid_set__detect_group',
+                       'uid_set__channel')
+            tz = '0'
+            if uid_push_qs.exists():
+                tz = uid_push_qs.first().tz
+            local_date_time = CommonService.get_now_time_str(n_time=nowTime, tz=tz, lang='cn')
+            local_date_time = local_date_time[0:10]
+            equipment_info_vo = EquipmentInfoService.get_equipment_info_obj(
+                local_date_time,
+                device_user_id=userID,
+                event_time=nowTime,
+                event_type=eventType,
+                device_uid=devUid,
+                device_nick_name=device_info[0].NickName,
+                channel=Channel,
+                alarm=alarm,
+                receive_time=receiveTime,
+                add_time=nowTime,
+            )
+            equipment_info_vo.save()
         except Exception:
         except Exception:
             errorInfo = traceback.format_exc()
             errorInfo = traceback.format_exc()
             print(errorInfo)
             print(errorInfo)

+ 4 - 1
Controller/EquipmentManagerV2.py

@@ -9,7 +9,7 @@ from django.views.generic.base import View
 
 
 from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY
 from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY
 from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidPushModel, UidChannelSetModel, \
 from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidPushModel, UidChannelSetModel, \
-    iotdeviceInfoModel
+    iotdeviceInfoModel, UIDModel
 from Object.ResponseObject import ResponseObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
 from Service.CommonService import CommonService
@@ -325,6 +325,9 @@ class EquipmentManagerV2(View):
             uv_dict[us['uid']]['channels'] = channels
             uv_dict[us['uid']]['channels'] = channels
 
 
         for p in dvls:
         for p in dvls:
+            # 如果存在序列号返回完整序列号
+            if p['serial_number']:
+                p['UID'] = CommonService.get_full_serial_number(p['UID'], p['serial_number'], p['Type'])
             # 新增IOT
             # 新增IOT
             p['iot'] = []
             p['iot'] = []
             for iot in iotqs:
             for iot in iotqs:

+ 24 - 54
Controller/IotCoreController.py

@@ -4,6 +4,7 @@ import hashlib
 import logging
 import logging
 import time
 import time
 import uuid
 import uuid
+from collections import OrderedDict
 
 
 import requests
 import requests
 from django.views import View
 from django.views import View
@@ -11,7 +12,7 @@ from django.views import View
 from Ansjer.config import AWS_IOT_GETS3_PULL_CHINA_ID, AWS_IOT_GETS3_PULL_CHINA_SECRET, \
 from Ansjer.config import AWS_IOT_GETS3_PULL_CHINA_ID, AWS_IOT_GETS3_PULL_CHINA_SECRET, \
     AWS_IOT_GETS3_PULL_FOREIGN_ID, AWS_IOT_GETS3_PULL_FOREIGN_SECRET, AWS_ARN, AWS_IOT_SES_ACCESS_CHINA_REGION, \
     AWS_IOT_GETS3_PULL_FOREIGN_ID, AWS_IOT_GETS3_PULL_FOREIGN_SECRET, AWS_ARN, AWS_IOT_SES_ACCESS_CHINA_REGION, \
     AWS_IOT_SES_ACCESS_FOREIGN_REGION_ASIA, AWS_IOT_SES_ACCESS_FOREIGN_REGION_EUROPE, \
     AWS_IOT_SES_ACCESS_FOREIGN_REGION_ASIA, AWS_IOT_SES_ACCESS_FOREIGN_REGION_EUROPE, \
-    AWS_IOT_SES_ACCESS_FOREIGN_REGION_AMERICA
+    AWS_IOT_SES_ACCESS_FOREIGN_REGION_AMERICA, CONFIG_INFO, CONFIG_TEST, CONFIG_CN
 from Controller.DeviceConfirmRegion import Device_Region
 from Controller.DeviceConfirmRegion import Device_Region
 from Model.models import Device_Info, iotdeviceInfoModel, SerialNumberModel, UidSetModel
 from Model.models import Device_Info, iotdeviceInfoModel, SerialNumberModel, UidSetModel
 from Object.IOTCore.IotObject import IOTClient
 from Object.IOTCore.IotObject import IOTClient
@@ -41,7 +42,7 @@ class IotCoreView(View):
         if operation == 'createKeysAndCertificate':
         if operation == 'createKeysAndCertificate':
             return self.create_keys_and_certificate(request_dict, response, request)
             return self.create_keys_and_certificate(request_dict, response, request)
         elif operation == 'requestPublishMessage':
         elif operation == 'requestPublishMessage':
-            return self.request_publish_message(request_dict, response, request)
+            return self.request_publish_message(request_dict, response)
         elif operation == 'getS3PullKey':
         elif operation == 'getS3PullKey':
             return self.get_s3_pull_key(request_dict, response, request)
             return self.get_s3_pull_key(request_dict, response, request)
         elif operation == 'thingRegroup':
         elif operation == 'thingRegroup':
@@ -128,15 +129,12 @@ class IotCoreView(View):
                 }
                 }
                 return response.json(0, {'res': res})
                 return response.json(0, {'res': res})
             else:
             else:
-                # 根据地区id确定使用的boto3 client
                 region_id = request_dict.get('region_id', None)
                 region_id = request_dict.get('region_id', None)
-                if region_id:
-                    region_id = int(region_id)
-                else:
-                    ip = CommonService.get_ip_address(request)
-                    region_id = Device_Region().get_device_region(ip)
-                iotClient = IOTClient(region_id)
+                if not region_id:
+                    # 根据配置信息确定region_id
+                    region_id = CommonService.confirm_region_id(request)
 
 
+                iotClient = IOTClient(int(region_id))
                 # 拼接物品名
                 # 拼接物品名
                 thingName = CommonService.get_thing_name(company_mark, thing_name_suffix)
                 thingName = CommonService.get_thing_name(company_mark, thing_name_suffix)
                 thingGroup = device_version + '_' + language
                 thingGroup = device_version + '_' + language
@@ -230,7 +228,7 @@ class IotCoreView(View):
             print(e)
             print(e)
             return response.json(500, repr(e))
             return response.json(500, repr(e))
 
 
-    def clear_Iot_Cerm(self, userID, request_dict, response):
+    def clear_Iot_Cerm(self, request_dict, response):
         serial_number = request_dict.get('serial_number', None)
         serial_number = request_dict.get('serial_number', None)
 
 
         if serial_number:
         if serial_number:
@@ -243,56 +241,28 @@ class IotCoreView(View):
         else:
         else:
             return response.json(444)
             return response.json(444)
 
 
-    def request_publish_message(self, request_dict, response, request):
-        # Alexa请求IoT Core下发MQTT消息通知设备开始或停止推流,或唤醒设备
+    # Alexa请求IoT Core下发MQTT消息通知设备开始或停止推流,或唤醒设备
+    @staticmethod
+    def request_publish_message(request_dict, response):
         UID = request_dict.get('UID', None)
         UID = request_dict.get('UID', None)
-        MSG = request_dict.get('MSG', None)
-
-        if not all([UID, MSG]):
+        rtsp = request_dict.get('rtsp', None)
+        enable = request_dict.get('enable', '1')
+        if not all([UID, rtsp]):
             return response.json(444)
             return response.json(444)
 
 
         try:
         try:
-            # 获取设备的物品名后缀
-            device_info_qs = Device_Info.objects.filter(UID=UID).values('UID', 'serial_number')
-            if not device_info_qs.exists():
-                return response.json(10043)
-            uid = device_info_qs[0]['UID']
-            serial_number = device_info_qs[0]['serial_number']
-            # 如果device_info表的serial_number不为空,物品名为'Ansjer_Device_序列号'
-            thing_name_suffix = serial_number if serial_number != '' else uid
-            # 获取数据组织将要请求的url
-            iot = iotdeviceInfoModel.objects.filter(thing_name__contains=thing_name_suffix).values('thing_name',
-                                                                                                   'endpoint',
-                                                                                                   'token_iot_number')
-            if not iot.exists():
-                return response.json(10043)
-            thing_name = iot[0]['thing_name'][14:]  # IoT core上的物品名: Ansjer_Device_ + 序列号+企业编码/uid
-            endpoint = iot[0]['endpoint']
-            Token = iot[0]['token_iot_number']
-            # Token = '297a601b3925e04daab5a60280650e09'
-            topic_suffix = '_power_topic' if 'Turn' in MSG else '_rtsp_topic'
-            topic_name = thing_name + topic_suffix  # MQTT主题
-
-            # api doc: https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/http.html
-            # url: https://IoT_data_endpoint/topics/url_encoded_topic_name?qos=1
-            # post请求url来发布MQTT消息
-            url = 'https://{}/topics/{}'.format(endpoint, topic_name)
-            authorizer_name = 'Ansjer_Iot_Auth'
-            signature = CommonService.rsa_sign(Token)  # Token签名
-            headers = {'x-amz-customauthorizer-name': authorizer_name, 'Token': Token,
-                       'x-amz-customauthorizer-signature': signature}
-            params = {'command': MSG}
-            r = requests.post(url=url, headers=headers, json=params, timeout=2)
-            if r.status_code == 200:
-                res = r.json()
-                if res['message'] == 'OK':
-                    return response.json(0)
-                return response.json(10044)
-            else:
-                # print('发布失败')
+            thing_name = CommonService.query_serial_with_uid(UID)   # 存在序列号则为使用序列号作为物品名
+            topic_name = 'ansjer/generic/{}'.format(thing_name)
+            msg = OrderedDict(
+                [
+                    ('alexaRtspCommand', rtsp),
+                    ('enable', int(enable)),
+                ]
+            )
+            if not CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg):
                 return response.json(10044)
                 return response.json(10044)
+            return response.json(0)
         except Exception as e:
         except Exception as e:
-            # print(e)
             return response.json(500, repr(e))
             return response.json(500, repr(e))
 
 
     def get_s3_pull_key(self, request_dict, response, request):
     def get_s3_pull_key(self, request_dict, response, request):

+ 119 - 0
Controller/MessagePush/EquipmentMessagePush.py

@@ -0,0 +1,119 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : EquipmentMessagePush.py
+@Time    : 2022/5/16 11:46
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+
+import logging
+import time
+
+from django.db import transaction
+from django.views.generic.base import View
+
+from Model.models import AiService, UidSetModel
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Service.CommonService import CommonService
+
+
+# 设备消息推送视图
+class EquipmentMessagePushView(View):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+        lang = request_dict.get('lang', None)
+        logger = logging.getLogger('info')
+        logger.info("传参语言{}".format(lang))
+        lang = lang if lang else token.lang
+        response = ResponseObject(lang)
+        if token.code != 0:
+            return response.json(token.code)
+        if operation is None:
+            return response.json(444, 'error path')
+        elif operation == 'update':
+            return self.do_change_status_all(request_dict, response)
+        elif operation == 'query':
+            return self.do_uid_set_query(request_dict, response)
+
+    @classmethod
+    def do_uid_set_query(cls, request_dict, response):
+
+        logger = logging.getLogger('info')
+        uid = request_dict.get('uid', None)
+        logger.info("----查询状态打印uid{}".format(uid))
+        if not uid:
+            return response.json(444, 'uid')
+        uid_set_qs = UidSetModel.objects.filter(uid=uid).order_by('-updTime')
+        if uid_set_qs.exists():
+            uid_set = uid_set_qs.first()
+            data = {
+                'status': uid_set.is_notification,
+                'interval': uid_set.new_detect_interval
+            }
+            return response.json(0, res=data)
+        return response.json(0)
+
+    @classmethod
+    def do_change_status_all(cls, request_dict, response):
+        logger = logging.getLogger('info')
+        status = request_dict.get('status', None)
+        uid = request_dict.get('uid', None)
+        interval = request_dict.get('interval', None)
+        if not status:
+            return response.json(444, 'status')
+        if not uid:
+            return response.json(444, 'uid')
+        try:
+            with transaction.atomic():
+                n_time = int(time.time())
+                status = int(status)
+                uid_set_qs = UidSetModel.objects.filter(uid=uid)
+                if not uid_set_qs.exists():
+                    qs_data = {
+                        'uid': uid,
+                        'addTime': n_time,
+                        'updTime': n_time,
+                    }
+                    if interval:
+                        qs_data['new_detect_interval'] = int(interval)
+                        qs_data['is_notification'] = status
+                    UidSetModel.objects.create(**qs_data)
+                if status == 1:
+                    if uid_set_qs.exists():
+                        qs_data = {
+                            'updTime': n_time,
+                        }
+                        if interval:
+                            qs_data['new_detect_interval'] = int(interval)
+                        qs_data['is_notification'] = status
+                        uid_set_qs.update(**qs_data)
+                if status == 0:
+                    ai_service_qs = AiService.objects.filter(uid=uid, use_status=1)
+                    if ai_service_qs.exists():
+                        qs_data = {'uid': uid, 'updTime': n_time, 'detect_status': status}
+                        ai_service_qs.update(**qs_data)
+                        topic_name = 'ansjer/generic/{}'.format(uid)
+                        # mqtt通知设备关闭AI识别功能
+                        msg = {'commandType': 'AIDisable'}
+                        req_success = CommonService.req_publish_mqtt_msg(uid, topic_name, msg)
+                        logger.info("推送>>>> mqtt回调:{}".format(req_success))
+                    if uid_set_qs.exists():
+                        uid_set_data = {'updTime': n_time, 'uid': uid, 'new_detect_interval': int(interval),
+                                        'detect_status': int(interval), 'is_notification': status}
+                        uid_set_qs.update(**uid_set_data)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))

+ 3 - 1
Controller/OrderContrller.py

@@ -127,7 +127,9 @@ class OrderView(View):
                 if d['UID'] == did['UID']:
                 if d['UID'] == did['UID']:
                     d['did'] = did['id']
                     d['did'] = did['id']
                     d['Type'] = did['Type']
                     d['Type'] = did['Type']
-                    d['serialNumber'] = did['serial_number']
+                    # 如果存在序列号返回完整序列号
+                    if did['serial_number']:
+                        d['UID'] = CommonService.get_full_serial_number(d['UID'], did['serial_number'], did['Type'])
                     data.append(d)
                     data.append(d)
             d['rank__content'] = d['rank__lang__content']
             d['rank__content'] = d['rank__lang__content']
             del d['rank__lang__content']
             del d['rank__lang__content']

+ 5 - 1
Controller/PaymentCycle.py

@@ -197,6 +197,10 @@ class PaypalCycleNotify(View):
                          ))
                          ))
             logger.info('billing_agreement_state')
             logger.info('billing_agreement_state')
             logger.info(state)
             logger.info(state)
+            red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            if lang != 'cn':
+                red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            return HttpResponseRedirect(red_url)
         try:
         try:
             userid = order_list[0]['userID__userID']
             userid = order_list[0]['userID__userID']
             username = order_list[0]['userID__username']
             username = order_list[0]['userID__username']
@@ -269,7 +273,7 @@ class PaypalCycleNotify(View):
 
 
                 # 核销coupon
                 # 核销coupon
                 if order_list[0]['coupon_id']:
                 if order_list[0]['coupon_id']:
-                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
+                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2, update_time=nowTime)
 
 
                 order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id,
                 order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id,
                                 promotion_rule_id=promotion_rule_id, agreement_id=agreement_id)
                                 promotion_rule_id=promotion_rule_id, agreement_id=agreement_id)

+ 948 - 0
Controller/SensorGateway/EquipmentFamilyController.py

@@ -0,0 +1,948 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : EquipmentFamilyController.py
+@Time    : 2022/5/13 15:50
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+
+import time
+
+import oss2
+from django.db import connection
+from django.db import transaction
+from django.db.models import Q, Count
+from django.views.generic.base import View
+
+from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY
+from Controller.DeviceConfirmRegion import Device_Region
+from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidChannelSetModel, \
+    iotdeviceInfoModel, UIDModel, Device_User, UserFamily, FamilyMember, FamilyMemberPermission, \
+    FamilyRoomDevice, FamilyRoom, FamilyMemberJoin
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Service.CommonService import CommonService
+
+
+# 家庭设备管理
+class EquipmentFamilyView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+
+        token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+        lang = request_dict.get('lang', None)
+        if lang:
+            response = ResponseObject(lang)
+        else:
+            response = ResponseObject(token.lang) if token.lang else ResponseObject()
+
+        if token.code != 0:
+            return response.json(token.code)
+        user_id = token.userID
+
+        # 手机端添加设备,查询,修改
+        if operation == 'add':
+            return self.do_save(user_id, request_dict, response, request)
+        # 分页获取未添加房间设备
+        elif operation == 'family-device-query':
+            return self.get_device_not_in_room(user_id, request_dict, response)
+        # 条件查询设备列表
+        elif operation == 'query':
+            return self.do_device_query(user_id, request_dict, response)
+        # 获取家庭列表
+        elif operation == 'family-list':
+            return self.get_family_list(user_id, request_dict, response)
+        # 查询所在家庭列表
+        elif operation == "where-family-list":
+            return self.who_family_list(user_id, response)
+        # 家庭保存
+        elif operation == 'family-save':
+            return self.family_save(user_id, request_dict, response)
+        # 家庭设置
+        elif operation == 'family-setting':
+            return self.get_family_setting(request_dict, response)
+        # 家庭成员删除
+        elif operation == 'member-del':
+            return self.family_member_del(user_id, request_dict, response)
+        # 获取房间列表
+        elif operation == 'room-list':
+            return self.get_family_room_list(request_dict, response)
+        # 房间保存
+        elif operation == 'room-save':
+            return self.room_save(request_dict, response)
+        # 权限列表
+        elif operation == 'permission-list':
+            return self.get_member_permission_list(user_id, request_dict, response)
+        # 成员权限修改
+        elif operation == 'permission-update':
+            return self.changes_member_permission(user_id, request_dict, response)
+        elif operation == 'family/del':
+            return self.family_family_del(user_id, request_dict, response)
+        else:
+            return response.json(414)
+
+    @classmethod
+    def family_family_del(cls, user_id, request_dict, response):
+        """
+        删除家庭
+        @param user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        if not family_id:
+            return response.json(444)
+        family_id = int(family_id)
+        permission = cls.get_member_permission_details(user_id, family_id)
+        if not permission or permission == '003':
+            return response.json(404)
+        user_family_qs = UserFamily.objects.filter(id=family_id, user_id=user_id)
+        if not user_family_qs.exists():
+            return response.json(173)
+        count = UserFamily.objects.filter(user_id=user_id).count()
+        if count <= 1:
+            return response.json(10057)
+        family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id)
+        if family_room_device_qs.exists():
+            family_room_device_qs.delete()
+        family_join_qs = FamilyMemberJoin.objects.filter(family_id=family_id)
+        if family_join_qs.exists():
+            family_join_qs.delete()
+        family_room_qs = FamilyRoom.objects.filter(family_id=family_id)
+        if family_room_qs.exists():
+            family_room_qs.delete()
+        family_member_qs = FamilyMember.objects.filter(family_id=family_id)
+        if family_member_qs.exists():
+            family_member_qs.delete()
+        family_qs = UserFamily.objects.filter(id=family_id)
+        if family_qs.exists():
+            family_qs.delete()
+        return response.json(0)
+
+    @classmethod
+    def do_save(cls, user_id, request_dict, response, request):
+        """
+        添加网关设备
+        @param request:
+        @param user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        nick_name = request_dict.get('nickName', None)
+        serial_number = request_dict.get('serialNumber', None)
+        device_type = request_dict.get('deviceType', None)
+        family_id = request_dict.get('familyId', None)
+        room_id = request_dict.get('roomId', None)
+        # type 可能为0
+        if not all([nick_name, serial_number, device_type]):
+            return response.json(444, {'param': 'nick_name, serial_number, device_type'})
+        device_info_qs = Device_Info.objects.filter(serial_number=serial_number, isShare=False)
+        if device_info_qs:
+            qs = device_info_qs.values('userID__NickName', 'NickName', 'userID_id')
+            nickname = qs[0]['NickName']
+            device_user_id = qs[0]['userID_id']
+            if device_user_id == user_id:
+                return response.json(174)
+            else:
+                if qs[0]['userID__userEmail']:
+                    bind_user = qs[0]['userID__userEmail']
+                elif qs[0]['userID__phone']:
+                    bind_user = qs[0]['userID__phone']
+                elif qs[0]['userID__username']:
+                    bind_user = qs[0]['userID__username']
+                elif qs[0]['userID__NickName']:
+                    bind_user = qs[0]['userID__NickName']
+                else:
+                    bind_user = qs[0]['userID_id']
+                res = {
+                    'bindUser': bind_user,
+                    'bindDeviceName': nickname,
+                    'isMainUserExists': 1
+                }
+                return response.json(0, res=res)
+        try:
+            with transaction.atomic():
+                family_id = int(family_id)
+                # 格式化后的日期时间
+                now_time = CommonService.timestamp_to_str(int(time.time()))
+                device_id = CommonService.getUserID(getUser=False)
+                Device_Info.objects.create(id=device_id, userID_id=user_id, NickName=nick_name,
+                                           Type=device_type,
+                                           UID=serial_number,
+                                           serial_number=serial_number, data_joined=now_time,
+                                           update_time=now_time)
+                boole = cls.family_room_device_save(family_id, room_id, device_id)
+                if not boole:
+                    return response.json(15)
+                # 判断是否有用户绑定
+                us_qs = UidSetModel.objects.filter(uid=serial_number)
+                if not us_qs:
+                    n_time = int(time.time())
+                    ip = CommonService.get_ip_address(request)
+                    region_id = Device_Region().get_device_region(ip)
+                    region_alexa = 'CN' if region_id == 1 else 'ALL'
+                    uid_set_create_dict = {
+                        'uid': serial_number,
+                        'addTime': n_time,
+                        'updTime': n_time,
+                        'ip': CommonService.get_ip_address(request_dict),
+                        'nickname': nick_name,
+                        'region_alexa': region_alexa,
+                    }
+                    UidSetModel.objects.create(**uid_set_create_dict)
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def get_device_not_in_room(cls, user_id, request_dict, response):
+        """
+        获取不在房间的设备
+        @param user_id: 用户id
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        page_no = request_dict.get('pageNo', None)
+        page_size = request_dict.get('pageSize', None)
+        family_id = request_dict.get('familyId', None)
+        if not all([page_no, page_size, family_id]):
+            return response.json(444)
+        page_no = int(page_no)
+        page_size = int(page_size)
+        device_list = cls.get_family_device_list(user_id, page_no, page_size, family_id, 0)
+        return response.json(0, device_list)
+
+    @classmethod
+    def do_device_query(cls, user_id, request_dict, response):
+        """
+        查询用户设备信息
+        @param user_id: 用户id
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @return: response
+        """
+        page = request_dict.get('page', None)
+        line = request_dict.get('line', None)
+        nick_name = request_dict.get('NickName', None)
+        family_id = request_dict.get('familyId', None)
+        room_id = request_dict.get('roomId', None)
+
+        page = int(page)
+        line = int(line)
+        uid = request_dict.get('uid', None)
+        if family_id:
+            permission = cls.get_member_permission_details(user_id, int(family_id))
+            if not permission or permission == '003':
+                return response.json(404)
+        if room_id:
+            family_room = FamilyRoom.objects.filter(id=room_id)
+            if not family_room.exists():
+                return response.json(173)
+            permission = cls.get_member_permission_details(user_id, family_room.first().family_id)
+            if not permission or permission == '003':
+                return response.json(404)
+        # 获取设备信息列表
+        device_info_list = cls.get_device_info_list(user_id, nick_name, uid,
+                                                    page, line, family_id, room_id)
+        uid_list = []
+        # 判断是否是主用户 isPrimaryUser=0:否,1:是
+        for dvl in device_info_list:
+            if dvl['primaryUserID'] and dvl['id'] == dvl['primaryUserID']:
+                dvl['isPrimaryUser'] = 1
+            else:
+                dvl['isPrimaryUser'] = 0
+            uid_list.append(dvl['UID'])
+        # 设备关联套餐,设备预览图
+        uid_bucket_qs, uid_preview_qs = cls.get_bucket_and_preview_by_uid(uid_list)
+        # 设备配置信息
+        uid_set_dict = cls.get_uid_set_dict(uid_list)
+        # 设备详情信息
+        result = cls.get_device_details(device_info_list, uid_bucket_qs, uid_preview_qs, uid_set_dict)
+        items = []
+        for index, item in enumerate(result):
+            # 加密
+            if item['View_Password']:
+                item['View_Password'] = CommonService.encode_data(item['View_Password'], 1, 4)
+            items.append(item)
+        return response.json(0, items)
+
+    @classmethod
+    def get_device_info_list(cls, user_id, nick_name, uid, page, line, family_id, room_id):
+        """
+        根据用户id获取设备信息
+        @param room_id: 家庭id
+        @param family_id: 房间id
+        @param uid: uid
+        @param nick_name: 设备名称
+        @param line: 条数
+        @param page: 页数
+        @param user_id: 用户id
+        @return: device_info_list 设备信息列表
+        """
+        # 获取用户设备信息
+        device_info_qs = Device_Info.objects.filter(userID_id=user_id)
+        # 过滤已重置的设备
+        device_info_qs = device_info_qs.filter(~Q(isExist=2))
+        if nick_name:
+            device_info_qs = device_info_qs.filter(NickName__icontains=nick_name)
+        if uid:
+            device_info_qs.filter(UID=uid)
+        if family_id or room_id:
+            # 根据家庭id获取房间id关联查询设备
+            return cls.get_family_device_list(user_id, page, line, family_id, room_id)
+        device_info_values = device_info_qs.values('id', 'userID', 'NickName', 'UID', 'View_Account', 'View_Password',
+                                                   'ChannelIndex',
+                                                   'Type', 'isShare', 'primaryUserID', 'primaryMaster', 'data_joined',
+                                                   'vodPrimaryUserID',
+                                                   'vodPrimaryMaster', 'userID__userEmail', 'version', 'isVod',
+                                                   'isExist', 'NotificationMode',
+                                                   'isCameraOpenCloud', 'serial_number')
+
+        device_info_values = device_info_values[(page - 1) * line:page * line]
+        device_info_list = CommonService.qs_to_list(device_info_values)
+        return device_info_list
+
+    @classmethod
+    def get_family_device_list(cls, user_id, page_no, page_size, family_id, room_id, is_room_other=False):
+        """
+        获取关联家庭设备列表
+        @param is_room_other: 是否显示其他房间设备
+        @param user_id: 用户id
+        @param page_no: 页数
+        @param page_size: 分页大小
+        @param family_id: 家庭id
+        @param room_id: 房间id
+        @return: result_list
+        """
+        cursor = connection.cursor()
+        sql = 'SELECT d.id,d.userID_id as userID,d.NickName,d.UID,d.View_Account,d.View_Password,d.ChannelIndex,' \
+              'd.Type,d.isShare,d.primaryUserID,d.primaryMaster,d.data_joined,d.vodPrimaryUserID,d.vodPrimaryMaster, ' \
+              'd.version,d.isVod,d.isExist,d.NotificationMode,d.isCameraOpenCloud,d.serial_number '
+        sql += 'FROM device_info d INNER JOIN family_room_device l ON d.id = l.device_id '
+        sql += 'WHERE d.userID_id = %s AND d.isExist != %s '
+        if family_id:
+            family_id = int(family_id)
+            user_id = UserFamily.objects.filter(id=family_id).first().user_id
+            sql += ' AND l.family_id = %s '
+        if room_id and is_room_other:
+            sql += ' AND l.room_id != %s '
+        elif room_id:
+            sql += ' AND l.room_id = %s '
+        sql += ' GROUP BY d.id order by d.data_joined DESC,d.id DESC LIMIT %s,%s '
+        if family_id and room_id:
+            cursor.execute(sql, [user_id, 2, int(family_id), int(room_id), ((page_no - 1) * page_size),
+                                 page_size, ])
+            data_obj = cursor.fetchall()
+        else:
+            cursor.execute(sql, [user_id, 2, int(family_id) if family_id else int(room_id), ((page_no - 1) * page_size),
+                                 page_size, ])
+            data_obj = cursor.fetchall()
+        cursor.close()  # 执行完,关闭
+        connection.close()
+        result_list = []
+        col_names = [desc[0] for desc in cursor.description]
+        for item in data_obj:
+            val = dict(zip(col_names, item))
+            user_id = val['userID']
+            device_user_qs = Device_User.objects.filter(userID=user_id)
+            val['userID__userEmail'] = device_user_qs.first().userEmail
+            val['isShare'] = False if val['isShare'] == 0 else True
+            if 'data_joined' in val:
+                if val['data_joined']:
+                    val['data_joined'] = val['data_joined'].strftime("%Y-%m-%d %H:%M:%S")
+                else:
+                    val['data_joined'] = ''
+            result_list.append(val)
+        return result_list
+
+    @classmethod
+    def get_bucket_and_preview_by_uid(cls, uid_list):
+        """
+        根据uid列表查询套餐
+        @param uid_list: uid列表
+        @return: uid_bucket_qs
+        """
+        uid_bucket_qs = UID_Bucket.objects.filter(uid__in=uid_list).values('bucket__content', 'status', 'channel',
+                                                                           'endTime', 'uid')
+        uid_preview_qs = UID_Preview.objects.filter(uid__in=uid_list).order_by('channel').values('id', 'uid', 'channel')
+        return uid_bucket_qs, uid_preview_qs
+
+    @classmethod
+    def get_uid_set_dict(cls, uid_list):
+        """
+        获取uid配置信息
+        @param uid_list: uid列表
+        @return: uid_set_dict uid配置信息
+        """
+        uid_set_qs = UidSetModel.objects.filter(uid__in=uid_list) \
+            .values('id', 'uid', 'version', 'nickname', 'ucode',
+                    'detect_status', 'detect_group',
+                    'detect_interval',
+                    'region_alexa', 'is_alexa', 'deviceModel',
+                    'TimeZone', 'TimeStatus', 'SpaceUsable',
+                    'SpaceSum', 'MirrorType', 'RecordType',
+                    'OutdoorModel', 'WIFIName', 'isDetector',
+                    'DetectorRank', 'is_human', 'is_custom_voice',
+                    'is_ptz', 'double_wifi', 'is_ai')
+        uid_set_dict = {}
+        for us in uid_set_qs:
+            uid_set_dict[us['uid']] = {
+                'version': us['version'],
+                'nickname': us['nickname'],
+                'ucode': us['ucode'],
+                'detect_interval': us['detect_interval'],
+                'detect_group': us['detect_group'],
+                'detect_status': us['detect_status'],
+                'region_alexa': us['region_alexa'],
+                'is_alexa': us['is_alexa'],
+                'deviceModel': us['deviceModel'],
+                'TimeZone': us['TimeZone'],
+                'TimeStatus': us['TimeStatus'],
+                'SpaceUsable': us['SpaceUsable'],
+                'SpaceSum': us['SpaceSum'],
+                'MirrorType': us['MirrorType'],
+                'RecordType': us['RecordType'],
+                'OutdoorModel': us['OutdoorModel'],
+                'WIFIName': us['WIFIName'],
+                'isDetector': us['isDetector'],
+                'DetectorRank': us['DetectorRank'],
+                'is_human': us['is_human'],
+                'is_custom_voice': us['is_custom_voice'],
+                'is_ptz': us['is_ptz'],
+                'double_wifi': us['double_wifi'],
+                'is_ai': us['is_ai']
+            }
+            # 从uid_channel里面取出通道配置信息
+            uid_channel_set_qs = UidChannelSetModel.objects.filter(uid__id=us['id']) \
+                .values('channel', 'channel_name',
+                        'pir_audio', 'mic_audio',
+                        'battery_status',
+                        'battery_level',
+                        'sleep_status',
+                        'sleep_time',
+                        'light_night_model',
+                        'light_alarm_type',
+                        'light_alarm_level',
+                        'light_alarm_man_en',
+                        'light_alarm_vol',
+                        'light_long_light'
+                        )
+            channels_list = []
+            for ucs in uid_channel_set_qs:
+                channels_dict = {
+                    'channel': ucs['channel'],
+                    'channel_name': ucs['channel_name'],
+                    'pir_audio': ucs['pir_audio'],
+                    'mic_audio': ucs['mic_audio'],
+                    'battery_status': ucs['battery_status'],
+                    'battery_level': ucs['battery_level'],
+                    'sleep_status': ucs['sleep_status'],
+                    'sleep_time': ucs['sleep_time'],
+                    'light_night_model': ucs['light_night_model'],
+                    'light_alarm_type': ucs['light_alarm_type'],
+                    'light_alarm_level': ucs['light_alarm_level'],
+                    'light_alarm_man_en': ucs['light_alarm_man_en'],
+                    'light_alarm_vol': ucs['light_alarm_vol'],
+                    'light_long_light': ucs['light_long_light']
+                }
+                channels_list.append(channels_dict)
+            uid_set_dict[us['uid']]['channels'] = channels_list
+        return uid_set_dict
+
+    @classmethod
+    def get_device_details(cls, device_info_list, uid_bucket_qs, uid_preview_qs, uid_set_dict):
+        """
+        设备详情
+        @param device_info_list: 设备信息列表
+        @param uid_bucket_qs: 套餐对象
+        @param uid_preview_qs:
+        @param uid_set_dict:
+        @return:
+        """
+        now_time = int(time.time())
+        data = []
+        for p in device_info_list:
+            # 获取iotDeviceInfo表的endpoint和tokenIotNumber
+            p['iot'] = []
+            if p['serial_number']:  # 存在序列号根据序列号查询
+                iot_device_info_qs = iotdeviceInfoModel.objects.filter(serial_number=p['serial_number'][0:6])
+            else:  # 根据uid查询
+                iot_device_info_qs = iotdeviceInfoModel.objects.filter(uid=p['UID'])
+            if iot_device_info_qs.exists():
+                iot_device_Info = iot_device_info_qs.values('endpoint', 'token_iot_number')
+                p['iot'].append({
+                    'endpoint': iot_device_Info[0]['endpoint'],
+                    'token_iot_number': iot_device_Info[0]['token_iot_number']
+                })
+
+            p['vod'] = []
+            for dm in uid_bucket_qs:
+                if p['UID'] == dm['uid']:
+                    if dm['endTime'] > now_time:
+                        p['vod'].append(dm)
+            p['preview'] = []
+
+            auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
+            bucket = oss2.Bucket(auth, 'oss-cn-hongkong.aliyuncs.com', 'statres')
+
+            for up in uid_preview_qs:
+                if p['UID'] == up['uid']:
+                    obj = 'uid_preview/{uid}/channel_{channel}.png'.format(uid=up['uid'], channel=up['channel'])
+                    img_sign = bucket.sign_url('GET', obj, 300)
+                    p['preview'].append(img_sign)
+
+            p_uid = p['UID']
+
+            # 返回设备初始化字符
+            uid_qs = UIDModel.objects.filter(uid=p_uid).values('platform', 'init_string', 'init_string_app')
+            if uid_qs.exists():
+                p['platform'] = uid_qs[0]['platform']
+                p['initString'] = uid_qs[0]['init_string']
+                p['initStringApp'] = uid_qs[0]['init_string_app']
+
+            if p_uid in uid_set_dict:
+                # 设备版本号
+                uidversion = uid_set_dict[p_uid]['version']
+                if len(uidversion) > 6:
+                    uidversion = uidversion[0: uidversion.rfind('.')]
+                p['uid_version'] = uidversion
+                p['ucode'] = uid_set_dict[p_uid]['ucode']
+                p['detect_interval'] = uid_set_dict[p_uid]['detect_interval']
+                p['detect_status'] = uid_set_dict[p_uid]['detect_status']
+                p['detect_group'] = uid_set_dict[p_uid]['detect_group']
+                p['region_alexa'] = uid_set_dict[p_uid]['region_alexa']
+                p['is_alexa'] = uid_set_dict[p_uid]['is_alexa']
+                p['deviceModel'] = uid_set_dict[p_uid]['deviceModel']
+                p['TimeZone'] = uid_set_dict[p_uid]['TimeZone']
+                p['TimeStatus'] = uid_set_dict[p_uid]['TimeStatus']
+                p['SpaceUsable'] = uid_set_dict[p_uid]['SpaceUsable']
+                p['SpaceSum'] = uid_set_dict[p_uid]['SpaceSum']
+                p['MirrorType'] = uid_set_dict[p_uid]['MirrorType']
+                p['RecordType'] = uid_set_dict[p_uid]['RecordType']
+                p['OutdoorModel'] = uid_set_dict[p_uid]['OutdoorModel']
+                p['WIFIName'] = uid_set_dict[p_uid]['WIFIName']
+                p['isDetector'] = uid_set_dict[p_uid]['isDetector']
+                p['DetectorRank'] = uid_set_dict[p_uid]['DetectorRank']
+                p['is_human'] = uid_set_dict[p_uid]['is_human']
+                p['is_custom_voice'] = uid_set_dict[p_uid]['is_custom_voice']
+                p['is_ptz'] = uid_set_dict[p_uid]['is_ptz']
+                p['channels'] = uid_set_dict[p_uid]['channels']
+                p['double_wifi'] = uid_set_dict[p_uid]['double_wifi']
+                p['is_ai'] = uid_set_dict[p_uid]['is_ai']
+                # 设备昵称 调用影子信息昵称,先阶段不可
+                if uid_set_dict[p_uid]['nickname']:
+                    p['NickName'] = uid_set_dict[p_uid]['nickname']
+            else:
+                # 设备版本号
+                p['uid_version'] = ''
+                p['ucode'] = ''
+            data.append(p)
+        return data
+
+    @classmethod
+    def get_family_list(cls, user_id, request_dict, response):
+        """
+        查询我的家庭列表
+        @param user_id: 用户id
+        @param request_dict: 请求
+        @param response: 响应
+        @return: 家庭列表items
+        """
+        lang = request_dict.get('lang', 'cn')
+        if user_id:
+            with transaction.atomic():
+                user_family_qs = UserFamily.objects.filter(user_id=user_id)
+                if not user_family_qs.exists():
+                    n_time = int(time.time())
+                    device_user = Device_User.objects.get(userID=user_id)
+                    # 创建默认家庭使用用户名或者邮箱作为名称
+                    family_name = device_user.username if device_user.username else device_user.userEmail
+                    family_name = family_name + "的家" if lang == 'cn' else family_name + " home"
+                    user_family = UserFamily.objects.create(user_id=user_id, name=family_name,
+                                                            updated_time=n_time,
+                                                            created_time=n_time)
+                    if user_family.id:
+                        member_permission_qs = FamilyMemberPermission.objects.filter(no='001').values('id')
+                        permission_id = member_permission_qs.first()['id']
+                        FamilyMember.objects.create(family_id=user_family.id, user_id=user_id,
+                                                    user_name=device_user.username, identity=1,
+                                                    permission_id=int(permission_id), sort=1, updated_time=n_time,
+                                                    created_time=n_time)
+                        cls.family_device_binding(user_id, family_id=user_family.id)
+
+                family_member_qs = FamilyMember.objects.filter(user_id=user_id) \
+                    .order_by('sort').values('identity', 'family_id', 'family__name', 'permission_id', 'permission__no',
+                                             'family__location', 'user__username', 'user__userIconUrl')
+                items = EquipmentFamilyView.family_info_list(family_member_qs)
+                return response.json(0, items)
+        return response.json(309)
+
+    @staticmethod
+    def who_family_list(user_id, response):
+        """
+        查询我加入的家庭集合与我创建的家庭集合
+        @param user_id:
+        @param response:
+        @return:
+        """
+        join_family_qs = FamilyMember.objects.filter(user_id=user_id, identity=0) \
+            .order_by('sort').values('identity', 'family_id', 'family__name', 'permission_id', 'permission__no',
+                                     'family__location', 'user__username', 'user__userIconUrl')
+        join_family_list = EquipmentFamilyView.family_info_list(join_family_qs)
+
+        my_family_qs = FamilyMember.objects.filter(user_id=user_id, identity=1) \
+            .order_by('sort').values('identity', 'family_id', 'family__name', 'permission_id', 'permission__no',
+                                     'family__location', 'user__username', 'user__userIconUrl')
+        my_family_list = EquipmentFamilyView.family_info_list(my_family_qs)
+
+        return response.json(0, {'myFamilyList': my_family_list, 'joinFamilyList': join_family_list})
+
+    @staticmethod
+    def family_info_list(family_member_qs):
+        items = []
+        data = {}
+        for item in family_member_qs:
+            data['familyId'] = item['family_id']
+            data['identity'] = item['identity']
+            data['familyName'] = item['family__name']
+            data['permissionId'] = item['permission_id']
+            data['permissionNo'] = item['permission__no']
+            data['familyLocation'] = item['family__location']
+            data['userName'] = item['user__username']
+            data['userIconUrl'] = item['user__userIconUrl']
+            room_qs = FamilyRoom.objects.filter(family_id=data['familyId']).order_by('sort') \
+                .values('id', 'name')
+            data['rooms'] = list(room_qs)
+            items.append(data)
+            data = {}
+        return items
+
+    @classmethod
+    def get_family_setting(cls, request_dict, response):
+        """
+        家庭设置
+        @param request_dict: 请求
+        @param response: 响应
+        @return: 家庭列表items
+        """
+        family_id = request_dict.get('familyId', None)
+        if not family_id:
+            return response.json(444)
+        family_id = int(family_id)
+        user_family_qs = UserFamily.objects.filter(id=family_id).values('id', 'name', 'location')
+        if not user_family_qs.exists():
+            return response.json(404)
+        family_dict = user_family_qs.first()
+        device_count = FamilyRoomDevice.objects.filter(family_id=family_id, sub_device=0).count()
+        family_dict['deviceCount'] = device_count
+        family_dict['roomCount'] = FamilyRoom.objects.filter(family_id=family_id).count()
+
+        family_member_qs = FamilyMember.objects.filter(family_id=family_id)
+        family_member_qs = family_member_qs.values('identity', 'family_id',
+                                                   'permission_id',
+                                                   'permission__no',
+                                                   'user__username',
+                                                   'user_id',
+                                                   'user__userIconUrl',
+                                                   'user__NickName',
+                                                   'user__phone',
+                                                   'user__userEmail',
+                                                   'id')
+        family_member_qs = family_member_qs.order_by('-identity').order_by('sort')
+        items = []
+        data = {}
+        for item in family_member_qs:
+            data['userName'] = item['user__username']
+            data['userIconUrl'] = item['user__userIconUrl']
+            data['userId'] = item['user_id']
+            data['identity'] = item['identity']
+            data['permissionId'] = item['permission_id']
+            data['permissionNo'] = item['permission__no']
+            data['nickName'] = item['user__NickName']
+            data['phone'] = item['user__phone']
+            data['userEmail'] = item['user__userEmail']
+            data['memberId'] = item['id']
+            items.append(data)
+            data = {}
+        family_dict['members'] = items
+        return response.json(0, family_dict)
+
+    @classmethod
+    def family_save(cls, user_id, request_dict, response):
+        """
+        家庭保存
+        @param user_id: 用户id
+        @param request_dict: 参数
+        @param response: 响应
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        family_name = request_dict.get('familyName', None)
+        location = request_dict.get('location', None)
+        with transaction.atomic():
+            now_time = int(time.time())
+            if family_id:
+                is_owner = cls.get_family_owner(user_id, family_id)
+                if not is_owner:
+                    return response.json(404)
+                family_member = FamilyMember.objects.filter(family_id=family_id, user_id=user_id)
+                if family_member.exists():
+                    family_member = family_member.first()
+                    if family_member.identity == 0:
+                        return response.json(404)
+                    family_qs = UserFamily.objects.filter(id=family_id)
+                    if family_qs.exists():
+                        data = {
+                            'updated_time': now_time
+                        }
+                        if family_name:
+                            data['name'] = family_name
+                        if location:
+                            data['location'] = location
+                        family_qs.update(**data)
+                        return response.json(0)
+            data = {'user_id': user_id, 'updated_time': now_time, 'created_time': now_time}
+            if family_name:
+                data['name'] = family_name
+                if location:
+                    data['location'] = location
+                UserFamily.objects.create(**data)
+                return response.json(0)
+            return response.json(444)
+
+    @classmethod
+    def family_room_device_save(cls, family_id, room_id, device_id):
+        """
+        设备与家庭房间保存
+        @param family_id: 家庭id
+        @param room_id: 房间id
+        @param device_id: 设备id
+        @return: Boole
+        """
+        now_time = int(time.time())
+        family_room_device = FamilyRoomDevice.objects.filter(device_id=device_id)
+        if family_room_device.exists():
+            return False
+        data = {
+            'family_id': int(family_id),
+            'device_id': device_id,
+            'updated_time': now_time,
+            'created_time': now_time
+        }
+        if room_id:
+            room_id = int(room_id)
+            if FamilyRoom.objects.filter(id=room_id).exists():
+                data['room_id'] = room_id
+        FamilyRoomDevice.objects.create(**data)
+        return True
+
+    @classmethod
+    def family_device_binding(cls, user_id, family_id):
+        """
+        用户旧设备与默认家庭进行绑定
+        @param user_id:
+        @param family_id:
+        @return: True
+        """
+        device_info_qs = Device_Info.objects.filter(userID=user_id)
+        device_info_qs = device_info_qs.filter(~Q(isExist=0)).values('id')
+        if device_info_qs.exists():
+            with transaction.atomic():
+                not_time = time.time()
+                device_list = []
+                for item in device_info_qs:
+                    device_id = item['id']
+                    family_device_qs = FamilyRoomDevice.objects.filter(device_id=device_id)
+                    if not family_device_qs.exists():
+                        # 设备绑定家庭
+                        device_list.append(FamilyRoomDevice(family_id=family_id, device_id=device_id,
+                                                            created_time=not_time,
+                                                            updated_time=not_time))
+                if device_list:
+                    FamilyRoomDevice.objects.bulk_create(device_list)
+        return True
+
+    @classmethod
+    def get_family_room_list(cls, request_dict, response):
+        """
+        获取房间列表并统计该房间下有几台设备
+        @param request_dict: 请求参数
+        @param response: 响应参数
+        @return: total;data
+        """
+        family_id = request_dict.get('familyId', None)
+        if not family_id:
+            return response.json(444)
+        count = FamilyRoomDevice.objects.filter(family_id=family_id).values('device_id').annotate(
+            count=Count('device_id')).count()
+
+        room_qs = FamilyRoom.objects.filter(family_id=family_id).order_by('sort')
+        total = room_qs.count()
+        room_qs = room_qs.values('id', 'name', 'sort')
+        room_list = []
+        if not room_qs.exists():
+            return response.json(0, {'total': 0, 'data': room_list, 'deviceTotal': count})
+        for item in room_qs:
+            item['deviceCount'] = FamilyRoomDevice.objects.filter(family_id=family_id, room_id=item['id']).count()
+            room_list.append(item)
+        return response.json(0, {'total': total, 'data': room_list, 'deviceTotal': count})
+
+    @classmethod
+    def room_save(cls, request_dict, response):
+        """
+        房间保存
+        @param request_dict: 请求参数
+        @param response: 响应参数
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        room_name = request_dict.get('roomName', None)
+        room_id = request_dict.get('roomId', None)
+        if not all([family_id, room_name]):
+            return response.json(444)
+        with transaction.atomic():
+            now_time = int(time.time())
+            if room_id:
+                room_qs = FamilyRoom.objects.filter(id=int(room_id))
+                if room_qs.exists():
+                    room_qs.update(name=room_name, updated_time=now_time)
+                    return response.json(0)
+            room_qs = FamilyRoom.objects.filter(family_id=family_id, name=room_name)
+
+            if room_qs.exists():
+                return response.json(174)
+            FamilyRoom.objects.create(family_id=family_id, name=room_name, updated_time=now_time,
+                                      created_time=now_time)
+        return response.json(0)
+
+    @classmethod
+    def changes_member_permission(cls, app_user_id, request_dict, response):
+        """
+        更新家庭成员权限
+        @param app_user_id: 当前app登录用户
+        @param request_dict: 请求参数
+        @param response: 响应实体
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        user_id = request_dict.get('userId', None)
+        no = request_dict.get('no', None)
+        if not all([family_id, user_id, no]):
+            return response.json(444)
+        owner = cls.get_family_owner(app_user_id, family_id)
+        if not owner:
+            return response.json(404)
+        permission_qs = FamilyMemberPermission.objects.filter(no=no).values()
+        if permission_qs.exists():
+            permission_qs = permission_qs.first()
+            p_id = permission_qs['id']
+            FamilyMember.objects.filter(family_id=family_id, user_id=user_id).update(permission_id=p_id)
+        return response.json(0)
+
+    @classmethod
+    def family_member_del(cls, app_user_id, request_dict, response):
+        """
+        家庭成员删除
+        @param app_user_id: 当前app登录用户
+        @param request_dict: 请求参数
+        @param response: 响应实体
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        user_id = request_dict.get('userId', None)
+        if not all([family_id, user_id]):
+            return response.json(444)
+        owner = cls.get_family_owner(app_user_id, family_id)
+        if not owner:
+            return response.json(404)
+        family_member_qs = FamilyMember.objects.filter(family_id=family_id, user_id=user_id)
+        if family_member_qs.exists():
+            family_member_qs.delete()
+        return response.json(0)
+
+    @classmethod
+    def get_member_permission_list(cls, app_user_id, request_dict, response):
+        """
+        获取用户权限列表
+        @param app_user_id: 当前app登录用户
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        user_id = request_dict.get('userId', app_user_id)
+        if not family_id:
+            return response.json(404)
+        result = cls.get_member_permission_by_family_id(user_id, family_id)
+        return response.json(0, result)
+
+    @classmethod
+    def get_member_permission_by_family_id(cls, user_id, family_id):
+        """
+        获取权限列表并返回当前user_id所在家庭中权限
+        @param user_id:
+        @param family_id:
+        @return:
+        """
+        member_qs = FamilyMember.objects.filter(family_id=family_id)
+        if user_id:
+            member_qs = member_qs.filter(user_id=user_id).values()
+            if member_qs.exists():
+                member_qs = member_qs.first()
+        permission = FamilyMemberPermission.objects.all().values('id', 'no')
+        data_list = []
+        this_permission = {}
+        result = {}
+        for item in permission:
+            if item['id'] == member_qs['permission_id']:
+                this_permission['id'] = item['id']
+                this_permission['no'] = item['no']
+            data_list.append(item)
+        result['memberPermission'] = this_permission
+        result['permissionList'] = data_list
+        return result
+
+    @classmethod
+    def get_member_permission_details(cls, user_id, family_id):
+        """
+        根据用户id获取家庭设备权限
+        @param user_id:
+        @param family_id:
+        @return: 权限编号 001:所有权限,002:查看设备,003:暂无权限
+        """
+        member_qs = FamilyMember.objects.filter(family_id=family_id, user_id=user_id).values()
+        if member_qs.exists():
+            member_qs = member_qs.first()
+            permission_id = member_qs['permission_id']
+            permission_qs = FamilyMemberPermission.objects.filter(id=permission_id).values('no')
+            return permission_qs.first()['no']
+        return ''
+
+    @classmethod
+    def get_family_owner(cls, user_id, family_id):
+        """
+        判断是否是家庭主用户
+        @param user_id:
+        @param family_id:
+        @return:
+        """
+        user_family_qs = UserFamily.objects.filter(id=family_id, user_id=user_id)
+        if user_family_qs.exists():
+            return True
+        return False

+ 263 - 0
Controller/SensorGateway/GatewayDeviceController.py

@@ -0,0 +1,263 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : GatewayDeviceController.py
+@Time    : 2022/6/6 13:50
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+from django.db import transaction
+from django.db.models import Q
+from django.views.generic.base import View
+
+from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
+from Model.models import FamilyRoomDevice, FamilyRoom, GatewaySubDevice, Device_Info, UserFamily, FamilyMember, \
+    UidSetModel, iotdeviceInfoModel
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+
+
+# 网关主页
+class GatewayDeviceView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+
+        token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+        lang = request_dict.get('lang', None)
+        response = ResponseObject(lang) if lang else ResponseObject(token.lang)
+        if token.code != 0:
+            return response.json(token.code)
+        user_id = token.userID
+
+        # 网关设备
+        if operation == 'list':
+            return self.gateway_device_list(request_dict, response)
+        elif operation == 'del':
+            return self.gateway_device_del(user_id, request_dict, response)
+        elif operation == 'update':
+            return self.gateway_device_update(user_id, request_dict, response)
+        elif operation == 'my/family/list':
+            return self.my_family_list(user_id, response)
+        elif operation == 'location-setting':
+            return self.device_location_setting(user_id, request_dict, response)
+
+    @classmethod
+    def device_location_setting(cls, user_id, request_dict, response):
+        """
+        网关位置迁移
+        @param user_id: 用户id
+        @param request_dict: 请求参数字典
+        @param response: 响应对象
+        @return: []
+        """
+        device_id = request_dict.get('deviceId', None)
+        family_id = request_dict.get('familyId', None)
+        room_id = request_dict.get('roomId', None)
+        if not all([device_id, family_id]):
+            return response.json(444)
+        family_id = int(family_id)
+        permission = EquipmentFamilyView.get_member_permission_details(user_id, family_id)
+        if not permission or permission == '003':
+            return response.json(404)
+        try:
+            with transaction.atomic():
+                family_room_device_qs = FamilyRoomDevice.objects.filter(device_id=device_id, family_id=family_id)
+                if family_room_device_qs.exists():
+                    family_room_device_qs = family_room_device_qs.filter(sub_device=0)
+                    if family_room_device_qs.exists() and room_id:
+                        family_room_device_qs.update(room_id=int(room_id))
+                else:
+                    user_family_qs = UserFamily.objects.filter(id=family_id)
+                    if not user_family_qs:
+                        return response.json(173)
+                    family_room_device_qs = FamilyRoomDevice.objects.filter(device_id=device_id)
+                    if family_room_device_qs.exists():
+                        param_data = {'family_id': family_id, 'room_id': 0}
+                        if room_id:
+                            param_data['room_id'] = room_id
+                        family_room_device_qs.update(**param_data)
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def gateway_device_update(cls, user_id, request_dict, response):
+        """
+        网关设备修改名称
+        @param user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        device_name = request_dict.get('deviceName')
+        device_id = request_dict.get('deviceId')
+        if not all([device_name, device_id]):
+            return response.json(444)
+        device_info_qs = Device_Info.objects.filter(userID_id=user_id, id=device_id)
+        if device_info_qs.exists():
+            device_info_qs.update(NickName=device_name)
+        return response.json(0)
+
+    @classmethod
+    def my_family_list(cls, user_id, response):
+        """
+        我的家庭列表
+        @param user_id:
+        @param response:
+        @return:
+        """
+        user_family_qs = UserFamily.objects.filter(user_id=user_id).values()
+        family_list = []
+        if user_family_qs.exists():
+            family_member_qs = FamilyMember.objects.filter(user_id=user_id, identity=1) \
+                .order_by('sort').values('identity', 'family_id', 'family__name', 'permission_id', 'permission__no',
+                                         'family__location', 'user__username', 'user__userIconUrl')
+            items = EquipmentFamilyView.family_info_list(family_member_qs)
+            return response.json(0, items)
+        return response.json(0, family_list)
+
+    @classmethod
+    def gateway_device_del(cls, user_id, request_dict, response):
+        """
+        网关设备删除或删除子设备
+        @param user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        device_id = request_dict.get('deviceId')
+        family_id = request_dict.get('familyId')
+        # 1 删除网关 否则删除子设备
+        sub_ids = request_dict.get('subIds')
+        if not family_id:
+            return response.json(444)
+        permission = EquipmentFamilyView.get_member_permission_details(user_id, family_id)
+        if not permission or permission == '003':
+            return response.json(404)
+        try:
+            with transaction.atomic():
+                if device_id:
+                    device_qs = Device_Info.objects.filter(id=device_id)
+                    if device_qs.exists():
+                        family_device_qs = FamilyRoomDevice.objects.filter(device_id=device_id)
+                        if family_device_qs.exists():
+                            family_device_qs.delete()
+                        gateway_qs = GatewaySubDevice.objects.filter(device_id=device_id)
+                        if gateway_qs.exists():
+                            gateway_qs.delete()
+                        uid_set_qs = UidSetModel.objects.filter(uid=device_qs.first().UID)
+                        if uid_set_qs.exists():
+                            uid_set_qs.delete()
+                        device_qs.delete()
+                elif sub_ids:
+                    sub_ids = sub_ids.split(',')
+                    ids = []
+                    for item in sub_ids:
+                        sub_id = int(item)
+                        ids.append(sub_id)
+                    family_device_qs = FamilyRoomDevice.objects.filter(sub_device__in=ids)
+                    if family_device_qs.exists():
+                        family_device_qs.delete()
+                    gateway_sub_qs = GatewaySubDevice.objects.filter(id__in=ids)
+                    if gateway_sub_qs.exists():
+                        gateway_sub_qs.delete()
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def gateway_device_list(cls, request_dict, response):
+        """
+        网关设备列表
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        device_id = request_dict.get('deviceId', None)
+        if not device_id:
+            return response.json(444)
+        device_qs = FamilyRoomDevice.objects.filter(device_id=device_id, sub_device=0)
+        if not device_qs.exists():
+            return response.json(173)
+        try:
+            device_qs = device_qs.values('family_id', 'device_id', 'room_id', 'device__Type', 'device__NickName',
+                                         'device__UID',
+                                         'device__serial_number')
+            device_qs = device_qs.first()
+            room_id = device_qs['room_id']
+            family_id = device_qs['family_id']
+            gateway_room_name = ''
+            if room_id:
+                room_qs = FamilyRoom.objects.filter(id=room_id)
+                gateway_room_name = room_qs.first().name if room_qs.exists() else ''
+
+            iot_device_info_qs = iotdeviceInfoModel.objects.filter(
+                serial_number=device_qs['device__serial_number'][0:6])
+            iot_data = {}
+            if iot_device_info_qs.exists():
+                iot_device_Info = iot_device_info_qs.values('endpoint', 'token_iot_number')
+                iot_data = {
+                    'endpoint': iot_device_Info[0]['endpoint'],
+                    'token_iot_number': iot_device_Info[0]['token_iot_number']
+                }
+            gateway = {
+                'deviceId': device_qs['device_id'],
+                'deviceType': device_qs['device__Type'],
+                'deviceNickName': device_qs['device__NickName'],
+                'UID': device_qs['device__UID'],
+                'serialNumber': device_qs['device__serial_number'],
+                'roomName': gateway_room_name,
+                'iot': iot_data,
+                'roomId': room_id,
+                'familyId': family_id
+            }
+            family_device_qs = FamilyRoomDevice.objects.filter(device_id=device_id)
+            family_device_qs = family_device_qs.filter(~Q(sub_device=0)).order_by('-created_time')
+
+            sub_device = []
+            if family_device_qs.exists():
+                family_device_qs = family_device_qs.values()
+                for item in family_device_qs:
+                    sub_id = item['sub_device']
+                    gateway_sub_qs = GatewaySubDevice.objects.filter(device_id=device_id, id=sub_id).values(
+                        'id', 'device_type',
+                        'nickname',
+                        'src_addr', 'status',
+                        'created_time', 'ieee_addr')
+                    if not gateway_sub_qs.exists():
+                        continue
+                    room_id = item['room_id']
+                    room_qs = FamilyRoom.objects.filter(id=room_id)
+                    gateway_room_name = room_qs.first().name if room_qs.exists() else ''
+                    gateway_sub_qs = gateway_sub_qs.first()
+                    sub_device.append({
+                        'gatewaySubId': gateway_sub_qs['id'],
+                        'nickName': gateway_sub_qs['nickname'],
+                        'deviceType': gateway_sub_qs['device_type'],
+                        'srcAddr': gateway_sub_qs['src_addr'],
+                        'status': gateway_sub_qs['status'],
+                        'createdTime': gateway_sub_qs['created_time'],
+                        'roomName': gateway_room_name,
+                        'roomId': room_qs.first().id if room_qs.exists() else 0,
+                        'ieeeAddr': gateway_sub_qs['ieee_addr'],
+                        'familyId': family_id,
+                    })
+            res = {'gateway': gateway, 'sub_device': sub_device, 'sub_device_count': len(sub_device), 'scene_count': 0}
+            return response.json(0, res)
+
+        except Exception as e:
+            print(e.args)
+            return response.json(500)

+ 551 - 0
Controller/SensorGateway/GatewayFamilyMemberController.py

@@ -0,0 +1,551 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : GatewayFamilyMemberController.py
+@Time    : 2022/5/25 10:21
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+
+import json
+import time
+
+from django.db import transaction
+from django.views.generic.base import View
+
+from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
+from Model.models import UserFamily, FamilyMemberJoin, FamilyMember, SysMsgModel, FamilyMemberPermission, \
+    Device_User, FamilyRoomDevice, FamilyRoom
+from Object.RedisObject import RedisObject
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Service.CommonService import CommonService
+
+
+# 家庭房间管理
+class GatewayFamilyMemberView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        token = request.META.get('HTTP_AUTHORIZATION')
+        token = TokenObject(token)
+        lang = request_dict.get('lang', None)
+        response = ResponseObject(lang) if lang else ResponseObject(token.lang)
+        if token.code != 0:
+            return response.json(token.code)
+        app_user_id = token.userID
+        # 添加设备关联房间
+        if operation == 'join':
+            return self.member_join(app_user_id, request_dict, response)
+        elif operation == 'join/page':
+            return self.member_join_page(request_dict, response)
+        elif operation == 'qrcode/generate':
+            return self.family_generate_token(app_user_id, request_dict, response)
+        elif operation == 'qrcode/check':
+            return self.check_qrcode(request_dict, response)
+        elif operation == 'join/info':
+            return self.member_join_info(request_dict, response)
+        elif operation == 'join/update':
+            return self.user_join_confirm(request_dict, response)
+        elif operation == 'del':
+            return self.member_del(app_user_id, request_dict, response)
+        elif operation == 'created':
+            return self.family_created(app_user_id, request_dict, response)
+        elif operation == 'del/home':
+            return self.del_home(app_user_id, request_dict, response)
+        elif operation == 'join/del':
+            return self.member_join_del(app_user_id, request_dict, response)
+
+    @classmethod
+    def member_join_del(cls, app_user_id, request_dict, response):
+        """
+        删除最近联系人
+        @param app_user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        join_ids = request_dict.get('joinIds', None)
+        family_id = request_dict.get('familyId', None)
+        if not join_ids:
+            return response.json()
+        is_owner = EquipmentFamilyView.get_family_owner(app_user_id, family_id)
+        if not is_owner:
+            return response.json(404)
+        try:
+            with transaction.atomic():
+                items = join_ids.split(',')
+                for item in items:
+                    family_member_join_qs = FamilyMemberJoin.objects.filter(id=int(item))
+                    if family_member_join_qs.exists():
+                        family_member_join_qs.delete()
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def del_home(cls, app_user_id, request_dict, response):
+        """
+        删除家庭
+        @param app_user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        if not family_id:
+            return response.json(444)
+        is_owner = EquipmentFamilyView.get_family_owner(app_user_id, family_id)
+        if not is_owner:
+            return response.json(404)
+        family_id = int(family_id)
+        try:
+            with transaction.atomic():
+                family_member_qs = FamilyMember.objects.filter(family_id=family_id, identity=0)
+                if family_member_qs.exists():
+                    return response.json(10057)
+                family_room_dev_qs = FamilyRoomDevice.objects.filter(family_id=family_id)
+                if family_room_dev_qs.exists():
+                    return response.json(10057)
+                family_room_qs = FamilyRoom.objects.filter(family_id=family_id)
+                if family_room_qs.exists():
+                    family_room_qs.delete()
+                FamilyMember.objects.filter(family_id=family_id).delete()
+                user_family_qs = UserFamily.objects.filter(id=family_id)
+                if user_family_qs.exists():
+                    user_family_qs.delete()
+                    return response.json(0)
+            return response.json(176)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def family_created(cls, app_user_id, request_dict, response):
+        """
+        创建家庭
+        @param app_user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        family_name = request_dict.get('familyName', None)
+        if not family_name:
+            return response.json(444)
+        n_time = int(time.time())
+        location = request_dict.get('location', '')
+        room_names = request_dict.get('roomNames', None)
+        user_family_qs = UserFamily.objects.filter(name=family_name, user_id=app_user_id)
+        if user_family_qs.exists():
+            return response.json(174)
+        try:
+            with transaction.atomic():
+                member_permission_qs = FamilyMemberPermission.objects.filter(no='001').values('id')
+                user_family = UserFamily.objects.create(user_id=app_user_id, name=family_name,
+                                                        location=location,
+                                                        updated_time=n_time,
+                                                        created_time=n_time)
+                if user_family.id:
+                    device_user = Device_User.objects.get(userID=app_user_id)
+                    permission_id = member_permission_qs.first()['id']
+                    FamilyMember.objects.create(family_id=user_family.id, user_id=app_user_id,
+                                                user_name=device_user.username, identity=1,
+                                                permission_id=int(permission_id), sort=1, updated_time=n_time,
+                                                created_time=n_time)
+                if room_names:
+                    names = room_names.split(',')
+                    rooms = []
+                    for index, item in enumerate(names):
+                        rooms.append(FamilyRoom(
+                            name=item,
+                            family_id=user_family.id,
+                            sort=index,
+                            updated_time=n_time,
+                            created_time=n_time
+                        ))
+                    FamilyRoom.objects.bulk_create(rooms)
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def member_del(cls, app_user_id, request_dict, response):
+        """
+        成员删除或退出
+        @param app_user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        member_id = request_dict.get('memberId', None)
+        family_id = request_dict.get('familyId', None)
+        if not family_id:
+            return response.json(444)
+        try:
+            family_id = int(family_id)
+            with transaction.atomic():
+                # 家庭所有者删除成员
+                if member_id:
+                    is_owner = EquipmentFamilyView.get_family_owner(app_user_id, family_id)
+                    if not is_owner:
+                        return response.json(404)
+                    member_id = int(member_id)
+                    family_member_qs = FamilyMember.objects.filter(id=member_id)
+                    if not family_member_qs.exists():
+                        return response.json(173)
+                    family_member_qs.delete()
+                    return response.json(0)
+                else:
+                    # 成员退出当前家庭
+                    family_member = FamilyMember.objects.filter(family_id=family_id, user_id=app_user_id, identity=1)
+                    if family_member.exists():
+                        return response.json(173)
+                    family_member_qs = FamilyMember.objects.filter(family_id=family_id, user_id=app_user_id)
+                    if not family_member_qs.exists():
+                        return response.json(173)
+                    family_member_qs.delete()
+                    return response.json(0)
+        except Exception as e:
+            return response.json(177, repr(e))
+
+    @classmethod
+    def user_join_confirm(cls, request_dict, response):
+        """
+        用户加入家庭确认
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        join_id = request_dict.get('joinId', None)
+        confirm = request_dict.get('confirm', None)
+        lang = request_dict.get('lang', 'en')
+        if not all([join_id, confirm]):
+            return response.json(444)
+        join_id = int(join_id)
+        family_join = FamilyMemberJoin.objects.filter(id=join_id, status=0)
+        if not family_join.exists():
+            return response.json(173)
+        family_member = FamilyMember.objects.filter(family_id=family_join.first().family_id,
+                                                    user_id=family_join.first().user_id)
+        if family_member.exists():
+            return response.json(174)
+        try:
+            now_time = int(time.time())
+            with transaction.atomic():
+                family_join.update(status=2 if confirm == 'confirm' else 1)
+                family_join = FamilyMemberJoin.objects.filter(id=join_id)
+                family_join = family_join.values('id', 'user_id', 'user__username', 'user__NickName', 'family__name',
+                                                 'family_id', 'family__user_id', 'status', 'type', 'updated_time')
+                family_join = family_join.first()
+                nick_name = family_join['user__NickName']
+                family_name = family_join['family__name']
+                join_type = family_join['type']
+                data = {
+                    'addTime': now_time,
+                    'updTime': now_time,
+                    'userID_id': family_join['user_id'] if join_type == 1 else family_join['family__user_id'],
+                    'eventType': 0
+                }
+                if confirm == 'confirm':
+                    msg_text = cls.get_confirm_text(nick_name, family_name, join_type, True, lang)
+                    p_id = FamilyMemberPermission.objects.filter(no='002').values('id').first()
+                    p_id = p_id['id']
+                    FamilyMember.objects.create(family_id=family_join['family_id'], updated_time=now_time,
+                                                user_id=family_join['user_id'],
+                                                created_time=now_time,
+                                                permission_id=p_id,
+                                                user_name=family_join['user__username'])
+                elif confirm == 'refusal':
+                    msg_text = cls.get_confirm_text(nick_name, family_name, join_type, False, lang)
+                else:
+                    ex = Exception("data is null")
+                    raise ex
+                data['msg'] = msg_text
+                data['uid'] = family_join['id']
+                SysMsgModel.objects.create(**data)
+            return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def get_confirm_text(cls, nick_name, family_name, join_type, is_confirm, lang='en'):
+        # join_type == 1等于扫码请求加u人
+        if is_confirm:
+            if join_type == 1:
+                if lang == 'cn':
+                    msg_text = '{} 同意你的请求'.format(family_name)
+                else:
+                    msg_text = '{} confirm to your request'.format(family_name)
+            else:
+                if lang == 'cn':
+                    msg_text = '{}同意加入{}'.format(nick_name, family_name)
+                else:
+                    msg_text = '{} confirm to join {}'.format(nick_name, family_name)
+        else:
+            if join_type == 1:
+                if lang == 'cn':
+                    msg_text = '{}拒绝你的请求'.format(family_name)
+                else:
+                    msg_text = '{} refused your request'.format(family_name)
+
+            else:
+                if lang == 'cn':
+                    msg_text = '{}拒绝加入{}'.format(nick_name, family_name)
+                else:
+                    msg_text = '{} refused to join '.format(family_name)
+        return msg_text
+
+    @classmethod
+    def member_join_info(cls, request_dict, response):
+        """
+        查询加入家庭信息
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        join_id = request_dict.get('joinId', None)
+        if not join_id:
+            return response.json(444)
+        join_id = int(join_id)
+        family_join_qs = FamilyMemberJoin.objects.filter(id=join_id)
+        if not family_join_qs.exists():
+            return response.json(173)
+        family_join_qs = family_join_qs.values('type', 'user__NickName', 'family__name', 'status', 'id',
+                                               'family__user__NickName')
+        family_join_qs = family_join_qs.first()
+        nick_name = family_join_qs['user__NickName']
+        if family_join_qs['type'] == 0:
+            nick_name = family_join_qs['family__user__NickName']
+        return response.json(0, {
+            'id': family_join_qs['id'],
+            'type': family_join_qs['type'],
+            'nickName': nick_name,
+            'familyName': family_join_qs['family__name'],
+            'status': family_join_qs['status'],
+        })
+
+    @classmethod
+    def member_join(cls, app_user_id, request_dict, response):
+        """
+        家庭成员加入
+        @param app_user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        invite = request_dict.get('QRCodeInvite', 0)
+        user_id = request_dict.get('app_user_id', None)
+        lang = request_dict.get('lang', 'en')
+        if not all([family_id, invite]):
+            return response.json(444)
+        invite = int(invite)
+        family_id = int(family_id)
+        now_time = int(time.time())
+        # 判断当前家庭是否已有该成员
+        if invite == 1:
+            family_qs = FamilyMember.objects.filter(family_id=family_id, user_id=app_user_id)
+        elif user_id:
+            family_qs = FamilyMember.objects.filter(family_id=family_id, user_id=user_id)
+        else:
+            return response.json(173)
+        if family_qs.exists():
+            return response.json(174)
+        try:
+            user_family_qs = UserFamily.objects.filter(id=family_id)
+            if not user_family_qs:
+                return response.json(173)
+            user_family = user_family_qs.first()
+            family_name = user_family.name
+            data = {
+                'addTime': now_time,
+                'updTime': now_time,
+                'eventType': 705
+            }
+            # 请求加入家庭,用户信息
+            user_qs = Device_User.objects.filter(userID=app_user_id)
+            nick_name = user_qs.first().NickName
+
+            if invite == 1:
+                msg_text = cls.get_msg_text(nick_name, family_name, lang, True)
+                # 通知对象 家庭所有者
+                join_user_id = app_user_id
+                data['userID_id'] = user_family.user_id
+            elif app_user_id:
+                msg_text = cls.get_msg_text(nick_name, family_name, lang, False)
+                # 通知对象 被邀请人
+                join_user_id = user_id
+                data['userID_id'] = user_id
+            else:
+                return response.json(173)
+            data['msg'] = msg_text
+            with transaction.atomic():
+                member_user_id = user_id if user_id else app_user_id
+                member_join_qs = FamilyMemberJoin.objects.filter(family_id=family_id, user_id=member_user_id)
+                if member_join_qs.exists():
+                    member_join_qs.update(status=0, updated_time=now_time)
+                    data['uid'] = member_join_qs.first().id
+                    SysMsgModel.objects.create(**data)
+                    return response.json(0)
+                family_user_join = FamilyMemberJoin.objects.create(family_id=family_id, user_id=join_user_id,
+                                                                   status=0,
+                                                                   updated_time=now_time,
+                                                                   created_time=now_time,
+                                                                   type=invite)
+                data['uid'] = family_user_join.id
+                SysMsgModel.objects.create(**data)
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def get_msg_text(cls, nick_name, family_name, lang, is_invite=False):
+        """
+        系统消息通知内容,中英文判断
+        @param nick_name:
+        @param family_name:
+        @param lang:
+        @param is_invite:
+        @return:
+        """
+        if lang and lang == 'cn':
+            if is_invite:
+                msg_text = '{}请求加入你的{}'.format(nick_name, family_name)
+            else:
+                msg_text = '{}邀请你加入{}'.format(nick_name, family_name)
+        else:
+            if is_invite:
+                msg_text = '{} Request to join your Homegroup {}'.format(nick_name, family_name)
+            else:
+                msg_text = '{} invite you to join the Homegroup {}'.format(nick_name, family_name)
+
+        return msg_text
+
+    @classmethod
+    def member_join_page(cls, request_dict, response):
+        """
+        家庭成员邀请记录
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        page_no = request_dict.get('pageNo', None)
+        page_size = request_dict.get('pageSize', None)
+        family_id = request_dict.get('familyId', None)
+        if not all([page_no, page_size, family_id]):
+            return response.json(444)
+        member_join = FamilyMemberJoin.objects.filter(family_id=family_id).values('id', 'status', 'user__username',
+                                                                                  'user__userIconUrl', 'user__phone',
+                                                                                  'user__userEmail', 'updated_time',
+                                                                                  'created_time',
+                                                                                  'user__NickName')
+
+        page_no = int(page_no)
+        page_size = int(page_size)
+        member_join = member_join.order_by('-updated_time')[(page_no - 1) * page_size: page_no * page_size]
+        if not member_join.exists():
+            return response.json(0, [])
+        result = []
+        for item in member_join:
+            result.append({
+                'joinId': item['id'],
+                'status': item['status'],
+                'userName': item['user__username'],
+                'userIconUrl': item['user__userIconUrl'],
+                'phone': item['user__phone'],
+                'nickName': item['user__NickName'],
+                'userEmail': item['user__userEmail'],
+                'updatedTime': item['updated_time'],
+                'createdTime': item['created_time']
+            })
+        return response.json(0, result)
+
+    @classmethod
+    def family_generate_token(cls, app_user_id, request_dict, response):
+        """
+        获取家庭令牌信息
+        @param app_user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        if not family_id:
+            return response.json(444)
+        family_id = int(family_id)
+        family_qs = UserFamily.objects.filter(id=family_id, user_id=app_user_id) \
+            .values('name', 'user__userEmail',
+                    'user__userIconUrl',
+                    'user__phone', 'user__NickName',
+                    'user__username')
+        if not family_qs.exists():
+            return response.json(173)
+        family_qs = family_qs.first()
+        data = {'sharer': app_user_id, 'familyId': family_id}
+        # -----------------
+        # share_token = jwt.encode(data, '.#^^&', algorithm='HS256').decode('utf-8')
+        # +++++++++++++++++
+        redisObj = RedisObject()
+        share_token = str(int(time.time())) + CommonService.RandomStr(22)
+        if not redisObj.set_data(key=share_token, val=json.dumps(data), expire=300):
+            return response.json(10, '生成失败')
+        return response.json(0, {
+            'shareToken': share_token,
+            'userPhone': family_qs['user__phone'],
+            'nickName': family_qs['user__NickName'],
+            'userIconUrl': family_qs['user__userIconUrl'],
+            'userName': family_qs['user__username'],
+            'familyName': family_qs['name'],
+            'userEmail': family_qs['user__userEmail'],
+        })
+
+    @classmethod
+    def check_qrcode(cls, request_dict, response):
+        """
+        检查二维码是否过期
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        share_token = request_dict.get('shareToken', None)
+        if not share_token:
+            return response.json(444)
+        redisObj = RedisObject()
+        share_data = redisObj.get_data(key=share_token)
+        if not share_data:
+            return response.json(119)
+        data = json.loads(share_data)
+        sharer = data.get('sharer', None)
+        family_id = data.get('familyId', None)
+        if not all([sharer, family_id]):
+            return response.json(173)
+        family_id = int(family_id)
+        user_family_qs = UserFamily.objects.filter(id=family_id)
+        if not user_family_qs.exists():
+            return response.json(173)
+        user_family_qs = user_family_qs.values('id', 'name', 'user__userEmail',
+                                               'user__userIconUrl',
+                                               'user__phone', 'user__NickName',
+                                               'user__username')
+        return response.json(0, {
+            'familyId': user_family_qs[0]['id'],
+            'userPhone': user_family_qs[0]['user__phone'],
+            'nickName': user_family_qs[0]['user__NickName'],
+            'userIconUrl': user_family_qs[0]['user__userIconUrl'],
+            'userName': user_family_qs[0]['user__username'],
+            'familyName': user_family_qs[0]['name'],
+            'userEmail': user_family_qs[0]['user__userEmail'],
+        })

+ 253 - 0
Controller/SensorGateway/GatewayFamilyRoomController.py

@@ -0,0 +1,253 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : GatewayFamilyRoomController.py
+@Time    : 2022/5/24 19:43
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+
+from django.db import transaction
+from django.db.models import Q, Count, F
+from django.views.generic.base import View
+
+from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
+from Model.models import FamilyRoomDevice, FamilyRoom
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+
+
+# 家庭房间管理
+class GatewayFamilyRoomView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        token = request.META.get('HTTP_AUTHORIZATION')
+        token = TokenObject(token)
+        lang = request_dict.get('lang', token.lang)
+        response = ResponseObject(lang)
+        if token.code != 0:
+            return response.json(token.code)
+        app_user_id = token.userID
+        # 添加设备关联房间
+        if operation == 'device-changes':
+            return self.room_device_save(app_user_id, request_dict, response)
+        # 房间排序
+        elif operation == 'sort':
+            return self.room_sort_save(request_dict, response)
+        # 房间删除
+        elif operation == 'del':
+            return self.room_del(app_user_id, request_dict, response)
+        # 房间详情
+        elif operation == 'details':
+            return self.get_room_details(app_user_id, request_dict, response)
+        elif operation == 'all-devices':    # 家庭所有设备
+            return self.all_devices(request_dict, response)
+        elif operation == 'devices-sort':    # 家庭设备排序
+            return self.devices_sort(request_dict, response)
+        else:
+            return response.json(414)
+
+    @classmethod
+    def room_device_save(cls, app_user_id, request_dict, response):
+        """
+        房间加入设备or移除设备
+        @param app_user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        device_ids = request_dict.get('deviceIds', None)
+        room_id = request_dict.get('roomId', None)
+        if not all([family_id, room_id]):
+            return response.json(444)
+        family_id = int(family_id)
+        room_id = int(room_id)
+        is_owner = EquipmentFamilyView.get_family_owner(app_user_id, family_id)
+        if not is_owner:
+            return response.json(404)
+        try:
+            with transaction.atomic():
+                room_qs = FamilyRoom.objects.filter(family_id=family_id, id=room_id)
+                if not room_qs.exists():
+                    return response.json(173)
+                qs = FamilyRoomDevice.objects.filter(family_id=family_id, room_id=room_id)
+                if qs.exists():
+                    qs.update(room_id=0, sort=0)
+                if device_ids:
+                    device_ids = device_ids.split(',')
+                    for i, item in enumerate(device_ids):
+                        device_id = int(item)
+                        device_qs = FamilyRoomDevice.objects.filter(device_id=device_id)
+                        if device_qs.exists():
+                            device_qs.update(room_id=room_id, sort=i)
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def room_del(cls, user_id, request_dict, response):
+        """
+        房间多选删除
+        @param user_id: 当前登录用户id
+        @param request_dict: 请求参数
+        @param response: 响应参数
+        @return:
+        """
+        ids = request_dict.get('roomIds', None)
+        if not ids:
+            return response.json(444)
+        ids = ids.split(',')
+        room_id = ids[0]
+        room_info = FamilyRoom.objects.filter(id=room_id)
+        if not room_info.exists():
+            return response.json(173)
+        is_owner = EquipmentFamilyView.get_family_owner(user_id, room_info.first().family_id)
+        if not is_owner:
+            return response.json(404)
+        try:
+            with transaction.atomic():
+                for item in ids:
+                    room_id = int(item)
+                    room_device = FamilyRoomDevice.objects.filter(room_id=room_id)
+                    if room_device.exists():
+                        room_device.update(room_id=0)
+                    FamilyRoom.objects.filter(id=room_id).delete()
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def room_sort_save(cls, request_dict, response):
+        """
+        房间排序
+        @param request_dict: 请求参数
+        @param response: 响应参数
+        @return:
+        """
+        ids = request_dict.get('ids', None)
+        if not ids:
+            return response.json(444)
+        items = ids.split(',')
+        for item in items:
+            item = item.split('-')
+            room_id, sort = item[0], item[1]
+            family_room = FamilyRoom.objects.filter(id=int(room_id))
+            if family_room.exists():
+                family_room.update(sort=int(sort))
+        return response.json(0)
+
+    @classmethod
+    def get_room_details(cls, app_user_id, request_dict, response):
+        """
+        房间设备详情(所在当前房间下,和所在家庭不在当前房间下的主设备)
+        @param app_user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        room_id = request_dict.get('roomId', None)
+        if not all([family_id, room_id]):
+            return response.json(444)
+        is_owner = EquipmentFamilyView.get_family_owner(app_user_id, family_id)
+        if not is_owner:
+            return response.json(404)
+        family_id = int(family_id)
+        room_id = int(room_id)
+        room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id, room_id=room_id).order_by('sort').values(
+            'device_id').annotate(count=Count('device_id')).values('device_id', 'device__Type', 'device__NickName')
+        device_room = []
+        if room_device_qs.exists():
+            room_name = FamilyRoom.objects.filter(id=room_id)
+            for item in room_device_qs:
+                device_room.append({
+                    'deviceId': item['device_id'],
+                    'deviceType': item['device__Type'],
+                    'nickName': item['device__NickName'],
+                    'roomName': room_name.first().name if room_name.exists() else '',
+                })
+
+        device_not_room = []
+        device_not_room_qs = FamilyRoomDevice.objects.filter(family_id=family_id)
+        device_not_room_qs = device_not_room_qs.filter(~Q(room_id=room_id)).values('device_id').annotate(
+            count=Count('device_id')).values('room_id', 'device_id', 'device__Type', 'device__NickName')
+        if device_not_room_qs.exists():
+            for item in device_not_room_qs:
+                name = ''
+                if room_device_qs.exists():
+                    family_room_qs = FamilyRoom.objects.filter(id=item['room_id'])
+                    if family_room_qs.exists():
+                        name = family_room_qs.first().name
+                device_not_room.append({
+                    'deviceId': item['device_id'],
+                    'deviceType': item['device__Type'],
+                    'nickName': item['device__NickName'],
+                    'roomName': name
+                })
+        return response.json(0, {'deviceRooms': device_room, 'deviceNotRooms': device_not_room})
+
+    @staticmethod
+    def all_devices(request_dict, response):
+        """
+        家庭所有设备(网关和摄像头设备)
+        @param request_dict: 请求参数
+        @request_dict familyId: 家庭id
+        @param response: 响应参数
+        @return:
+        """
+        family_id = request_dict.get('familyId', None)
+        if not family_id:
+            return response.json(444)
+        try:
+            family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id, sub_device=0).\
+                annotate(type=F('device__Type'), nickname=F('device__NickName')).\
+                values('device_id', 'type', 'nickname', 'room_id').order_by('sort')
+            if not family_room_device_qs.exists():
+                return response.json(0, [])
+            # 查询房间名称
+            for device in family_room_device_qs:
+                room_id = device['room_id']
+                if room_id == 0:
+                    device['room'] = ''
+                else:
+                    family_room_qs = FamilyRoom.objects.filter(id=room_id).values('name')
+                    device['room'] = family_room_qs[0]['name'] if family_room_qs.exists() else ''
+                device.pop('room_id')
+            return response.json(0, list(family_room_device_qs))
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def devices_sort(request_dict, response):
+        """
+        家庭设备排序
+        @param request_dict: 请求参数
+        @request_dict 设备id: deviceIds
+        @param response: 响应参数
+        @return:
+        """
+        device_ids = request_dict.get('deviceIds', None)
+        if not device_ids:
+            return response.json(444)
+        try:
+            device_ids = device_ids.split(',')
+            with transaction.atomic():
+                for i, item in enumerate(device_ids):
+                    device_id = int(item)
+                    FamilyRoomDevice.objects.filter(device_id=device_id).update(sort=i)
+            return response.json(0)
+        except Exception as e:
+            return response.json(500, repr(e))

+ 0 - 0
SensorGateway/SensorGatewayController.py → Controller/SensorGateway/SensorGatewayController.py


+ 362 - 0
Controller/SensorGateway/SubDeviceController.py

@@ -0,0 +1,362 @@
+# -*- coding: utf-8 -*-
+"""
+@Author : Rocky
+@Time : 2022/5/25 15:17
+@File :SubDeviceController.py
+"""
+import time
+from collections import OrderedDict
+
+from django.db import transaction
+from django.db.models import Count
+from django.views import View
+
+from Model.models import Device_Info, GatewaySubDevice, FamilyRoomDevice, SensorRecord
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Service.CommonService import CommonService
+
+
+class GatewaySubDeviceView(View):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        token_obj = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+        lang = request_dict.get('lang', None)
+        response = ResponseObject(lang if lang else token_obj.lang)
+
+        if token_obj.code != 0:
+            return response.json(token_obj.code)
+        user_id = token_obj.userID
+        if operation == 'add':  # 添加子设备
+            return self.add_sub_device(request_dict, user_id, response)
+        elif operation == 'detail':  # 查询子设备信息
+            return self.query_sub_device(request_dict, response)
+        elif operation == 'update':  # 更新子设备信息
+            return self.sensor_update(request_dict, response)
+        elif operation == 'delete':  # 删除子设备
+            return self.delete(request_dict, user_id, response)
+        elif operation == 'records/tem-hum':  # 查询温湿度传感器记录
+            return self.records_tem_hum(request_dict, response)
+        elif operation == 'records':  # 查询其他传感器记录
+            return self.records(request_dict, response)
+        elif operation == 'records-date':  # 查询传感器记录日期
+            return self.records_date(request_dict, response)
+        else:
+            return response.json(414)
+
+    @staticmethod
+    def add_sub_device(request_dict, user_id, response):
+        """
+        添加子设备
+        @param request_dict: 请求参数
+        @request_dict serialNumber: 序列号
+        @request_dict deviceType: 设备类型
+        @request_dict nickName: 设备名
+        @request_dict ieeeAddr: 长地址
+        @request_dict srcAddr: 短地址
+        @request_dict mac: mac地址
+        @request_dict deviceModel: 设备型号
+        @request_dict manufacturer: 制造商
+        @request_dict sensorSerial: 传感器序列号
+        @request_dict firmwareVersion: 固件版本
+        @request_dict hardwareVersion: 硬件版本
+        @request_dict familyId: 家庭id
+        @request_dict roomId: 房间id
+        @param user_id: 用户id
+        @param response: 响应对象
+        @return: response 响应对象
+        """
+        serial_number = request_dict.get('serialNumber', None)
+        device_type = int(request_dict.get('deviceType', None))
+        nickname = request_dict.get('nickName', None)
+        ieee_addr = request_dict.get('ieeeAddr', None)
+        src_addr = request_dict.get('srcAddr', None)
+        mac = request_dict.get('mac', '')
+        device_model = request_dict.get('deviceModel', '')
+        manufacturer = request_dict.get('manufacturer', '')
+        sensor_serial = request_dict.get('sensorSerial', '')
+        firmware_version = request_dict.get('firmwareVersion', '')
+        hardware_version = request_dict.get('hardwareVersion', '')
+
+        family_id = request_dict.get('familyId', None)
+        room_id = request_dict.get('roomId', 0)
+
+        if not all([serial_number, device_type, nickname, src_addr, family_id]):
+            return response.json(444)
+        now_time = int(time.time())
+        try:
+            # 查询网关设备数据
+            device_info_qs = Device_Info.objects.filter(userID_id=user_id, serial_number=serial_number).values('id')
+            if not device_info_qs.exists():
+                return response.json(14)
+            device_id = device_info_qs[0]['id']
+            # 查询是否已添加过该子设备
+            sub_device_qs = GatewaySubDevice.objects.filter(device_id=device_id, ieee_addr=ieee_addr)
+            if sub_device_qs.exists():
+                return response.json(174)
+
+            with transaction.atomic():
+                sub_device = GatewaySubDevice.objects.create(device_id=device_id, device_type=device_type,
+                                                             nickname=nickname, ieee_addr=ieee_addr, src_addr=src_addr,
+                                                             status=1, mac=mac, device_model=device_model,
+                                                             manufacturer=manufacturer, sensor_serial=sensor_serial,
+                                                             firmware_version=firmware_version,
+                                                             hardware_version=hardware_version,
+                                                             created_time=now_time, updated_time=now_time)
+                FamilyRoomDevice.objects.create(family_id=family_id, room_id=room_id, device_id=device_id,
+                                                sub_device=sub_device.id, created_time=now_time, updated_time=now_time)
+            return response.json(0)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def query_sub_device(request_dict, response):
+        """
+        查询子设备信息
+        @param request_dict: 请求参数
+        @request_dict gatewaySubId: 子设备id
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('gatewaySubId', None)
+
+        if not all([sub_device_id]):
+            return response.json(444)
+        try:
+            gateway_sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('manufacturer',
+                                                                                             'device_model',
+                                                                                             'mac', 'sensor_serial')
+            if not gateway_sub_device_qs.exists():
+                return response.json(173)
+            res = {
+                'manufacturer': gateway_sub_device_qs[0]['manufacturer'],
+                'device_model': gateway_sub_device_qs[0]['device_model'],
+                'mac': gateway_sub_device_qs[0]['mac'],
+                'sensor_serial': gateway_sub_device_qs[0]['sensor_serial'],
+            }
+            return response.json(0, res)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @classmethod
+    def sensor_update(cls, request_dict, response):
+        """
+        传感器修改
+        @param request_dict: 请求参数
+        @request_dict gateway_sub_id: 子设备id
+        @request_dict nickName: 设备名
+        @request_dict room_id: 房间id
+        @param response: 响应结果
+        @return: list
+        """
+        gateway_sub_id = int(request_dict.get('gatewaySubId', None))
+        nickName = request_dict.get('nickName', None)
+        room_id = request_dict.get('roomId', None)
+        if not all([gateway_sub_id]):
+            return response.json(444)
+        try:
+            gateway_sub_qs = GatewaySubDevice.objects.filter(id=gateway_sub_id)
+            if not gateway_sub_qs.exists():
+                return response.json(173)
+            if nickName:
+                gateway_sub_qs.update(nickname=nickName)
+            if room_id:
+                FamilyRoomDevice.objects.filter(sub_device=gateway_sub_id).update(room_id=room_id)
+            return response.json(0)
+        except Exception as e:
+            print(e.args)
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def delete(request_dict, user_id, response):
+        """
+        更新子设备信息
+        @param request_dict: 请求参数
+        @request_dict sub_device_id: 子设备id
+        @param user_id: 用户id
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('subDeviceId', None)
+
+        if not all([sub_device_id]):
+            return response.json(444)
+        try:
+            GatewaySubDevice.objects.filter(id=sub_device_id).delete()
+            return response.json(0)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def records_tem_hum(request_dict, response):
+        """
+        查询温湿度传感器记录
+        @param request_dict: 请求参数
+        @request_dict gatewaySubId: 子设备id
+        @request_dict cycle: 时间周期
+        @request_dict eventType: 事件类型, 18:温度,19:湿度
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('gatewaySubId', None)
+        cycle = request_dict.get('cycle', None)
+        event_type = request_dict.get('eventType', None)
+        if not all([sub_device_id, cycle, event_type]):
+            return response.json(444, {'error param': 'gatewaySubId or cycle or eventType'})
+        now_time = int(time.time())
+        try:
+            record_dict = OrderedDict()
+            record_list = []
+            if cycle == 'Hours':
+                start_time = now_time - 24 * 60 * 60
+                sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                               event_type=event_type,
+                                                               created_time__range=(start_time, now_time)). \
+                    values('alarm', 'created_time').order_by('created_time')
+                if not sensor_record_qs.exists():
+                    return response.json(0, {'records': [], 'time': now_time})
+
+                for sensor_record in sensor_record_qs:
+                    created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
+                    hour = int(created_time[-7:-5])
+                    minute = int(created_time[-4:-2])
+                    if hour != 23 and minute > 30:  # 不为23时且分钟大于30,hour+1
+                        hour += 1
+                    alarm = float(sensor_record['alarm'])
+                    # 组织数据,record_dict:{"0": [1.0, 2.0, 3.0], "1": [1.0, 2.0, 3.0]...}
+                    if str(hour) in record_dict:
+                        record_dict[str(hour)].append(alarm)
+                    else:
+                        record_dict[str(hour)] = [alarm]
+
+            elif cycle == 'Week':
+                start_time = now_time - 24 * 60 * 60 * 7
+                sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                               event_type=event_type,
+                                                               created_time__range=(start_time, now_time)). \
+                    values('alarm', 'created_time').order_by('created_time')
+                if not sensor_record_qs.exists():
+                    return response.json(0, {'records': [], 'time': now_time})
+
+                for sensor_record in sensor_record_qs:
+                    created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
+                    week = int(created_time[-1:])
+                    alarm = float(sensor_record['alarm'])
+                    # 组织数据,record_dict:{"0": [1.0, 2.0, 3.0], "1": [1.0, 2.0, 3.0]...}
+                    if str(week) in record_dict:
+                        record_dict[str(week)].append(alarm)
+                    else:
+                        record_dict[str(week)] = [alarm]
+
+            elif cycle == 'Month':
+                start_time = now_time - 24 * 60 * 60 * 30
+                sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                               event_type=event_type,
+                                                               created_time__range=(start_time, now_time)). \
+                    values('alarm', 'created_time').order_by('created_time')
+                if not sensor_record_qs.exists():
+                    return response.json(0, {'records': [], 'time': now_time})
+
+                for sensor_record in sensor_record_qs:
+                    created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
+                    month = int(created_time[:2])
+                    day = int(created_time[3:5])
+                    date = str(month) + '/' + str(day)
+                    alarm = float(sensor_record['alarm'])
+                    # 组织数据,record_dict:{"0": [1.0, 2.0, 3.0], "1": [1.0, 2.0, 3.0]...}
+                    if date in record_dict:
+                        record_dict[date].append(alarm)
+                    else:
+                        record_dict[date] = [alarm]
+
+            # 组织响应数据列表,value为每 小时/天 的平均值
+            for k, v in record_dict.items():
+                record_list.append({'key': k, 'value': round(sum(v) / len(v), 1)})
+
+            res = {
+                'records': record_list,
+                'time': now_time
+            }
+            return response.json(0, res)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def records(request_dict, response):
+        """
+        查询其他传感器记录
+        @param request_dict: 请求参数
+        @request_dict gatewaySubId: 子设备id
+        @request_dict page: 页数
+        @request_dict size: 条数
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('gatewaySubId', None)
+        page = request_dict.get('page', None)
+        size = request_dict.get('size', None)
+        if not all([sub_device_id, page, size]):
+            return response.json(444, {'error param': 'gatewaySubId or page or size'})
+
+        start_time = request_dict.get('startTime', None)
+        end_time = request_dict.get('endTime', None)
+
+        try:
+            page, size = int(page), int(size)
+            if start_time and end_time:
+                sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                               created_time__range=(start_time, end_time)). \
+                                       values('alarm', 'created_time').order_by('-created_time')[
+                                   (page - 1) * size:page * size]
+            else:
+                sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id). \
+                                       values('alarm', 'created_time').order_by('-created_time')[
+                                   (page - 1) * size:page * size]
+            if not sensor_record_qs.exists():
+                return response.json(0, [])
+            return response.json(0, list(sensor_record_qs))
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def records_date(request_dict, response):
+        """
+        查询传感器记录日期
+        @param request_dict: 请求参数
+        @request_dict gatewaySubId: 子设备id
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('gatewaySubId', None)
+        if not sub_device_id:
+            return response.json(444, {'error param': 'gatewaySubId'})
+
+        try:
+            sensor_record_qs = SensorRecord.objects.extra(
+                select={'date': "FROM_UNIXTIME(created_time,'%%Y-%%m-%%d')"}).values('date'). \
+                                   filter(gateway_sub_device_id=sub_device_id). \
+                                   annotate(count=Count('created_time')). \
+                                   order_by('-date')[:31]
+            record_date_list = []
+            for sensor_record in sensor_record_qs:
+                record_date_list.append({
+                    'timestamp': CommonService.str_to_timestamp(sensor_record['date'], '%Y-%m-%d'),
+                    'count': sensor_record['count'],
+                    'format': sensor_record['date'],
+                })
+            return response.json(0, record_date_list)
+        except Exception as e:
+            return response.json(500, repr(e))

+ 41 - 43
Controller/SerialNumberController.py

@@ -2,27 +2,24 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 import json
 import json
 import logging
 import logging
-import random
-import requests
 import time
 import time
 
 
+import requests
 from django.db import transaction
 from django.db import transaction
 from django.views import View
 from django.views import View
 
 
-from Controller.DetectController import DetectControllerView
-from Controller.DeviceConfirmRegion import Device_Region
-from Model.models import SerialNumberModel, CompanySerialModel, UIDCompanySerialModel, CompanyModel, RegionModel, \
-    CountryModel, UIDModel, Device_Info, iotdeviceInfoModel, UidPushModel, LogModel, MacModel, UidSetModel, UID_Bucket, \
-    Unused_Uid_Meal, Order_Model, StsCrdModel, VodHlsModel, ExperienceContextModel, Equipment_Info, UidUserModel
+from Ansjer.config import CRCKey, SERVER_DOMAIN_US, SERVER_DOMAIN_CN, CONFIG_INFO, CONFIG_TEST, CONFIG_US, \
+    CONFIG_CN
+from Model.models import SerialNumberModel, CompanySerialModel, UIDCompanySerialModel, UIDModel, Device_Info, \
+    iotdeviceInfoModel, LogModel, UidSetModel, UID_Bucket, \
+    Unused_Uid_Meal, Order_Model, StsCrdModel, VodHlsModel, ExperienceContextModel, UidUserModel, ExperienceAiModel, \
+    AiService
 from Object.RedisObject import RedisObject
 from Object.RedisObject import RedisObject
-from Object.uidManageResponseObject import uidManageResponseObject
 from Object.TokenObject import TokenObject
 from Object.TokenObject import TokenObject
+from Object.uidManageResponseObject import uidManageResponseObject
 from Service.AlgorithmService import AlgorithmBaseOn35
 from Service.AlgorithmService import AlgorithmBaseOn35
 from Service.CommonService import CommonService
 from Service.CommonService import CommonService
-from Ansjer.config import CRCKey, SERVER_TYPE, SERVER_DOMAIN_US, SERVER_DOMAIN_CN
 from Service.EquipmentInfoService import EquipmentInfoService
 from Service.EquipmentInfoService import EquipmentInfoService
-from Service.ModelService import ModelService
-from Object.AWS.S3Email import S3Email
 
 
 
 
 class SerialNumberView(View):
 class SerialNumberView(View):
@@ -45,9 +42,9 @@ class SerialNumberView(View):
 
 
         if operation == 'getUID':
         if operation == 'getUID':
             return self.do_get_uid(request_dict, response)
             return self.do_get_uid(request_dict, response)
-        elif operation == 'attachUID':      # 绑定uid
+        elif operation == 'attachUID':  # 绑定uid
             return self.do_attach_uid(request_dict, response, request)
             return self.do_attach_uid(request_dict, response, request)
-        elif operation == 'detachUID':      # 解绑uid
+        elif operation == 'detachUID':  # 解绑uid
             return self.do_detach_uid(request, request_dict, response)
             return self.do_detach_uid(request, request_dict, response)
         elif operation == 'create':
         elif operation == 'create':
             return self.do_create(request_dict, response)
             return self.do_create(request_dict, response)
@@ -133,11 +130,9 @@ class SerialNumberView(View):
 
 
     def do_attach_uid(self, request_dict, response, request):
     def do_attach_uid(self, request_dict, response, request):
         serial_number = request_dict.get('serial_number', None)
         serial_number = request_dict.get('serial_number', None)
-        country_id = request_dict.get('country_id', None)
         company_id = request_dict.get('company_id', None)
         company_id = request_dict.get('company_id', None)
         token = request_dict.get('token', None)
         token = request_dict.get('token', None)
         time_stamp = request_dict.get('time_stamp', None)
         time_stamp = request_dict.get('time_stamp', None)
-        p2p_type = request_dict.get('p2ptype', 1)
 
 
         if not all([serial_number, company_id, token, time_stamp]):
         if not all([serial_number, company_id, token, time_stamp]):
             return response.json(444)
             return response.json(444)
@@ -150,31 +145,16 @@ class SerialNumberView(View):
         serial = serial_number[0:6]
         serial = serial_number[0:6]
         full_serial = serial_number[0:9]
         full_serial = serial_number[0:9]
 
 
-        if serial_number[9:10]:
-            p2p_type = serial_number[9:10]
-
         try:
         try:
-            if not country_id:
-                # 设备模拟国外环境测试
-                # if SERVER_TYPE == 'Ansjer.us_config.formal_settings':   # 国外正式配置使用固定ip进行测试
-                #     ip = '67.220.90.13'
-                # else:
-                #     ip = CommonService.get_ip_address(request)
-
-                ip = CommonService.get_ip_address(request)
-                country_id = Device_Region().get_device_region(ip)
-
             # 判断序列号是否已和企业关联
             # 判断序列号是否已和企业关联
             company_serial_qs = CompanySerialModel.objects.filter(company__secret=company_id, serial_number=serial)
             company_serial_qs = CompanySerialModel.objects.filter(company__secret=company_id, serial_number=serial)
             if not company_serial_qs.exists():
             if not company_serial_qs.exists():
                 return response.json(173)
                 return response.json(173)
-
-            # 当序列号已关联UID
             company_serial = company_serial_qs[0]
             company_serial = company_serial_qs[0]
 
 
             if company_serial.status == 0:  # 该序列号未绑定企业
             if company_serial.status == 0:  # 该序列号未绑定企业
                 return response.json(173)
                 return response.json(173)
-            elif company_serial.status == 1:    # 绑定uid
+            elif company_serial.status == 1:  # 绑定uid
                 # redis加锁,防止同一个序列号重复绑定
                 # redis加锁,防止同一个序列号重复绑定
                 key = serial + 'do_attach_uid'
                 key = serial + 'do_attach_uid'
                 redisObj = RedisObject()
                 redisObj = RedisObject()
@@ -182,13 +162,27 @@ class SerialNumberView(View):
                 redisObj.CONN.expire(key, 60)
                 redisObj.CONN.expire(key, 60)
                 if not isLock:
                 if not isLock:
                     return response.json(5)
                     return response.json(5)
+
+                region_id = request_dict.get('region_id', None)
+                if not region_id:
+                    # 根据配置信息确定region_id
+                    region_id = CommonService.confirm_region_id(request)
+
+                p2p_type = request_dict.get('p2ptype', 1)
+                if serial_number[9:10]:
+                    p2p_type = serial_number[9:10]
+                p2p_type = int(p2p_type)
+                # 尚云: 地区为亚洲分配美洲的uid
+                if p2p_type == 1 and region_id == 2:
+                    region_id = 3
+
                 with transaction.atomic():
                 with transaction.atomic():
                     count = 0
                     count = 0
                     while count < 3:
                     while count < 3:
                         # 查询是否存在未绑定序列号的uid
                         # 查询是否存在未绑定序列号的uid
                         uid_qs = UIDModel.objects.filter(vpg__company_id=company_serial.company.id,
                         uid_qs = UIDModel.objects.filter(vpg__company_id=company_serial.company.id,
-                                                         vpg__region_id=country_id, status=0, p2p_type=p2p_type). \
-                                                         order_by('id')
+                                                         vpg__region_id=region_id, status=0, p2p_type=p2p_type). \
+                            order_by('id')
                         if not uid_qs.exists():
                         if not uid_qs.exists():
                             return response.json(375)
                             return response.json(375)
 
 
@@ -199,7 +193,7 @@ class SerialNumberView(View):
                             return response.json(377)
                             return response.json(377)
 
 
                         result = UIDModel.objects.filter(id=uid.id, status=0).update(status=2, update_time=now_time)
                         result = UIDModel.objects.filter(id=uid.id, status=0).update(status=2, update_time=now_time)
-                        if int(result) <= 0:    # 更新失败
+                        if int(result) <= 0:  # 更新失败
                             count += 1
                             count += 1
                             continue
                             continue
 
 
@@ -216,7 +210,7 @@ class SerialNumberView(View):
 
 
                         full_uid_code = uid.full_uid_code
                         full_uid_code = uid.full_uid_code
                         if uid.platform in CRCKey.keys():
                         if uid.platform in CRCKey.keys():
-                            full_uid_code += ':'+CRCKey[uid.platform]
+                            full_uid_code += ':' + CRCKey[uid.platform]
 
 
                         res = {
                         res = {
                             'full_uid_code': CommonService.encode_data(full_uid_code),
                             'full_uid_code': CommonService.encode_data(full_uid_code),
@@ -249,7 +243,7 @@ class SerialNumberView(View):
                         redisObj.del_data(key=key)
                         redisObj.del_data(key=key)
                         return response.json(0, res)
                         return response.json(0, res)
                     return response.json(5)
                     return response.json(5)
-            elif company_serial.status == 2:   # 返回uid
+            elif company_serial.status == 2:  # 返回uid
                 uid_qs = UIDCompanySerialModel.objects.filter(company_serial_id=company_serial.id)
                 uid_qs = UIDCompanySerialModel.objects.filter(company_serial_id=company_serial.id)
                 if not uid_qs.exists():
                 if not uid_qs.exists():
                     return response.json(173)
                     return response.json(173)
@@ -257,7 +251,7 @@ class SerialNumberView(View):
                                     'uid__platform', 'uid__init_string', 'uid__init_string_app')[0]
                                     'uid__platform', 'uid__init_string', 'uid__init_string_app')[0]
                 full_uid_code = uid['uid__full_uid_code']
                 full_uid_code = uid['uid__full_uid_code']
                 if uid['uid__platform'] in CRCKey.keys():
                 if uid['uid__platform'] in CRCKey.keys():
-                    full_uid_code += ':'+CRCKey[uid['uid__platform']]
+                    full_uid_code += ':' + CRCKey[uid['uid__platform']]
                 res = {
                 res = {
                     'full_uid_code': CommonService.encode_data(full_uid_code),
                     'full_uid_code': CommonService.encode_data(full_uid_code),
                     'uid': CommonService.encode_data(uid['uid__uid']),
                     'uid': CommonService.encode_data(uid['uid__uid']),
@@ -333,7 +327,7 @@ class SerialNumberView(View):
         try:
         try:
             with transaction.atomic():
             with transaction.atomic():
                 uid = uid_serial.uid.uid
                 uid = uid_serial.uid.uid
-                company_serial_qs.update(status=1)      # 更新序列号状态
+                company_serial_qs.update(status=1)  # 更新序列号状态
                 # 删除设备相关数据,参考后台的设备重置删除的数据
                 # 删除设备相关数据,参考后台的设备重置删除的数据
                 Device_Info.objects.filter(UID=uid).delete()
                 Device_Info.objects.filter(UID=uid).delete()
                 UidSetModel.objects.filter(uid=uid).delete()
                 UidSetModel.objects.filter(uid=uid).delete()
@@ -351,6 +345,10 @@ class SerialNumberView(View):
                 VodHlsModel.objects.filter(uid=uid).delete()
                 VodHlsModel.objects.filter(uid=uid).delete()
                 ExperienceContextModel.objects.filter(uid=uid).delete()
                 ExperienceContextModel.objects.filter(uid=uid).delete()
 
 
+                # 重置AI
+                ExperienceAiModel.objects.filter(uid=uid).delete()
+                AiService.objects.filter(uid=uid).delete()
+
                 # 修改其他数据库的序列号使用状态为已使用
                 # 修改其他数据库的序列号使用状态为已使用
                 update_success = self.update_serial_status(serial=serial, status=1)
                 update_success = self.update_serial_status(serial=serial, status=1)
                 try:
                 try:
@@ -358,7 +356,7 @@ class SerialNumberView(View):
                 except AssertionError:
                 except AssertionError:
                     return response.json(378)
                     return response.json(378)
 
 
-                UIDModel.objects.filter(uid=uid).update(status=0, mac='')    # 重置uid的使用状态为未使用
+                UIDModel.objects.filter(uid=uid).update(status=0, mac='')  # 重置uid的使用状态为未使用
                 uid_serial.delete()
                 uid_serial.delete()
 
 
                 # 记录操作日志
                 # 记录操作日志
@@ -382,11 +380,12 @@ class SerialNumberView(View):
 
 
     @staticmethod
     @staticmethod
     def update_serial_status(serial, status):
     def update_serial_status(serial, status):
-        if SERVER_TYPE == 'Ansjer.cn_config.test_settings':   # 测试服不处理
+        if CONFIG_INFO == CONFIG_TEST:  # 测试服不处理
             return True
             return True
-        if SERVER_TYPE == 'Ansjer.us_config.formal_settings':
+        server_domain = SERVER_DOMAIN_CN
+        if CONFIG_INFO == CONFIG_US:
             server_domain = SERVER_DOMAIN_CN
             server_domain = SERVER_DOMAIN_CN
-        elif SERVER_TYPE == 'Ansjer.cn_config.formal_settings':
+        elif CONFIG_INFO == CONFIG_CN:
             server_domain = SERVER_DOMAIN_US
             server_domain = SERVER_DOMAIN_US
         url = server_domain + 'serialNumber/changeSerialNumberStatus'
         url = server_domain + 'serialNumber/changeSerialNumberStatus'
         data = {'serial': serial, 'status': status}
         data = {'serial': serial, 'status': status}
@@ -434,4 +433,3 @@ class SerialNumberView(View):
             djangoLogger = logging.getLogger('django')
             djangoLogger = logging.getLogger('django')
             djangoLogger.exception(repr(e))
             djangoLogger.exception(repr(e))
             return response.json(500, str(e))
             return response.json(500, str(e))
-

+ 74 - 35
Controller/TestApi.py

@@ -56,10 +56,7 @@ from Service.CommonService import CommonService
 from Service.ModelService import ModelService
 from Service.ModelService import ModelService
 from Object.m3u8generate import PlaylistGenerator
 from Object.m3u8generate import PlaylistGenerator
 from Model.models import Device_User, Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidPushModel
 from Model.models import Device_User, Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidPushModel
-from Ansjer.config import PAYPAL_CRD,SERVER_DOMAIN,SERVER_DOMAIN_SSL,PAYPAL_WEB_HOOK_ID
-
-
-
+from Ansjer.config import PAYPAL_CRD, SERVER_DOMAIN, SERVER_DOMAIN_SSL, PAYPAL_WEB_HOOK_ID
 
 
 SERVER_DOMAIN = 'http://test.dvema.com/'
 SERVER_DOMAIN = 'http://test.dvema.com/'
 ACCESS_KEY = "AKIA2E67UIMD3CYTIWPA"
 ACCESS_KEY = "AKIA2E67UIMD3CYTIWPA"
@@ -86,7 +83,7 @@ class testView(View):
         request.encoding = 'utf-8'
         request.encoding = 'utf-8'
         operation = kwargs.get('operation')
         operation = kwargs.get('operation')
         response = ResponseObject()
         response = ResponseObject()
-        return response.json(0,request.body)
+        return response.json(0, request.body)
 
 
     def validation(self, request_dict, request, operation):
     def validation(self, request_dict, request, operation):
         response = ResponseObject()
         response = ResponseObject()
@@ -97,7 +94,7 @@ class testView(View):
             logger = logging.getLogger('info')
             logger = logging.getLogger('info')
             logger.info('测试打印')
             logger.info('测试打印')
             res = make_password(123456)
             res = make_password(123456)
-            return JsonResponse(status=200, data=res,safe=False)
+            return JsonResponse(status=200, data=res, safe=False)
         elif operation == 'testMiddleWare':
         elif operation == 'testMiddleWare':
             a = int('a')
             a = int('a')
             return JsonResponse(status=200, safe=False)
             return JsonResponse(status=200, safe=False)
@@ -126,13 +123,13 @@ class testView(View):
             return self.queryInterface(request_dict, userID, response)
             return self.queryInterface(request_dict, userID, response)
         elif operation == 'generateToken':
         elif operation == 'generateToken':
             userID = '158943604783713800138000'
             userID = '158943604783713800138000'
-            return self.generate_token(request_dict,userID)
+            return self.generate_token(request_dict, userID)
         elif operation == 'test_upload_s3':
         elif operation == 'test_upload_s3':
             userID = '158943604783713800138000'
             userID = '158943604783713800138000'
             return self.test_upload_s3(request_dict, response)
             return self.test_upload_s3(request_dict, response)
         elif operation == 'rekognition':
         elif operation == 'rekognition':
             userID = '158943604783713800138000'
             userID = '158943604783713800138000'
-            return self.testRekognition(request,request_dict)
+            return self.testRekognition(request, request_dict)
         elif operation == 'ip':
         elif operation == 'ip':
             return self.ip(response)
             return self.ip(response)
         elif operation == 'configType':
         elif operation == 'configType':
@@ -141,10 +138,32 @@ class testView(View):
             return self.createData(request_dict, response)
             return self.createData(request_dict, response)
         elif operation == 'findPaypalOrder':
         elif operation == 'findPaypalOrder':
             return self.findPaypalOrder(request_dict, response)
             return self.findPaypalOrder(request_dict, response)
+        elif operation == 'comb':
+            return self.do_comb(request_dict, response)
+        elif operation == 'count_ts':
+            return self.count_ts(request_dict, response)
         else:
         else:
             return 123
             return 123
 
 
-    def findPaypalOrder(self,request_dict, response):
+    def do_comb(self, request_dict, response):
+        import itertools
+        list1 = [1, 2, 3, 4]
+        list2 = []
+        for i in range(1, len(list1) + 1):
+            iter = itertools.combinations(list1, i)
+            list2.append(list(iter))
+        list3 = []
+        for list_ in list2:
+            for val in list_:
+                print('-------------list')
+                print(type(val))
+                comb = [str(i) for i in val]
+                comb_int = int("".join(comb))
+                list3.append(comb_int)
+
+        return HttpResponse(json.dumps(list3))
+
+    def findPaypalOrder(self, request_dict, response):
         from paypalrestsdk import Order, ResourceNotFound
         from paypalrestsdk import Order, ResourceNotFound
         PAYPAL_CRD = {
         PAYPAL_CRD = {
             "mode": "sandbox",  # sandbox or live
             "mode": "sandbox",  # sandbox or live
@@ -178,11 +197,9 @@ class testView(View):
         # print(related_resources)
         # print(related_resources)
         # return HttpResponse(sale)
         # return HttpResponse(sale)
 
 
-
-
     def createBucket(self):
     def createBucket(self):
 
 
-        #查看桶列表
+        # 查看桶列表
         # url = "https://azvod1.s3-ap-northeast-1.amazonaws.com"
         # url = "https://azvod1.s3-ap-northeast-1.amazonaws.com"
         # session = Session(ACCESS_KEY, SECRET_KEY)
         # session = Session(ACCESS_KEY, SECRET_KEY)
         # s3_client = session.client('s3', endpoint_url=url)
         # s3_client = session.client('s3', endpoint_url=url)
@@ -193,10 +210,10 @@ class testView(View):
         session = Session(ACCESS_KEY, SECRET_KEY)
         session = Session(ACCESS_KEY, SECRET_KEY)
         s3_client = session.client('s3')
         s3_client = session.client('s3')
 
 
-        #上传
+        # 上传
         # s3_client.put_object(Bucket="azvod1", Key="file/rule.txt", Body=open(r"E:\download\Shadowsocks-4.1.10.0\user-rule.txt", 'rb').read())
         # s3_client.put_object(Bucket="azvod1", Key="file/rule.txt", Body=open(r"E:\download\Shadowsocks-4.1.10.0\user-rule.txt", 'rb').read())
 
 
-        #下载
+        # 下载
         resp = s3_client.get_object(Bucket="azvod1", Key="file/rule.txt")
         resp = s3_client.get_object(Bucket="azvod1", Key="file/rule.txt")
         with open('local.txt', 'wb') as f:
         with open('local.txt', 'wb') as f:
             f.write(resp['Body'].read())
             f.write(resp['Body'].read())
@@ -219,7 +236,7 @@ class testView(View):
         if uid:
         if uid:
             dvqs = dvqs.filter(UID=uid)
             dvqs = dvqs.filter(UID=uid)
         # count = dvqs.count()
         # count = dvqs.count()
-        #分页
+        # 分页
         dvql = dvqs[(page - 1) * line:page * line].values('id', 'userID', 'NickName', 'UID', 'View_Account',
         dvql = dvqs[(page - 1) * line:page * line].values('id', 'userID', 'NickName', 'UID', 'View_Account',
                                                           'View_Password', 'ChannelIndex', 'Type', 'isShare',
                                                           'View_Password', 'ChannelIndex', 'Type', 'isShare',
                                                           'primaryUserID', 'primaryMaster', 'data_joined',
                                                           'primaryUserID', 'primaryMaster', 'data_joined',
@@ -273,8 +290,7 @@ class testView(View):
             data.append(p)
             data.append(p)
         return response.json(0, data)
         return response.json(0, data)
 
 
-
-    #获取播放列表
+    # 获取播放列表
     def do_test_query_vod_list(self, userID, ip, request_dict, response):
     def do_test_query_vod_list(self, userID, ip, request_dict, response):
         uid = 'GZL2PEFJPLY7W6BG111A'
         uid = 'GZL2PEFJPLY7W6BG111A'
         channel = 2
         channel = 2
@@ -315,7 +331,7 @@ class testView(View):
             'sec': 12})
             'sec': 12})
         return response.json(0, vod_play_list)
         return response.json(0, vod_play_list)
 
 
-    #生成m3u8列表
+    # 生成m3u8列表
     def do_sign_play_m3u8(self, request_dict, response):
     def do_sign_play_m3u8(self, request_dict, response):
         uid = 'GZL2PEFJPLY7W6BG111A'
         uid = 'GZL2PEFJPLY7W6BG111A'
         channel = 2
         channel = 2
@@ -653,9 +669,6 @@ class testView(View):
                 return HttpResponse(json.dumps(res, ensure_ascii=False),
                 return HttpResponse(json.dumps(res, ensure_ascii=False),
                                     content_type="application/json,charset=utf-8")
                                     content_type="application/json,charset=utf-8")
 
 
-
-
-
     def do_pay_by_ali(self, request_dict, userID, response):
     def do_pay_by_ali(self, request_dict, userID, response):
         uid = request_dict.get('uid', None)
         uid = request_dict.get('uid', None)
         rank = request_dict.get('rank', None)
         rank = request_dict.get('rank', None)
@@ -755,24 +768,23 @@ class testView(View):
             vod_play_list.append({'name': vod['time'], 'sign_url': vod_play_url, 'thumb': thumb, 'sec': vod['sec']})
             vod_play_list.append({'name': vod['time'], 'sign_url': vod_play_url, 'thumb': thumb, 'sec': vod['sec']})
         return response.json(0, vod_play_list)
         return response.json(0, vod_play_list)
 
 
-    def generate_token(self,request_dict,userID):
+    def generate_token(self, request_dict, userID):
         # UserIdToken
         # UserIdToken
         tko = TokenObject()
         tko = TokenObject()
-        userID = request_dict.get('userID',None)
-        username = request_dict.get('username',None)
+        userID = request_dict.get('userID', None)
+        username = request_dict.get('username', None)
         res = tko.generate(
         res = tko.generate(
             data={'userID': userID, 'lang': 'cn', 'user': username, 'm_code': username})
             data={'userID': userID, 'lang': 'cn', 'user': username, 'm_code': username})
-        #uidToken
+        # uidToken
         # utko = UidTokenObject()
         # utko = UidTokenObject()
         # res = utko.generate(data={'uid': '4UZSEDP93MJ3X7YB111A','channel': 1})
         # res = utko.generate(data={'uid': '4UZSEDP93MJ3X7YB111A','channel': 1})
 
 
         # from Object.ETkObject import ETkObject
         # from Object.ETkObject import ETkObject
         # etkObj = ETkObject(etk='')
         # etkObj = ETkObject(etk='')
         # res = etkObj.encrypt("4UZSEDP93MJ3X7YB111A")
         # res = etkObj.encrypt("4UZSEDP93MJ3X7YB111A")
-        return JsonResponse(status=200, data=res,safe=False)
-
+        return JsonResponse(status=200, data=res, safe=False)
 
 
-    def test_upload_s3(self,request_dict , response):
+    def test_upload_s3(self, request_dict, response):
         aws_s3_guonei = boto3.client(
         aws_s3_guonei = boto3.client(
             's3',
             's3',
             aws_access_key_id=AWS_ACCESS_KEY_ID[0],
             aws_access_key_id=AWS_ACCESS_KEY_ID[0],
@@ -791,8 +803,7 @@ class testView(View):
         )
         )
         return response.json(0, {'datas': response_url, 'count': 1})
         return response.json(0, {'datas': response_url, 'count': 1})
 
 
-
-    def testRekognition(self,request,request_dict):
+    def testRekognition(self, request, request_dict):
         # ip = CommonService.get_ip_address(request)
         # ip = CommonService.get_ip_address(request)
         # ipInfo = CommonService.getIpIpInfo(ip,"CN")
         # ipInfo = CommonService.getIpIpInfo(ip,"CN")
         # # print(type(ipInfo))
         # # print(type(ipInfo))
@@ -807,15 +818,15 @@ class testView(View):
         # client = boto3.client('s3', aws_access_key_id='AKIA2E67UIMD45Y3HL53',aws_secret_access_key='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',region_name='us-east-1')
         # client = boto3.client('s3', aws_access_key_id='AKIA2E67UIMD45Y3HL53',aws_secret_access_key='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',region_name='us-east-1')
         # exit(request.FILES)
         # exit(request.FILES)
 
 
-
         files = request.FILES.get('image')
         files = request.FILES.get('image')
-        labels = int(request_dict.get('labels',5))
-        minConfidence = int(request_dict.get('minConfidence',99))
+        labels = int(request_dict.get('labels', 5))
+        minConfidence = int(request_dict.get('minConfidence', 99))
         if not files:
         if not files:
             return HttpResponse('请上传图片!!!!')
             return HttpResponse('请上传图片!!!!')
-        client = boto3.client('rekognition', aws_access_key_id='AKIA2E67UIMD6JD6TN3J',aws_secret_access_key='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',region_name='us-east-1')
+        client = boto3.client('rekognition', aws_access_key_id='AKIA2E67UIMD6JD6TN3J',
+                              aws_secret_access_key='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', region_name='us-east-1')
         # image = open('E:/photo/a615fa40b8c476bab0f6eeb332e62a5a-1000.jpg', "rb")
         # image = open('E:/photo/a615fa40b8c476bab0f6eeb332e62a5a-1000.jpg', "rb")
-        response = client.detect_labels(Image={'Bytes':files.read()},MaxLabels=labels,MinConfidence=minConfidence)
+        response = client.detect_labels(Image={'Bytes': files.read()}, MaxLabels=labels, MinConfidence=minConfidence)
         # for obj in response['Labels']:
         # for obj in response['Labels']:
         #     exit(obj)
         #     exit(obj)
         #     if obj['Name'] == 'Person':
         #     if obj['Name'] == 'Person':
@@ -839,3 +850,31 @@ class testView(View):
         # qs = DeviceLogModel.objects.filter(add_time__lt=filter_date)
         # qs = DeviceLogModel.objects.filter(add_time__lt=filter_date)
         DeviceLogModel.objects.create(uid=uid)
         DeviceLogModel.objects.create(uid=uid)
         return response.json(0)
         return response.json(0)
+
+    def count_ts(self, request_dict, response):
+        year = request_dict.get('year', None)
+        month = request_dict.get('month', None)
+        if not year:
+            year = CommonService.timestamp_to_str(int(time.time()), '%Y')
+        if not month:
+            month = CommonService.timestamp_to_str(int(time.time()), '%m')
+        year = int(year)
+        month = int(month)
+        startTime = CommonService.str_to_timestamp('{year}-{month}'.format(year=year, month=month), '%Y-%m')
+        endTime = CommonService.str_to_timestamp('{year}-{month}'.format(year=year, month=month + 1), '%Y-%m') - 1
+        qsTs = VodHlsModel.objects.filter(time__gte=startTime, time__lte=endTime).values('fg')
+        if not qsTs.exists():
+            return HttpResponse('查无数据')
+        sumTs = 0  # 总ts个数
+        sumSec = 0  # 总秒数
+        for val in qsTs:
+            fg = int(val['fg'])
+            sumTs += fg & 0xf
+            for i in range(15):
+                shift = (i + 1) * 4
+                sumSec += (fg >> shift) & 0xf
+        size = 0
+        return HttpResponse(
+            "{year}年{month}月 </br>上传的TS总数:{sumTs} </br> 总秒数:{sumSec} </br> 总大小:{size}GB (1秒约等150KB计算)".format(year=year, month=month,
+                                                                                           sumTs=sumTs, sumSec=sumSec,
+                                                                                           size=size))

+ 264 - 0
Controller/UnicomCombo/UnicomComboController.py

@@ -0,0 +1,264 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : UnicomComboController.py
+@Time    : 2022/6/23 9:18
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import json
+import logging
+import time
+
+from django.db import transaction
+from django.http import HttpResponse
+from django.views.generic.base import View
+
+from Model.models import UnicomDeviceInfo, UnicomCombo, Pay_Type
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
+from Object.UnicomObject import UnicomObjeect
+
+
+class UnicomComboView(View):
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, request, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        if operation == 'buy-notify':
+            return self.package_callback_notify(request_dict, request)
+        elif operation == 'device-queue-monitoring':
+            return self.device_queue_monitoring_push(request_dict, request)
+        elif operation == 'device-status-change':
+            return self.device_status_change_push(request_dict, request)
+        elif operation == 'device-bind':
+            response = ResponseObject('cn')
+            return self.device_add(request_dict, response)
+        else:
+            token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+            lang = request_dict.get('lang', token.lang)
+            response = ResponseObject(lang)
+            if token.code != 0:
+                return response.json(token.code)
+            if operation == 'combo-save':
+                return self.save_unicom_combo(request_dict, response)
+            elif operation == 'combo-list':
+                return self.query_package_list(response)
+
+    @classmethod
+    def device_add(cls, request_dict, response):
+        """
+        设备绑定iccid
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        iccid = request_dict.get('iccid', None)
+        serial_no = request_dict.get('serialNo', None)
+        if not all([iccid, serial_no]):
+            return response.json(444)
+        n_time = int(time.time())
+        try:
+            with transaction.atomic():
+                # 待完善代码 根据uid与用户id验证系统设备
+                unicom_device_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
+                if unicom_device_qs.exists():
+                    return response.json(174)
+                unicom_obj = UnicomObjeect()
+                result = unicom_obj.verify_device(iccid=iccid)
+                if result.status_code == 200 and result.text:
+                    res_dict = json.loads(result.text)
+                    if res_dict['success']:
+                        if res_dict['data']['status'] == 0:
+                            return response.json(173)
+                        params = {'iccid': iccid, 'serial_no': serial_no, 'updated_time': n_time,
+                                  'created_time': n_time}
+                        UnicomDeviceInfo.objects.create(**params)
+                    return response.json(0)
+                else:
+                    return response.json(173)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def save_unicom_combo(cls, request_dict, response):
+        """
+        联通套餐保存
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        combo_id = request_dict.get('id', None)
+        combo_name = request_dict.get('comboName', None)
+        flow_total = request_dict.get('flowTotal', None)
+        expiration_days = request_dict.get('expirationDays', None)
+        expiration_type = request_dict.get('expirationType', None)
+        price = request_dict.get('price', None)
+        remark = request_dict.get('remark', None)
+        pay_type = request_dict.get('payType', '').split(',')
+        if not all([pay_type, combo_name, flow_total, expiration_days, expiration_type, price]):
+            return response.json(444)
+        try:
+            flow_total = int(flow_total)
+            expiration_days = int(expiration_days)
+            expiration_type = int(expiration_type)
+            with transaction.atomic():
+                re_data = {
+                    'combo_name': combo_name,
+                    'flow_total': flow_total,
+                    'expiration_days': expiration_days,
+                    'expiration_type': expiration_type,
+                    'price': price,
+                }
+                if remark:
+                    re_data['remark'] = remark
+                if combo_id:
+                    UnicomCombo.objects.filter(id=combo_id).update(**re_data)
+                    UnicomCombo.objects.get(id=combo_id).pay_type.set(pay_type)
+                    return response.json(0)
+                UnicomCombo.objects.create(**re_data).pay_type.set(pay_type)
+                return response.json(0)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def query_package_list(cls, response):
+        """
+        查询套餐列表
+        @return:
+        """
+        try:
+            combo_qs = UnicomCombo.objects.filter(is_show=1, status=0, is_del=False) \
+                .order_by('sort').values('id', 'combo_name',
+                                         'flow_total',
+                                         'expiration_days',
+                                         'expiration_type', 'price',
+                                         'remark')
+            if not combo_qs.exists():
+                return response.json(0, [])
+            combo_list = []
+            for item in combo_qs:
+                # 获取支付方式列表
+                pay_type_qs = Pay_Type.objects.filter(unicomcombo=item['id']).values('id', 'payment')
+                combo_list.append({
+                    'id': item['id'],
+                    'comboName': item['combo_name'],
+                    'flowTotal': item['flow_total'],
+                    'expirationDays': item['expiration_days'],
+                    'expirationType': item['expiration_type'],
+                    'price': item['price'],
+                    'remark': item['remark'],
+                    'payTypes': list(pay_type_qs),
+                })
+            return response.json(0, combo_list)
+        except Exception as e:
+            print(e)
+            return response.json(177, repr(e))
+
+    @classmethod
+    def buy_package(cls):
+        """
+        购买套餐
+        @return:
+        """
+        pass
+
+    @classmethod
+    def query_device_usage_history(cls):
+        """
+        查询用量历史
+        @return:
+        """
+
+    @staticmethod
+    def package_callback_notify(request_dict, request):
+        """
+        异步套餐订购回调
+        @param request_dict:
+        @param request:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            logger.info('联通异步套餐订购回调参数{}'.format(request_dict))
+            body = request.body.decode("utf-8")
+            if body:
+                dict_data = json.loads(body)
+                sign = dict_data['sign']
+                logger.info('设备订购异步回调请求参数{}'.format(dict_data))
+                dict_data.pop('sign')
+                unicom_obj = UnicomObjeect()
+                generate_sign = unicom_obj.createSign(**dict_data)
+                logger.info('设备订购请求签名{}'.format(sign))
+                logger.info('设备订购生成签名{}'.format(generate_sign))
+            r_data = {'success': True, 'msg': '成功'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+        except Exception as e:
+            print(repr(e))
+            r_data = {'success': False, 'msg': '失败'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+
+    @staticmethod
+    def device_queue_monitoring_push(request_dict, request):
+        """
+        设备套餐队列用完或者到期推送
+        @param request_dict:
+        @param request:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            logger.info('设备套餐队列推送{}'.format(request_dict))
+            body = request.body.decode("utf-8")
+            if body:
+                dict_data = json.loads(body)
+                sign = dict_data['sign']
+                logger.info('设备套餐队列回调请求参数{}'.format(dict_data))
+                dict_data.pop('sign')
+                unicom_obj = UnicomObjeect()
+                generate_sign = unicom_obj.createSign(**dict_data)
+                logger.info('设备套餐队列请求签名{}'.format(sign))
+                logger.info('设备套餐队列生成签名{}'.format(generate_sign))
+            r_data = {'success': True, 'msg': '成功'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+        except Exception as e:
+            print(repr(e))
+            r_data = {'success': False, 'msg': '失败'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+
+    @staticmethod
+    def device_status_change_push(request_dict, request):
+        """
+        设备状态变更推送执行场景说明
+        @param request_dict:
+        @param request:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            logger.info('设备状态变更推送{}'.format(request_dict))
+            body = request.body.decode("utf-8")
+            if body:
+                dict_data = json.loads(body)
+                sign = dict_data['sign']
+                logger.info('设备状态变更推送请求参数{}'.format(dict_data))
+                dict_data.pop('sign')
+                unicom_obj = UnicomObjeect()
+                generate_sign = unicom_obj.createSign(**dict_data)
+                logger.info('设备状态变更推送请求签名{}'.format(sign))
+                logger.info('设备状态变更推送生成签名{}'.format(generate_sign))
+            r_data = {'success': True, 'msg': '成功'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+        except Exception as e:
+            print(repr(e))
+            r_data = {'success': False, 'msg': '失败'}
+            return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")

+ 1 - 1
Controller/UserBrandController.py

@@ -57,9 +57,9 @@ class MyserviceDynamodb(object):
         try:
         try:
             session = Session(aws_access_key_id=self.access_key, aws_secret_access_key=self.secret_key,
             session = Session(aws_access_key_id=self.access_key, aws_secret_access_key=self.secret_key,
                               region_name=self.region)
                               region_name=self.region)
+            return session
         except:
         except:
             print("Failed to connect session in region{0}".format(self.region))
             print("Failed to connect session in region{0}".format(self.region))
-        return session
 
 
     # 创建user_brand_all表
     # 创建user_brand_all表
     def user_brand_all_table_create(self, table_name):
     def user_brand_all_table_create(self, table_name):

+ 471 - 71
Model/models.py

@@ -1,13 +1,14 @@
 from itertools import chain
 from itertools import chain
+
 from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
 from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
 from django.db import models
 from django.db import models
-from django.utils import six, timezone
+from django.utils import six
+from django.utils import timezone
 from django.utils.encoding import python_2_unicode_compatible
 from django.utils.encoding import python_2_unicode_compatible
 from imagekit.models import ProcessedImageField
 from imagekit.models import ProcessedImageField
 from imagekit.processors import ResizeToFill
 from imagekit.processors import ResizeToFill
 
 
 from Ansjer.config import SERVER_DOMAIN
 from Ansjer.config import SERVER_DOMAIN
-from django.utils import timezone
 
 
 
 
 class PermissionsManager(models.Manager):
 class PermissionsManager(models.Manager):
@@ -78,17 +79,19 @@ class Permissions(models.Model):
     def natural_key(self):
     def natural_key(self):
         return (self.permName)
         return (self.permName)
 
 
+
 class MenuModel(models.Model):
 class MenuModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     parentId = models.IntegerField(default=0, verbose_name='父节点ID')
     parentId = models.IntegerField(default=0, verbose_name='父节点ID')
-    name = models.CharField(max_length=50,  null=True, default='', verbose_name='名称')   #首字母大写,一定要与vue文件的name对应起来,用于noKeepAlive缓存控制(该项特别重要)
-    path = models.CharField(max_length=100, null=True, default='',verbose_name='路径')
-    component = models.CharField(max_length=100, null=True, default='', verbose_name='vue文件路径') #所谓的vue 组件
+    name = models.CharField(max_length=50, null=True, default='',
+                            verbose_name='名称')  # 首字母大写,一定要与vue文件的name对应起来,用于noKeepAlive缓存控制(该项特别重要)
+    path = models.CharField(max_length=100, null=True, default='', verbose_name='路径')
+    component = models.CharField(max_length=100, null=True, default='', verbose_name='vue文件路径')  # 所谓的vue 组件
     hidden = models.BooleanField(blank=True, default=False, verbose_name=u'是否隐藏')
     hidden = models.BooleanField(blank=True, default=False, verbose_name=u'是否隐藏')
     alwaysShow = models.BooleanField(blank=True, default=False, verbose_name=u'始终显示当前节点')
     alwaysShow = models.BooleanField(blank=True, default=False, verbose_name=u'始终显示当前节点')
     levelHidden = models.BooleanField(blank=True, default=False, verbose_name=u'是否隐藏一级路由')
     levelHidden = models.BooleanField(blank=True, default=False, verbose_name=u'是否隐藏一级路由')
-    title = models.CharField(max_length=50, default='',verbose_name='标题')
-    icon = models.CharField(max_length=50, default='',verbose_name='图标名')
+    title = models.CharField(max_length=50, default='', verbose_name='标题')
+    icon = models.CharField(max_length=50, default='', verbose_name='图标名')
     isCustomSvg = models.BooleanField(blank=True, default=False, verbose_name=u'是否是自定义svg图标')
     isCustomSvg = models.BooleanField(blank=True, default=False, verbose_name=u'是否是自定义svg图标')
     noKeepAlive = models.BooleanField(blank=True, default=False, verbose_name=u'当前路由是否不缓存')
     noKeepAlive = models.BooleanField(blank=True, default=False, verbose_name=u'当前路由是否不缓存')
     noClosable = models.BooleanField(blank=True, default=False, verbose_name=u'当前路由是否可关闭多标签页')
     noClosable = models.BooleanField(blank=True, default=False, verbose_name=u'当前路由是否可关闭多标签页')
@@ -99,7 +102,7 @@ class MenuModel(models.Model):
     dynamicNewTab = models.BooleanField(blank=True, default=False, verbose_name=u'动态传参路由是否新开标签页')
     dynamicNewTab = models.BooleanField(blank=True, default=False, verbose_name=u'动态传参路由是否新开标签页')
     redirect = models.CharField(max_length=50, default='', verbose_name='重定向')
     redirect = models.CharField(max_length=50, default='', verbose_name='重定向')
     menu_code = models.CharField(max_length=100, default='', verbose_name='菜单编码')
     menu_code = models.CharField(max_length=100, default='', verbose_name='菜单编码')
-    menutype  = models.SmallIntegerField(default=1, verbose_name=u'类型') #类型: 1-菜单 2-按钮
+    menutype = models.SmallIntegerField(default=1, verbose_name=u'类型')  # 类型: 1-菜单 2-按钮
     sort = models.IntegerField(default=0, verbose_name='排序')
     sort = models.IntegerField(default=0, verbose_name='排序')
 
 
     class Meta:
     class Meta:
@@ -107,6 +110,7 @@ class MenuModel(models.Model):
         verbose_name = u'菜单表'
         verbose_name = u'菜单表'
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
 
 
+
 class Role(models.Model):
 class Role(models.Model):
     rid = models.SmallIntegerField(primary_key=True, unique=True, verbose_name=u'用户角色组ID')
     rid = models.SmallIntegerField(primary_key=True, unique=True, verbose_name=u'用户角色组ID')
     roleName = models.CharField(max_length=32, unique=True,
     roleName = models.CharField(max_length=32, unique=True,
@@ -148,6 +152,7 @@ class Role(models.Model):
             permslist.sort()
             permslist.sort()
             return permslist
             return permslist
 
 
+
 class Device_User(AbstractBaseUser):
 class Device_User(AbstractBaseUser):
     userID = models.CharField(blank=True, max_length=32, primary_key=True,
     userID = models.CharField(blank=True, max_length=32, primary_key=True,
                               verbose_name=u'用户ID', unique=True)
                               verbose_name=u'用户ID', unique=True)
@@ -175,10 +180,10 @@ class Device_User(AbstractBaseUser):
     language = models.CharField(blank=True, max_length=16, default='en', verbose_name=u'语言地区')
     language = models.CharField(blank=True, max_length=16, default='en', verbose_name=u'语言地区')
     # 手机注册增加字段
     # 手机注册增加字段
     phone = models.CharField(max_length=16, db_index=True, verbose_name=u'手机号', default='', blank=True)
     phone = models.CharField(max_length=16, db_index=True, verbose_name=u'手机号', default='', blank=True)
-    fingerprint_enable = models.SmallIntegerField(default=0, verbose_name=u'是否开启了指纹登录') # 0:未开启,1:已开启
+    fingerprint_enable = models.SmallIntegerField(default=0, verbose_name=u'是否开启了指纹登录')  # 0:未开启,1:已开启
     fingerprint_key = models.CharField(max_length=128, default='', verbose_name=u'客户端用于解码的密钥等信息')
     fingerprint_key = models.CharField(max_length=128, default='', verbose_name=u'客户端用于解码的密钥等信息')
-    is_local = models.BooleanField(blank=True, default=False, verbose_name=u'是否是本地登录用户') # False:账号登录,1:本地登录
-    subscribe_email = models.SmallIntegerField(default=0, verbose_name=u'是否订阅营销邮件') # 0:未订阅,1:订阅,2:不订阅
+    is_local = models.BooleanField(blank=True, default=False, verbose_name=u'是否是本地登录用户')  # False:账号登录,1:本地登录
+    subscribe_email = models.SmallIntegerField(default=0, verbose_name=u'是否订阅营销邮件')  # 0:未订阅,1:订阅,2:不订阅
     region_country = models.IntegerField(blank=True, default=0, verbose_name='地区表唯一标识')
     region_country = models.IntegerField(blank=True, default=0, verbose_name='地区表唯一标识')
     objects = UserManager()
     objects = UserManager()
 
 
@@ -270,7 +275,7 @@ class Device_Info(models.Model):
     iSNotification = models.BooleanField(blank=True, verbose_name=u'报警通知 0:关闭,1:开启)', default=False)
     iSNotification = models.BooleanField(blank=True, verbose_name=u'报警通知 0:关闭,1:开启)', default=False)
     isVod = models.SmallIntegerField(blank=True, default=0, verbose_name='是否支持云存')  # 是否支持云存设备
     isVod = models.SmallIntegerField(blank=True, default=0, verbose_name='是否支持云存')  # 是否支持云存设备
     isExist = models.SmallIntegerField(blank=True, default=1, verbose_name='是否被删除')  # 是否被删除了(需主用户交互) 1存在,0不存在,2设备被重置
     isExist = models.SmallIntegerField(blank=True, default=1, verbose_name='是否被删除')  # 是否被删除了(需主用户交互) 1存在,0不存在,2设备被重置
-    isCameraOpenCloud =  models.SmallIntegerField(blank=True, default=1, verbose_name='是否开启云存')  # 0:不开启  1:开启
+    isCameraOpenCloud = models.SmallIntegerField(blank=True, default=1, verbose_name='是否开启云存')  # 0:不开启  1:开启
     serial_number = models.CharField(blank=True, max_length=9, default='', verbose_name='关联序列号')
     serial_number = models.CharField(blank=True, max_length=9, default='', verbose_name='关联序列号')
     ###
     ###
     REQUIRED_FIELDS = []
     REQUIRED_FIELDS = []
@@ -324,7 +329,7 @@ class Equipment_Info(models.Model):
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     eventTime = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     eventTime = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receiveTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
     receiveTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
-    userID_id = models.CharField(default='',  db_index=True, blank=True, max_length=32, verbose_name=u'用户ID')
+    userID_id = models.CharField(default='', db_index=True, blank=True, max_length=32, verbose_name=u'用户ID')
     is_st = models.SmallIntegerField(default=0, verbose_name='是否截图')  # 0 否,1 是图,2,视频
     is_st = models.SmallIntegerField(default=0, verbose_name='是否截图')  # 0 否,1 是图,2,视频
     storage_location = models.SmallIntegerField(default=1, verbose_name='数据信息存储位置。1:阿里云oss,2:aws')
     storage_location = models.SmallIntegerField(default=1, verbose_name='数据信息存储位置。1:阿里云oss,2:aws')
     borderCoords = models.TextField(default='', blank=True, verbose_name=u'ai类型图片边框位置信息')
     borderCoords = models.TextField(default='', blank=True, verbose_name=u'ai类型图片边框位置信息')
@@ -568,7 +573,7 @@ class Ai_Push_Info(models.Model):
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     eventTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'设备报警时间')
     eventTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receiveTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
     receiveTime = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
-    userID_id = models.CharField(default='',  db_index=True, blank=True, max_length=32, verbose_name=u'用户ID')
+    userID_id = models.CharField(default='', db_index=True, blank=True, max_length=32, verbose_name=u'用户ID')
     is_st = models.SmallIntegerField(default=0, verbose_name='是否截图')  # 0 否,1 是图,2,视频
     is_st = models.SmallIntegerField(default=0, verbose_name='是否截图')  # 0 否,1 是图,2,视频
     storage_location = models.SmallIntegerField(default=1, db_index=True, verbose_name='数据信息存储位置。1:阿里云oss,2:aws')
     storage_location = models.SmallIntegerField(default=1, db_index=True, verbose_name='数据信息存储位置。1:阿里云oss,2:aws')
     # message_id = models.CharField(blank=True, max_length=32, default='', verbose_name='第三方推送服务器返回的id')
     # message_id = models.CharField(blank=True, max_length=32, default='', verbose_name='第三方推送服务器返回的id')
@@ -700,10 +705,10 @@ class Store_Meal(models.Model):
     symbol = models.CharField(blank=True, default='$', max_length=32, verbose_name=u'符号')
     symbol = models.CharField(blank=True, default='$', max_length=32, verbose_name=u'符号')
     price = models.CharField(blank=True, max_length=32, verbose_name=u'价格')
     price = models.CharField(blank=True, max_length=32, verbose_name=u'价格')
     virtual_price = models.CharField(blank=True, max_length=32, verbose_name=u'虚拟价格')
     virtual_price = models.CharField(blank=True, max_length=32, verbose_name=u'虚拟价格')
-    is_discounts = models.SmallIntegerField(default=0, verbose_name=u'该套餐是否有优惠 [0=否,1是]')   # 0没有;1有
+    is_discounts = models.SmallIntegerField(default=0, verbose_name=u'该套餐是否有优惠 [0=否,1是]')  # 0没有;1有
     discount_price = models.CharField(blank=True, max_length=32, verbose_name=u'第二年优惠价格')
     discount_price = models.CharField(blank=True, max_length=32, verbose_name=u'第二年优惠价格')
-    day = models.IntegerField(default=0, blank=True, verbose_name=u'云存录像保存天数(循环)')   # 7,30,180,360
-    expire = models.IntegerField(default=0, blank=True, verbose_name=u'有效期') #单位月
+    day = models.IntegerField(default=0, blank=True, verbose_name=u'云存录像保存天数(循环)')  # 7,30,180,360
+    expire = models.IntegerField(default=0, blank=True, verbose_name=u'有效期')  # 单位月
     # content = models.TextField(blank=True, null=True, verbose_name=u'描述')
     # content = models.TextField(blank=True, null=True, verbose_name=u'描述')
     add_time = models.DateTimeField(blank=True, null=True, verbose_name=u'加入时间', auto_now_add=True)
     add_time = models.DateTimeField(blank=True, null=True, verbose_name=u'加入时间', auto_now_add=True)
     # type = models.SmallIntegerField(default=0, verbose_name='付款类型')  # 0是paypal,1为支付宝
     # type = models.SmallIntegerField(default=0, verbose_name='付款类型')  # 0是paypal,1为支付宝
@@ -717,7 +722,7 @@ class Store_Meal(models.Model):
     # lang = models.CharField(default='', max_length=20, verbose_name='语言/国家')
     # lang = models.CharField(default='', max_length=20, verbose_name='语言/国家')
     lang = models.ManyToManyField(to='Lang', verbose_name='套餐语言', db_table='store_meal_lang')
     lang = models.ManyToManyField(to='Lang', verbose_name='套餐语言', db_table='store_meal_lang')
     cycle_config_id = models.IntegerField(null=True, verbose_name='周期付款配置表id')
     cycle_config_id = models.IntegerField(null=True, verbose_name='周期付款配置表id')
-    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序,越小越靠前') #单位月
+    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序,越小越靠前')  # 单位月
     # 备用字段
     # 备用字段
     spare_3 = models.CharField(default='', blank=True, max_length=64, db_index=True, verbose_name=u'备用字段3')
     spare_3 = models.CharField(default='', blank=True, max_length=64, db_index=True, verbose_name=u'备用字段3')
     spare_4 = models.CharField(default='', blank=True, max_length=64, db_index=True, verbose_name=u'备用字段4')
     spare_4 = models.CharField(default='', blank=True, max_length=64, db_index=True, verbose_name=u'备用字段4')
@@ -731,6 +736,7 @@ class Store_Meal(models.Model):
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
         ordering = ('id',)
         ordering = ('id',)
 
 
+
 class AiStoreMeal(models.Model):
 class AiStoreMeal(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增ID')
     price = models.CharField(blank=True, max_length=32, verbose_name=u'价格')
     price = models.CharField(blank=True, max_length=32, verbose_name=u'价格')
@@ -738,9 +744,9 @@ class AiStoreMeal(models.Model):
     symbol = models.CharField(blank=True, default='$', max_length=32, verbose_name=u'符号')
     symbol = models.CharField(blank=True, default='$', max_length=32, verbose_name=u'符号')
     currency = models.CharField(blank=True, default='$', max_length=32, verbose_name=u'货币符号')
     currency = models.CharField(blank=True, default='$', max_length=32, verbose_name=u'货币符号')
     is_show = models.SmallIntegerField(default=0, verbose_name=u'是否显示')  # 0: 否, 1: 是
     is_show = models.SmallIntegerField(default=0, verbose_name=u'是否显示')  # 0: 否, 1: 是
-    is_discounts = models.SmallIntegerField(default=0, verbose_name=u'是否有优惠')   # 0: 没有, 1: 有
+    is_discounts = models.SmallIntegerField(default=0, verbose_name=u'是否有优惠')  # 0: 没有, 1: 有
     discount_price = models.CharField(blank=True, max_length=32, verbose_name=u'第二年优惠价格')
     discount_price = models.CharField(blank=True, max_length=32, verbose_name=u'第二年优惠价格')
-    effective_day = models.IntegerField(default=0, blank=True, verbose_name=u'有效天数')   # 7, 30
+    effective_day = models.IntegerField(default=0, blank=True, verbose_name=u'有效天数')  # 7, 30
     pay_type = models.ManyToManyField(to='Pay_Type', verbose_name='付款类型', db_table='ai_store_meal_pay')
     pay_type = models.ManyToManyField(to='Pay_Type', verbose_name='付款类型', db_table='ai_store_meal_pay')
     lang = models.ManyToManyField(to='Lang', verbose_name='套餐语言', db_table='ai_store_meal_lang')
     lang = models.ManyToManyField(to='Lang', verbose_name='套餐语言', db_table='ai_store_meal_lang')
     add_time = models.DateTimeField(blank=True, verbose_name=u'添加时间', auto_now_add=True)
     add_time = models.DateTimeField(blank=True, verbose_name=u'添加时间', auto_now_add=True)
@@ -868,7 +874,7 @@ class Order_Model(models.Model):
     orderID = models.CharField(blank=True, max_length=20, primary_key=True, verbose_name=u'订单id')
     orderID = models.CharField(blank=True, max_length=20, primary_key=True, verbose_name=u'订单id')
     paymentID = models.CharField(blank=True, max_length=64, default='', verbose_name='付款id')
     paymentID = models.CharField(blank=True, max_length=64, default='', verbose_name='付款id')
     trade_no = models.CharField(blank=True, max_length=32, default='', verbose_name='第三方订单号')
     trade_no = models.CharField(blank=True, max_length=32, default='', verbose_name='第三方订单号')
-    userID = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE)    # 订单关联用户
+    userID = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE)  # 订单关联用户
     UID = models.CharField(max_length=20, verbose_name='设备UID')
     UID = models.CharField(max_length=20, verbose_name='设备UID')
     channel = models.SmallIntegerField(default=0, verbose_name=u'通道数')
     channel = models.SmallIntegerField(default=0, verbose_name=u'通道数')
     desc = models.CharField(max_length=50, default='', verbose_name='商品描述')
     desc = models.CharField(max_length=50, default='', verbose_name='商品描述')
@@ -884,8 +890,10 @@ class Order_Model(models.Model):
     payType = models.SmallIntegerField(default=0, verbose_name='支付方式')
     payType = models.SmallIntegerField(default=0, verbose_name='支付方式')
     payTime = models.IntegerField(verbose_name='支付成功时间', default=0)
     payTime = models.IntegerField(verbose_name='支付成功时间', default=0)
     rank = models.ForeignKey(Store_Meal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='关联云存套餐表')
     rank = models.ForeignKey(Store_Meal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='关联云存套餐表')
-    ai_rank = models.ForeignKey(AiStoreMeal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='关联ai套餐表')
-    order_type = models.SmallIntegerField(default=0, verbose_name='订单类型:0:云存:1:ai')
+    ai_rank = models.ForeignKey(AiStoreMeal, to_field='id', default='', on_delete=models.CASCADE,
+                                verbose_name='关联ai套餐表')
+    order_type = models.SmallIntegerField(default=0, verbose_name='订单类型:0:云存,1:ai,2:联通4G')
+    unify_combo_id = models.CharField(blank=True, default='', max_length=32, verbose_name=u'统一套餐id')
     nickname = models.CharField(default='', max_length=64, verbose_name='设备昵称')
     nickname = models.CharField(default='', max_length=64, verbose_name='设备昵称')
     uid_bucket_id = models.IntegerField(default=0, verbose_name='关联uid_bucket的字段')
     uid_bucket_id = models.IntegerField(default=0, verbose_name='关联uid_bucket的字段')
     commodity_type = models.SmallIntegerField(default=0, verbose_name='云存储套餐类型')
     commodity_type = models.SmallIntegerField(default=0, verbose_name='云存储套餐类型')
@@ -909,16 +917,53 @@ class Order_Model(models.Model):
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
         ordering = ('-orderID',)
         ordering = ('-orderID',)
 
 
-class CouponModel(models.Model):
+
+# 优惠券文案语言表
+class CouponLang(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增ID')
+    lang = models.CharField(default='', max_length=20, db_index=True, verbose_name='语言/国家')
+    instruction = models.CharField(blank=True, default='', max_length=200, verbose_name=u'用法')
+    quota = models.CharField(blank=True, default='', max_length=200, verbose_name=u'优惠额度, 例如20.0%')
+    unit = models.CharField(blank=True, default='', max_length=200, verbose_name=u'优惠单位, 例如off, 折')
+    remark = models.CharField(blank=True, default='', max_length=200, verbose_name=u'备注')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'coupon_lang'
+        verbose_name = '套餐语言'
+        verbose_name_plural = verbose_name
+        ordering = ('id',)
+
+
+class CouponConfigModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='主键')
     id = models.AutoField(primary_key=True, verbose_name='主键')
-    userID_id = models.CharField(default='', db_index=True, blank=True, max_length=32, verbose_name=u'用户ID')
-    use_status = models.SmallIntegerField(default=0, verbose_name='使用状态') #0未使用;1冻结;2已使用
-    type = models.SmallIntegerField(default=0, verbose_name='优惠类型') #1打折; 2抵扣
+    type = models.SmallIntegerField(default=0, verbose_name='优惠类型')  # 1打折; 2抵扣
+    use_range = models.CharField(default=0, max_length=100, verbose_name='使用限制')  # 0:所有服务都可使用; 1:云存;2:ai;多种1,2,3
     coupon_discount = models.CharField(blank=True, max_length=32, verbose_name=u'折扣力度')
     coupon_discount = models.CharField(blank=True, max_length=32, verbose_name=u'折扣力度')
-    distributeTime = models.IntegerField(verbose_name='发放到用户账户时间', default=0)
-    valid_time = models.PositiveIntegerField(default=9999999999, verbose_name='有效期间')  #超过有效期不可在使用;0永久
-    # use_limit = models.CharField(default=0, max_length=100, verbose_name='使用限制')  #0:所有服务都可使用; 1:云存;2:ai;
-    addTime = models.IntegerField(verbose_name='添加时间', default=0)
+    lang = models.ManyToManyField(to='CouponLang', verbose_name='套餐语言', db_table='coupon_lang_associated')
+
+    def __str__(self):
+        return self.id
+
+    class Meta:
+        db_table = 'coupon_config'
+        verbose_name = u'优惠券配置表'
+        verbose_name_plural = verbose_name
+
+
+class CouponModel(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='主键')
+    use_status = models.SmallIntegerField(default=0, verbose_name='使用状态')  # 0未使用;1冻结;2已使用
+    distribute_time = models.IntegerField(verbose_name='发放到用户账户时间', default=0)
+    valid_time = models.PositiveIntegerField(default=9999999999, verbose_name='有效期间')  # 超过有效期不可在使用;0永久
+    # userID = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE)  # 关联用户
+    userID = models.CharField(blank=True, max_length=32, db_index=True, verbose_name=u'用户ID')
+    coupon_config = models.ForeignKey(CouponConfigModel, null=True, blank=True, to_field='id', on_delete=models.CASCADE,
+                                      verbose_name='关联优惠券配置表的id')
+    update_time = models.IntegerField(verbose_name='更新时间', default=0)
+    create_time = models.IntegerField(verbose_name='添加时间', default=0)
 
 
     def __str__(self):
     def __str__(self):
         return self.id
         return self.id
@@ -928,12 +973,13 @@ class CouponModel(models.Model):
         verbose_name = u'优惠券'
         verbose_name = u'优惠券'
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
 
 
+
 class PayCycleConfigModel(models.Model):
 class PayCycleConfigModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='主键')
     id = models.AutoField(primary_key=True, verbose_name='主键')
     # name = models.CharField(default='',max_length=200, verbose_name='计划名字')
     # name = models.CharField(default='',max_length=200, verbose_name='计划名字')
     # tax = models.CharField(max_length=2000, default='', verbose_name='税金')
     # tax = models.CharField(max_length=2000, default='', verbose_name='税金')
     cycles = models.IntegerField(verbose_name='周期:0代表无限期', default=0)
     cycles = models.IntegerField(verbose_name='周期:0代表无限期', default=0)
-    frequency = models.CharField(max_length=50,verbose_name='频率,MONTH,WEEK,YEAR', default=0)
+    frequency = models.CharField(max_length=50, verbose_name='频率,MONTH,WEEK,YEAR', default=0)
     frequencyInterval = models.IntegerField(default=0, verbose_name='频率周期')
     frequencyInterval = models.IntegerField(default=0, verbose_name='频率周期')
     remark = models.CharField(max_length=1000, default='', verbose_name='备注')
     remark = models.CharField(max_length=1000, default='', verbose_name='备注')
 
 
@@ -945,16 +991,19 @@ class PayCycleConfigModel(models.Model):
         verbose_name = u'周期付款计划'
         verbose_name = u'周期付款计划'
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
 
 
+
 class PromotionRuleModel(models.Model):
 class PromotionRuleModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='主键')
     id = models.AutoField(primary_key=True, verbose_name='主键')
-    ruleName = models.TextField(default='', verbose_name='规则名字')                     #json格式, 例: {"cn":"黑色星期五","en":"Black Friday"}
-    ruleDesc = models.TextField(default='', verbose_name='规则描述')                     #json格式,   例:  {"cn":"买一送一","en":"buy one get one free"}
-    ruleConfig = models.CharField(max_length=2000, default='', verbose_name='规则配置')  #json格式, 例: {"buy": 1, "get": 1}
+    ruleName = models.TextField(default='', verbose_name='规则名字')  # json格式, 例: {"cn":"黑色星期五","en":"Black Friday"}
+    ruleDesc = models.TextField(default='',
+                                verbose_name='规则描述')  # json格式,   例:  {"cn":"买一送一","en":"buy one get one free"}
+    ruleConfig = models.CharField(max_length=2000, default='', verbose_name='规则配置')  # json格式, 例: {"buy": 1, "get": 1}
     startTime = models.IntegerField(verbose_name='促销活动开始时间', default=0)
     startTime = models.IntegerField(verbose_name='促销活动开始时间', default=0)
     endTime = models.IntegerField(verbose_name='促销活动结束时间', default=0)
     endTime = models.IntegerField(verbose_name='促销活动结束时间', default=0)
     status = models.SmallIntegerField(default=0, verbose_name='活动状态:0未进行;1进行中')
     status = models.SmallIntegerField(default=0, verbose_name='活动状态:0未进行;1进行中')
     remark = models.CharField(max_length=50, default='', verbose_name='备注')
     remark = models.CharField(max_length=50, default='', verbose_name='备注')
-    popups = models.CharField(max_length=2000, default='', verbose_name='app弹窗消息')   #json格式 ,例: {"cn":"买一送一","en":"buy one get one free"}
+    popups = models.CharField(max_length=2000, default='',
+                              verbose_name='app弹窗消息')  # json格式 ,例: {"cn":"买一送一","en":"buy one get one free"}
 
 
     def __str__(self):
     def __str__(self):
         return self.id
         return self.id
@@ -966,7 +1015,6 @@ class PromotionRuleModel(models.Model):
         ordering = ('-id',)
         ordering = ('-id',)
 
 
 
 
-
 class VodHlsModel(models.Model):
 class VodHlsModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='回放列表主键')
     id = models.AutoField(primary_key=True, verbose_name='回放列表主键')
     uid = models.CharField(max_length=20, verbose_name='设备UID', db_index=True)
     uid = models.CharField(max_length=20, verbose_name='设备UID', db_index=True)
@@ -976,8 +1024,7 @@ class VodHlsModel(models.Model):
     sec = models.IntegerField(verbose_name='秒数', default=0)
     sec = models.IntegerField(verbose_name='秒数', default=0)
     bucket = models.ForeignKey(VodBucketModel, blank=True, to_field='id', on_delete=models.CASCADE, default=1,
     bucket = models.ForeignKey(VodBucketModel, blank=True, to_field='id', on_delete=models.CASCADE, default=1,
                                verbose_name='存储空间')
                                verbose_name='存储空间')
-    fg = models.CharField(max_length=20,verbose_name='ts个数,时间描述片段数') # 阿里为时间片段数,亚马逊为一个32bit整型,前28bit代表ts文件的时长
-
+    fg = models.CharField(max_length=20, verbose_name='ts个数,时间描述片段数')  # 阿里为时间片段数,亚马逊为一个32bit整型,前28bit代表ts文件的时长
 
 
     def __str__(self):
     def __str__(self):
         return self.id
         return self.id
@@ -1016,7 +1063,7 @@ class StsCrdModel(models.Model):
     addTime = models.IntegerField(verbose_name='添加时间', default=0)
     addTime = models.IntegerField(verbose_name='添加时间', default=0)
     bucket = models.ForeignKey(VodBucketModel, blank=True, to_field='id', on_delete=models.CASCADE, default=1,
     bucket = models.ForeignKey(VodBucketModel, blank=True, to_field='id', on_delete=models.CASCADE, default=1,
                                verbose_name='存储空间')
                                verbose_name='存储空间')
-    type = models.SmallIntegerField(default=0,verbose_name='sts类型') # 0:阿里云,1:s3
+    type = models.SmallIntegerField(default=0, verbose_name='sts类型')  # 0:阿里云,1:s3
 
 
     def __str__(self):
     def __str__(self):
         return self.id
         return self.id
@@ -1046,6 +1093,7 @@ class UID_Bucket(models.Model):
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
         ordering = ('id',)
         ordering = ('id',)
 
 
+
 class Unused_Uid_Meal(models.Model):
 class Unused_Uid_Meal(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     uid = models.CharField(max_length=20, verbose_name='设备UID', db_index=True)
     uid = models.CharField(max_length=20, verbose_name='设备UID', db_index=True)
@@ -1054,6 +1102,7 @@ class Unused_Uid_Meal(models.Model):
     addTime = models.IntegerField(verbose_name='添加时间', default=0)
     addTime = models.IntegerField(verbose_name='添加时间', default=0)
     expire = models.IntegerField(verbose_name='存储桶存储时长[月份]', default=0)
     expire = models.IntegerField(verbose_name='存储桶存储时长[月份]', default=0)
     num = models.IntegerField(verbose_name='个数', default=0)
     num = models.IntegerField(verbose_name='个数', default=0)
+
     # effect_time = models.BigIntegerField(verbose_name='生效时间', db_index=True, default=0)
     # effect_time = models.BigIntegerField(verbose_name='生效时间', db_index=True, default=0)
     # uid_bucket = models.ForeignKey(UID_Bucket, blank=True, to_field='id', on_delete=models.CASCADE, default=0,
     # uid_bucket = models.ForeignKey(UID_Bucket, blank=True, to_field='id', on_delete=models.CASCADE, default=0,
     #                            verbose_name='uid_bucket关联')
     #                            verbose_name='uid_bucket关联')
@@ -1111,14 +1160,14 @@ class UidSetModel(models.Model):
     version = models.CharField(max_length=32, verbose_name='设备版本', default='')
     version = models.CharField(max_length=32, verbose_name='设备版本', default='')
     p2p_region = models.CharField(max_length=16, verbose_name='设备p2p区域', default='ALL')  # ALL CN EU US
     p2p_region = models.CharField(max_length=16, verbose_name='设备p2p区域', default='ALL')  # ALL CN EU US
     cloud_vod = models.SmallIntegerField(default=2, verbose_name='云存开关')  # 0,关闭,1开启,2,不支持
     cloud_vod = models.SmallIntegerField(default=2, verbose_name='云存开关')  # 0,关闭,1开启,2,不支持
-    tz = models.CharField(default='', max_length=16, verbose_name ='设备时区')  # +8
+    tz = models.CharField(default='', max_length=16, verbose_name='设备时区')  # +8
     video_code = models.SmallIntegerField(default=0, verbose_name='编码类型')  # 0:264,1:265
     video_code = models.SmallIntegerField(default=0, verbose_name='编码类型')  # 0:264,1:265
     nickname = models.CharField(default='', max_length=64, verbose_name='设备昵称')
     nickname = models.CharField(default='', max_length=64, verbose_name='设备昵称')
     ip = models.CharField(max_length=20, default='', verbose_name=u'设备ip')
     ip = models.CharField(max_length=20, default='', verbose_name=u'设备ip')
     # 设备重置后第一次启动时间
     # 设备重置后第一次启动时间
     is_alexa = models.IntegerField(default=0, verbose_name='是否支持alexa')  # 0为不支持,1为支持,2为开启alexa发现
     is_alexa = models.IntegerField(default=0, verbose_name='是否支持alexa')  # 0为不支持,1为支持,2为开启alexa发现
     detect_group = models.CharField(default='', max_length=32, verbose_name=u'检测类型')
     detect_group = models.CharField(default='', max_length=32, verbose_name=u'检测类型')
-    pwd = models.CharField(max_length=32, default='', verbose_name=u'设备密码') # 暂时是预留字段
+    pwd = models.CharField(max_length=32, default='', verbose_name=u'设备密码')  # 暂时是预留字段
     resetTime = models.IntegerField(default=0, verbose_name='设备重置时间')
     resetTime = models.IntegerField(default=0, verbose_name='设备重置时间')
     region_alexa = models.CharField(max_length=8, verbose_name='设备alexa区域', default='ALL')  # ALL CN EU US
     region_alexa = models.CharField(max_length=8, verbose_name='设备alexa区域', default='ALL')  # ALL CN EU US
     deviceModel = models.CharField(blank=True, max_length=64, default='', verbose_name=u'设备型号')
     deviceModel = models.CharField(blank=True, max_length=64, default='', verbose_name=u'设备型号')
@@ -1137,6 +1186,9 @@ class UidSetModel(models.Model):
     double_wifi = models.IntegerField(default=0, verbose_name='是否支持双频wifi。0:不支持,1:支持')
     double_wifi = models.IntegerField(default=0, verbose_name='是否支持双频wifi。0:不支持,1:支持')
     is_ptz = models.IntegerField(default=0, verbose_name='是否支持云台。0:不支持,1:支持')
     is_ptz = models.IntegerField(default=0, verbose_name='是否支持云台。0:不支持,1:支持')
     is_ai = models.IntegerField(default=2, verbose_name='是否支持ai')  # 0,关闭,1开启,2,不支持
     is_ai = models.IntegerField(default=2, verbose_name='是否支持ai')  # 0,关闭,1开启,2,不支持
+    is_notification = models.IntegerField(blank=True, default=1, verbose_name='新加-消息提醒开关')  # 0:关闭,1:开启
+    new_detect_interval = models.IntegerField(blank=True, verbose_name='新加-消息提醒间隔', default=60)  # 秒
+
     class Meta:
     class Meta:
         db_table = 'uid_set'
         db_table = 'uid_set'
         verbose_name = u'设备配置表'
         verbose_name = u'设备配置表'
@@ -1380,7 +1432,7 @@ class GrantCodeModel(models.Model):
 class UserAppFrequencyModel(models.Model):
 class UserAppFrequencyModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
     user = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE, verbose_name='关联设备用户表')
     user = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE, verbose_name='关联设备用户表')
-    type = models.SmallIntegerField(default=0, verbose_name='使用频率类型') # 1:每天,2:三天,3:一周,4:两周,5:一个月,6:一个月以上
+    type = models.SmallIntegerField(default=0, verbose_name='使用频率类型')  # 1:每天,2:三天,3:一周,4:两周,5:一个月,6:一个月以上
     data_time = models.IntegerField(default=0, verbose_name='数据时间')
     data_time = models.IntegerField(default=0, verbose_name='数据时间')
     add_time = models.IntegerField(default=0, verbose_name='添加时间')
     add_time = models.IntegerField(default=0, verbose_name='添加时间')
     update_time = models.IntegerField(default=0, verbose_name='更新时间')
     update_time = models.IntegerField(default=0, verbose_name='更新时间')
@@ -1415,6 +1467,7 @@ class AppFrequencyYearStatisticsModel(models.Model):
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
         db_table = 'app_frequency_year_statistics'
         db_table = 'app_frequency_year_statistics'
 
 
+
 # alexa连接数统计表
 # alexa连接数统计表
 class AlexaConnectStatisticsModel(models.Model):
 class AlexaConnectStatisticsModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
@@ -1445,7 +1498,7 @@ class AppLogModel(models.Model):
     user = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE, verbose_name='关联设备用户表')
     user = models.ForeignKey(Device_User, to_field='userID', on_delete=models.CASCADE, verbose_name='关联设备用户表')
     uid = models.CharField(max_length=20, default='', verbose_name='设备uid')
     uid = models.CharField(max_length=20, default='', verbose_name='设备uid')
     average_delay = models.CharField(max_length=32, default='', verbose_name='最高平均延时')
     average_delay = models.CharField(max_length=32, default='', verbose_name='最高平均延时')
-    status = models.SmallIntegerField(default=0, verbose_name='失败状态')   # 0: 成功,1: 失败
+    status = models.SmallIntegerField(default=0, verbose_name='失败状态')  # 0: 成功,1: 失败
     filename = models.CharField(max_length=120, default='', verbose_name='文件名')
     filename = models.CharField(max_length=120, default='', verbose_name='文件名')
     add_time = models.IntegerField(default=0, verbose_name='日期')
     add_time = models.IntegerField(default=0, verbose_name='日期')
 
 
@@ -1460,9 +1513,9 @@ class DeviceLogModel(models.Model):
     ip = models.CharField(default='', max_length=32, verbose_name='ip')
     ip = models.CharField(default='', max_length=32, verbose_name='ip')
     uid = models.CharField(max_length=32, default='', verbose_name='设备uid')
     uid = models.CharField(max_length=32, default='', verbose_name='设备uid')
     serial_number = models.CharField(max_length=9, default='', verbose_name='序列号')
     serial_number = models.CharField(max_length=9, default='', verbose_name='序列号')
-    status = models.SmallIntegerField(default=0, verbose_name='上传状态')   # 0: 成功,1: 失败, 3非文件形式,与error_info相关
+    status = models.SmallIntegerField(default=0, verbose_name='上传状态')  # 0: 成功,1: 失败, 3非文件形式,与error_info相关
     filename = models.CharField(max_length=120, default='', verbose_name='文件名')
     filename = models.CharField(max_length=120, default='', verbose_name='文件名')
-    error_info = models.TextField(blank = True, default = '', verbose_name='设备异常信息')
+    error_info = models.TextField(blank=True, default='', verbose_name='设备异常信息')
     add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
     add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
 
 
     class Meta:
     class Meta:
@@ -1504,8 +1557,8 @@ class CountryIPModel(models.Model):
 class ZositechHelpModel(models.Model):
 class ZositechHelpModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
     locale = models.CharField(default='', db_index=True, max_length=50, verbose_name='语言')
     locale = models.CharField(default='', db_index=True, max_length=50, verbose_name='语言')
-    label_names =  models.CharField(default='', db_index=True, max_length=50, verbose_name='标签')
-    origin  =  models.CharField(default='', db_index=True ,max_length=50, verbose_name='来源')
+    label_names = models.CharField(default='', db_index=True, max_length=50, verbose_name='标签')
+    origin = models.CharField(default='', db_index=True, max_length=50, verbose_name='来源')
     # author_id = models.CharField(default='', max_length=50, verbose_name='管理员id')
     # author_id = models.CharField(default='', max_length=50, verbose_name='管理员id')
     # body = models.TextField(default='', blank=True, verbose_name='内容')
     # body = models.TextField(default='', blank=True, verbose_name='内容')
     # comments_disabled = models.CharField(default='', max_length=10, verbose_name='comments')
     # comments_disabled = models.CharField(default='', max_length=10, verbose_name='comments')
@@ -1532,7 +1585,8 @@ class EquipmentVersionLimitModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
     type = models.SmallIntegerField(default=0, verbose_name='限制类型')
     type = models.SmallIntegerField(default=0, verbose_name='限制类型')
     content = models.TextField(default='', verbose_name='限制内容')
     content = models.TextField(default='', verbose_name='限制内容')
-    equipment_version = models.ForeignKey(Equipment_Version, to_field='eid', on_delete=models.CASCADE, verbose_name='关联设备版本信息id')
+    equipment_version = models.ForeignKey(Equipment_Version, to_field='eid', on_delete=models.CASCADE,
+                                          verbose_name='关联设备版本信息id')
     status = models.SmallIntegerField(default=0, verbose_name='是否启用。0:不启用,1:启用')
     status = models.SmallIntegerField(default=0, verbose_name='是否启用。0:不启用,1:启用')
     add_time = models.IntegerField(default=0, verbose_name='添加时间')
     add_time = models.IntegerField(default=0, verbose_name='添加时间')
     update_time = models.IntegerField(default=0, verbose_name='更新时间')
     update_time = models.IntegerField(default=0, verbose_name='更新时间')
@@ -1545,9 +1599,10 @@ class EquipmentVersionLimitModel(models.Model):
 
 
 class ExperienceContextModel(models.Model):
 class ExperienceContextModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
-    experience_type = models.SmallIntegerField(default=0,verbose_name='体验类型') # 0: 免费体验套餐, 1: 激活码
+    experience_type = models.SmallIntegerField(default=0, verbose_name='体验类型')  # 0: 免费体验套餐, 1: 激活码
     uid = models.CharField(max_length=20, default='', verbose_name='设备uid')
     uid = models.CharField(max_length=20, default='', verbose_name='设备uid')
     do_time = models.IntegerField(default=0, verbose_name='激活时间')
     do_time = models.IntegerField(default=0, verbose_name='激活时间')
+
     # is_experience = models.SmallIntegerField(default=0, verbose_name=u'是否云存体验用户')  # 0:不是体验用户,1:是体验用户
     # is_experience = models.SmallIntegerField(default=0, verbose_name=u'是否云存体验用户')  # 0:不是体验用户,1:是体验用户
 
 
     class Meta:
     class Meta:
@@ -1555,13 +1610,26 @@ class ExperienceContextModel(models.Model):
         verbose_name = '设备体验表'
         verbose_name = '设备体验表'
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
 
 
+
+class ExperienceAiModel(models.Model):
+    id = models.AutoField(primary_key=True)
+    experience_type = models.SmallIntegerField(default=0, verbose_name='体验类型')  # 0: 免费体验, 1: 激活码
+    uid = models.CharField(max_length=20, default='', verbose_name='设备uid')
+    do_time = models.IntegerField(default=0, verbose_name='激活时间')
+
+    class Meta:
+        db_table = 'experience_ai'
+        verbose_name = 'ai体验表'
+        verbose_name_plural = verbose_name
+
+
 class CDKcontextModel(models.Model):
 class CDKcontextModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
-    cdk = models.CharField(max_length=50,unique=True,verbose_name='激活码')
+    cdk = models.CharField(max_length=50, unique=True, verbose_name='激活码')
     create_time = models.IntegerField(default=0, verbose_name='创建时间')
     create_time = models.IntegerField(default=0, verbose_name='创建时间')
-    valid_time = models.IntegerField(default=0, verbose_name='有效期间')  #超过有效期激活码不可在激活 ,0:永久
-    is_activate = models.SmallIntegerField(default=0, verbose_name='是否已激活') #0 未激活  1 已激活
-    is_down = models.SmallIntegerField(default=0, verbose_name='是否已下载') #0 未下载 1 已下载
+    valid_time = models.IntegerField(default=0, verbose_name='有效期间')  # 超过有效期激活码不可在激活 ,0:永久
+    is_activate = models.SmallIntegerField(default=0, verbose_name='是否已激活')  # 0 未激活  1 已激活
+    is_down = models.SmallIntegerField(default=0, verbose_name='是否已下载')  # 0 未下载 1 已下载
     rank = models.ForeignKey(Store_Meal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='套餐类型')
     rank = models.ForeignKey(Store_Meal, to_field='id', default='', on_delete=models.CASCADE, verbose_name='套餐类型')
     # order = models.ForeignKey(Order_Model, blank=True, max_length=20, to_field='orderID', on_delete=models.CASCADE, verbose_name='订单id', unique=True)
     # order = models.ForeignKey(Order_Model, blank=True, max_length=20, to_field='orderID', on_delete=models.CASCADE, verbose_name='订单id', unique=True)
     order = models.CharField(max_length=20, blank=True, unique=True, verbose_name='订单id')
     order = models.CharField(max_length=20, blank=True, unique=True, verbose_name='订单id')
@@ -1612,6 +1680,45 @@ class DeviceTypeModel(models.Model):
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
 
 
 
 
+class AppBundle(models.Model):
+    id = models.AutoField(primary_key=True)
+    app_bundle_id = models.CharField(default='', max_length=32, verbose_name='app版本id')
+    app_device_type = models.ManyToManyField(to='AppDeviceType', db_table='app_bundle_device_type',
+                                             verbose_name='APP版本-设备类型')
+
+    class Meta:
+        db_table = 'app_bundle'
+        verbose_name = 'APP版本表'
+        verbose_name_plural = verbose_name
+
+
+class AppDeviceType(models.Model):
+    id = models.AutoField(primary_key=True)
+    model = models.SmallIntegerField(default=0, verbose_name='设备类型')  # 1:DVR, 2:IPC
+    type = models.IntegerField(default=0, verbose_name='设备型号')
+    icon = models.CharField(default='', max_length=200, verbose_name='图标文件路径')
+
+    class Meta:
+        db_table = 'app_device_type'
+        verbose_name = 'APP设备类型表'
+        verbose_name_plural = verbose_name
+
+
+class DeviceNameLanguage(models.Model):
+    id = models.AutoField(primary_key=True)
+    app_device_type = models.ForeignKey(AppDeviceType, to_field='id', default='', on_delete=models.CASCADE,
+                                        verbose_name='关联APP设备类型表id')
+    lang = models.CharField(default='', max_length=10, verbose_name='语言')
+    name = models.CharField(default='', max_length=32, verbose_name='设备名称')
+    sort = models.SmallIntegerField(default=0, verbose_name=u'升序排序')
+
+    class Meta:
+        ordering = ('sort',)
+        db_table = 'device_name_language'
+        verbose_name = '设备名称语言表'
+        verbose_name_plural = verbose_name
+
+
 class OperatingLogsModel(models.Model):
 class OperatingLogsModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
     userId = models.CharField(blank=False, max_length=32, db_index=True, verbose_name=u'操作人')
     userId = models.CharField(blank=False, max_length=32, db_index=True, verbose_name=u'操作人')
@@ -1640,6 +1747,7 @@ class ProcessInfoLogsModel(models.Model):
         verbose_name = '过程信息表'
         verbose_name = '过程信息表'
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
 
 
+
 class EquipmentLogModel(models.Model):
 class EquipmentLogModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
     user = models.CharField(blank=False, max_length=32, db_index=True, verbose_name=u'操作用户')
     user = models.CharField(blank=False, max_length=32, db_index=True, verbose_name=u'操作用户')
@@ -1650,6 +1758,7 @@ class EquipmentLogModel(models.Model):
     time = models.DateTimeField(null=True, blank=True, db_index=True, verbose_name=u'访问时间')
     time = models.DateTimeField(null=True, blank=True, db_index=True, verbose_name=u'访问时间')
     operatingcontent = models.TextField(blank=True, default='', verbose_name=u'操作内容')
     operatingcontent = models.TextField(blank=True, default='', verbose_name=u'操作内容')
     url = models.CharField(max_length=150, default='', blank=True, verbose_name=u'访问路径')
     url = models.CharField(max_length=150, default='', blank=True, verbose_name=u'访问路径')
+
     class Meta:
     class Meta:
         db_table = 'equipment_log'
         db_table = 'equipment_log'
         verbose_name = '设备日志表'
         verbose_name = '设备日志表'
@@ -1693,7 +1802,6 @@ class RegionModel(models.Model):
     continent_code = models.CharField(max_length=3, default='', verbose_name='洲代码')
     continent_code = models.CharField(max_length=3, default='', verbose_name='洲代码')
     api = models.CharField(max_length=50, default='', verbose_name='请求地址')
     api = models.CharField(max_length=50, default='', verbose_name='请求地址')
 
 
-
     class Meta:
     class Meta:
         db_table = 'tb_region'
         db_table = 'tb_region'
         verbose_name = '区域表'
         verbose_name = '区域表'
@@ -1720,10 +1828,10 @@ class UIDModel(models.Model):
     uid = models.CharField(max_length=20, null=False, db_index=True, unique=True, verbose_name='设备id')
     uid = models.CharField(max_length=20, null=False, db_index=True, unique=True, verbose_name='设备id')
     mac = models.CharField(max_length=17, null=True, default='', verbose_name='设备id对应的mac地址')
     mac = models.CharField(max_length=17, null=True, default='', verbose_name='设备id对应的mac地址')
     uid_extra = models.TextField(default='', verbose_name='uid的额外描述')
     uid_extra = models.TextField(default='', verbose_name='uid的额外描述')
-    status = models.SmallIntegerField(default=0, verbose_name='使用状态')   # 0:未使用, 2:已使用
+    status = models.SmallIntegerField(default=0, verbose_name='使用状态')  # 0:未使用, 2:已使用
     add_time = models.IntegerField(default=0, verbose_name='添加时间')
     add_time = models.IntegerField(default=0, verbose_name='添加时间')
     update_time = models.IntegerField(default=0, verbose_name='更新时间')
     update_time = models.IntegerField(default=0, verbose_name='更新时间')
-    area = models.SmallIntegerField(default=0, verbose_name='区域')   # 0:国内, 1:国外
+    area = models.SmallIntegerField(default=0, verbose_name='区域')  # 0:国内, 1:国外
     vpg = models.ForeignKey(VPGModel, to_field='id', default=1, on_delete=models.DO_NOTHING, verbose_name='关联VPG表的id')
     vpg = models.ForeignKey(VPGModel, to_field='id', default=1, on_delete=models.DO_NOTHING, verbose_name='关联VPG表的id')
     p2p_type = models.IntegerField(default=1, verbose_name='p2p类型。1:宸云,2:tutk')
     p2p_type = models.IntegerField(default=1, verbose_name='p2p类型。1:宸云,2:tutk')
     full_uid_code = models.CharField(max_length=256, default='', verbose_name='宸云完整uid')
     full_uid_code = models.CharField(max_length=256, default='', verbose_name='宸云完整uid')
@@ -1895,7 +2003,8 @@ class CompanySerialModel(models.Model):
 class UIDCompanySerialModel(models.Model):
 class UIDCompanySerialModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
     uid = models.ForeignKey(UIDModel, to_field='id', on_delete=models.CASCADE, verbose_name='关联UID表')
     uid = models.ForeignKey(UIDModel, to_field='id', on_delete=models.CASCADE, verbose_name='关联UID表')
-    company_serial = models.ForeignKey(CompanySerialModel, to_field='id', on_delete=models.CASCADE, verbose_name='6位数序列号')
+    company_serial = models.ForeignKey(CompanySerialModel, to_field='id', on_delete=models.CASCADE,
+                                       verbose_name='6位数序列号')
     add_time = models.IntegerField(default=0, verbose_name='添加时间')
     add_time = models.IntegerField(default=0, verbose_name='添加时间')
     update_time = models.IntegerField(default=0, verbose_name='更新时间')
     update_time = models.IntegerField(default=0, verbose_name='更新时间')
 
 
@@ -1907,7 +2016,8 @@ class UIDCompanySerialModel(models.Model):
 
 
 class iotdeviceInfoModel(models.Model):
 class iotdeviceInfoModel(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
-    serial_number = models.CharField(max_length=11, blank=True, default='', db_index=True, verbose_name=u'关联Device_Info表的序列号')
+    serial_number = models.CharField(max_length=11, blank=True, default='', db_index=True,
+                                     verbose_name=u'关联Device_Info表的序列号')
     uid = models.CharField(blank=True, max_length=32, default='', db_index=True, verbose_name=u'设备UID')
     uid = models.CharField(blank=True, max_length=32, default='', db_index=True, verbose_name=u'设备UID')
     certificate_id = models.CharField(blank=True, max_length=256, default='', verbose_name=u'证书id')
     certificate_id = models.CharField(blank=True, max_length=256, default='', verbose_name=u'证书id')
     certificate_pem = models.TextField(blank=True, default='', verbose_name=u'证书项目')
     certificate_pem = models.TextField(blank=True, default='', verbose_name=u'证书项目')
@@ -1916,9 +2026,10 @@ class iotdeviceInfoModel(models.Model):
     thing_name = models.CharField(blank=True, max_length=256, default='', verbose_name=u'IoT Thing Name')
     thing_name = models.CharField(blank=True, max_length=256, default='', verbose_name=u'IoT Thing Name')
     thing_groups = models.CharField(blank=True, max_length=256, default='', verbose_name=u'IoT Thing Groups')
     thing_groups = models.CharField(blank=True, max_length=256, default='', verbose_name=u'IoT Thing Groups')
     endpoint = models.CharField(blank=True, max_length=256, db_index=True, default='', verbose_name=u'iot端点')
     endpoint = models.CharField(blank=True, max_length=256, db_index=True, default='', verbose_name=u'iot端点')
-    token_iot_number = models.CharField(blank=True,  db_index=True, default='', max_length=50, verbose_name='连接iot令牌')
+    token_iot_number = models.CharField(blank=True, db_index=True, default='', max_length=50, verbose_name='连接iot令牌')
     add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
     add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
     update_time = models.DateTimeField(blank=True, auto_now=True, verbose_name=u'更新时间')
     update_time = models.DateTimeField(blank=True, auto_now=True, verbose_name=u'更新时间')
+
     class Meta:
     class Meta:
         db_table = 'iot_deviceInfo'
         db_table = 'iot_deviceInfo'
         verbose_name = 'iot设备信息表'
         verbose_name = 'iot设备信息表'
@@ -1930,6 +2041,7 @@ class UIDMainUser(models.Model):
     id = models.AutoField(primary_key=True)
     id = models.AutoField(primary_key=True)
     UID = models.CharField(blank=True, max_length=32, verbose_name=u'设备UID', default='')
     UID = models.CharField(blank=True, max_length=32, verbose_name=u'设备UID', default='')
     user_id = models.CharField(blank=True, max_length=32, verbose_name=u'用户ID', default='')
     user_id = models.CharField(blank=True, max_length=32, verbose_name=u'用户ID', default='')
+
     class Meta:
     class Meta:
         db_table = 'uid_mainuser'
         db_table = 'uid_mainuser'
         verbose_name = '设备主用户表'
         verbose_name = '设备主用户表'
@@ -1954,7 +2066,6 @@ class Pc_Info(models.Model):
     content = models.TextField(blank=True, default='', verbose_name=u'内容信息')
     content = models.TextField(blank=True, default='', verbose_name=u'内容信息')
     authority = models.SmallIntegerField(blank=True, default=0, verbose_name='权限')
     authority = models.SmallIntegerField(blank=True, default=0, verbose_name='权限')
 
 
-
     class Meta:
     class Meta:
         db_table = 'pc_info'
         db_table = 'pc_info'
         verbose_name = u'pc信息表'
         verbose_name = u'pc信息表'
@@ -1971,6 +2082,7 @@ class CloudLogModel(models.Model):
     url = models.CharField(max_length=150, default='', blank=True, verbose_name=u'访问路径')
     url = models.CharField(max_length=150, default='', blank=True, verbose_name=u'访问路径')
     time = models.IntegerField(null=True, blank=True, db_index=True, verbose_name=u'访问时间')
     time = models.IntegerField(null=True, blank=True, db_index=True, verbose_name=u'访问时间')
     content = models.TextField(blank=True, default='', verbose_name=u'参数内容')
     content = models.TextField(blank=True, default='', verbose_name=u'参数内容')
+
     class Meta:
     class Meta:
         db_table = 'cloud_log'
         db_table = 'cloud_log'
         verbose_name = '云存api记录表'
         verbose_name = '云存api记录表'
@@ -1995,6 +2107,7 @@ class PctestjobModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     jobname = models.CharField(blank=True, max_length=32, verbose_name=u'岗位名字')
     jobname = models.CharField(blank=True, max_length=32, verbose_name=u'岗位名字')
     jobcode = models.SmallIntegerField(default=3, verbose_name='岗位code 。1:管理员,3:普通人员')
     jobcode = models.SmallIntegerField(default=3, verbose_name='岗位code 。1:管理员,3:普通人员')
+
     class Meta:
     class Meta:
         db_table = 'pctest_job'
         db_table = 'pctest_job'
         verbose_name = u'pc岗位表'
         verbose_name = u'pc岗位表'
@@ -2030,6 +2143,7 @@ class PctestfunctionModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     functionname = models.CharField(blank=True, max_length=32, verbose_name=u'职能名字')
     functionname = models.CharField(blank=True, max_length=32, verbose_name=u'职能名字')
     functioncode = models.SmallIntegerField(default=1, verbose_name='职能code 。PC端自己逻辑判断')
     functioncode = models.SmallIntegerField(default=1, verbose_name='职能code 。PC端自己逻辑判断')
+
     class Meta:
     class Meta:
         db_table = 'pctest_function'
         db_table = 'pctest_function'
         verbose_name = u'pc设备职能表'
         verbose_name = u'pc设备职能表'
@@ -2078,7 +2192,8 @@ class PctestjobdeviceModel(models.Model):
 class PctestModel(models.Model):
 class PctestModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     device = models.ForeignKey(PctestdeviceModel, to_field='id', on_delete=models.DO_NOTHING, verbose_name='关联pc测试设备表')
     device = models.ForeignKey(PctestdeviceModel, to_field='id', on_delete=models.DO_NOTHING, verbose_name='关联pc测试设备表')
-    function = models.ForeignKey(PctestfunctionModel, to_field='id', on_delete=models.DO_NOTHING, verbose_name='关联pc设备职能表')
+    function = models.ForeignKey(PctestfunctionModel, to_field='id', on_delete=models.DO_NOTHING,
+                                 verbose_name='关联pc设备职能表')
 
 
     class Meta:
     class Meta:
         db_table = 'pctest_device_function'
         db_table = 'pctest_device_function'
@@ -2108,12 +2223,9 @@ class P2PIpModel(models.Model):
 
 
 class DeviceDomainModel(models.Model):
 class DeviceDomainModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
-    uid = models.CharField(max_length=20, default='', unique=True, db_index=True, verbose_name='uid')
-    serial_number = models.CharField(max_length=9, default='', unique=True, db_index=True, verbose_name='序列号')
     ip = models.CharField(default='', max_length=32, verbose_name='ip')
     ip = models.CharField(default='', max_length=32, verbose_name='ip')
     country_name = models.CharField(max_length=20, default='', verbose_name='国家名')
     country_name = models.CharField(max_length=20, default='', verbose_name='国家名')
     api = models.CharField(max_length=50, default='', verbose_name='使用的域名')
     api = models.CharField(max_length=50, default='', verbose_name='使用的域名')
-    region_id = models.SmallIntegerField(default=0, verbose_name='地区id')
     add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
     add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
     update_time = models.DateTimeField(blank=True, auto_now=True, verbose_name=u'更新时间')
     update_time = models.DateTimeField(blank=True, auto_now=True, verbose_name=u'更新时间')
 
 
@@ -2123,6 +2235,22 @@ class DeviceDomainModel(models.Model):
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
 
 
 
 
+class DeviceDomainRegionModel(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    serial_number = models.CharField(max_length=9, default='', verbose_name='序列号')
+    ip = models.CharField(default='', max_length=32, verbose_name='ip')
+    country_name = models.CharField(max_length=20, default='', verbose_name='国家名')
+    api = models.CharField(max_length=50, default='', verbose_name='使用的域名')
+    region_id = models.SmallIntegerField(default=0, verbose_name='地区id')
+    add_time = models.DateTimeField(blank=True, auto_now_add=True, verbose_name=u'添加时间')
+    update_time = models.DateTimeField(blank=True, auto_now=True, verbose_name=u'更新时间')
+
+    class Meta:
+        db_table = 'device_domain_region'
+        verbose_name = u'设备域名地区表'
+        verbose_name_plural = verbose_name
+
+
 class RequestRecordModel(models.Model):
 class RequestRecordModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增ID')
     method = models.CharField(max_length=10, default='', verbose_name='请求类型')
     method = models.CharField(max_length=10, default='', verbose_name='请求类型')
@@ -2144,16 +2272,17 @@ class AiService(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     uid = models.CharField(max_length=20, verbose_name='设备UID', db_index=True)
     uid = models.CharField(max_length=20, verbose_name='设备UID', db_index=True)
     channel = models.SmallIntegerField(default=0, verbose_name='通道')
     channel = models.SmallIntegerField(default=0, verbose_name='通道')
-    orders = models.ForeignKey(Order_Model, to_field='orderID', default='', on_delete=models.CASCADE, verbose_name='关联订单表')
-    detect_status = models.SmallIntegerField(default=0, verbose_name='状态[0:关闭,1:开启]')
+    orders = models.ForeignKey(Order_Model, to_field='orderID', default='', on_delete=models.CASCADE,
+                               verbose_name='关联订单表')
+    detect_status = models.SmallIntegerField(default=0, verbose_name='状态')  # 0:关闭, 1:开启
     endTime = models.BigIntegerField(verbose_name='套餐结束时间', db_index=True, default=0)
     endTime = models.BigIntegerField(verbose_name='套餐结束时间', db_index=True, default=0)
     addTime = models.IntegerField(verbose_name='添加时间', default=0)
     addTime = models.IntegerField(verbose_name='添加时间', default=0)
     updTime = models.BigIntegerField(verbose_name='更新时间', default=0)
     updTime = models.BigIntegerField(verbose_name='更新时间', default=0)
-    use_status = models.IntegerField(verbose_name='使用状态[0:未使用,1:使用中,2已过期]', default=0)
-    detect_group = models.CharField(blank=True, default='1', max_length=100, verbose_name='侦测类型[1=人;2=动物;3=车]')
+    use_status = models.IntegerField(verbose_name='使用状态', default=0)  # 0:未使用, 1:使用中, 2:已过期
+    # 1:人, 2:动物, 3:车, 4:包裹
+    detect_group = models.CharField(blank=True, default='1', max_length=100, verbose_name='侦测类型')
     detect_interval = models.IntegerField(verbose_name='推送间隔', default=60)  # 秒
     detect_interval = models.IntegerField(verbose_name='推送间隔', default=60)  # 秒
 
 
-
     class Meta:
     class Meta:
         db_table = 'ai_service'
         db_table = 'ai_service'
         verbose_name = 'ai设备服务表'
         verbose_name = 'ai设备服务表'
@@ -2263,6 +2392,7 @@ class CloudVodSurveysOperateLog(models.Model):
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
         ordering = ('id',)
         ordering = ('id',)
 
 
+
 class DeviceOTAUpgradeRecord(models.Model):
 class DeviceOTAUpgradeRecord(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     created_time = models.IntegerField(default=0, verbose_name='创建时间')
     created_time = models.IntegerField(default=0, verbose_name='创建时间')
@@ -2272,12 +2402,14 @@ class DeviceOTAUpgradeRecord(models.Model):
     serial_number = models.CharField(max_length=11, blank=True, verbose_name='序列号', default='')
     serial_number = models.CharField(max_length=11, blank=True, verbose_name='序列号', default='')
     uid = models.CharField(max_length=22, blank=True, verbose_name='设备UID', default='')
     uid = models.CharField(max_length=22, blank=True, verbose_name='设备UID', default='')
     mci = models.CharField(max_length=10, blank=True, verbose_name='设备大类:IPC/NVR/DVR', default='')
     mci = models.CharField(max_length=10, blank=True, verbose_name='设备大类:IPC/NVR/DVR', default='')
+
     class Meta:
     class Meta:
         db_table = 'device_OTA_upgrade_record'
         db_table = 'device_OTA_upgrade_record'
         verbose_name = '设备OTA升级记录'
         verbose_name = '设备OTA升级记录'
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
         ordering = ('id',)
         ordering = ('id',)
 
 
+
 class PaypalWebHookEvent(models.Model):
 class PaypalWebHookEvent(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
     webhook_event_id = models.CharField(max_length=200, blank=True, verbose_name='webhook事件ID', default='')
     webhook_event_id = models.CharField(max_length=200, blank=True, verbose_name='webhook事件ID', default='')
@@ -2298,4 +2430,272 @@ class PaypalWebHookEvent(models.Model):
         db_table = 'paypal_webhook_event'
         db_table = 'paypal_webhook_event'
         verbose_name = 'paypal钩子事件记录表'
         verbose_name = 'paypal钩子事件记录表'
         verbose_name_plural = verbose_name
         verbose_name_plural = verbose_name
-        ordering = ('id',)
+        ordering = ('id',)
+
+
+class PopupsConfig(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+
+    title = models.CharField(max_length=1000, verbose_name='弹窗标题', blank=True, default='')
+    content = models.CharField(max_length=1000, verbose_name='弹窗内容', blank=True, default='')
+    tag = models.SmallIntegerField(default=0, verbose_name='app跳转页面标签{1:云存储购 2:AI购买 3:优惠券}')
+    start_time = models.IntegerField(default=0, verbose_name='更新时间')
+    end_time = models.IntegerField(default=0, verbose_name='创建时间')
+    lang = models.CharField(blank=True, max_length=16, default='en', verbose_name=u'语言地区')
+
+    class Meta:
+        db_table = 'popups_config'
+        verbose_name = 'app弹窗设置'
+        verbose_name_plural = verbose_name
+        ordering = ('id',)
+
+
+class RedDotsConfig(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    module = models.CharField(max_length=1000, verbose_name='app模块', blank=True, default='')
+    start_time = models.IntegerField(default=0, verbose_name='更新时间')
+    end_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'red_dots_config'
+        verbose_name = '红点标记配置'
+        verbose_name_plural = verbose_name
+        ordering = ('id',)
+
+
+class UserFamily(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    user = models.ForeignKey(Device_User, to_field='userID', default='', on_delete=models.CASCADE,
+                             verbose_name='关联用户表ID')
+    name = models.CharField(max_length=50, db_index=True, verbose_name=u'家庭名称', default='', blank=True)
+    location = models.CharField(max_length=100, verbose_name='位置', blank=True, default='')
+    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序,越小越靠前')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'user_family'
+        verbose_name = '用户家庭'
+        verbose_name_plural = verbose_name
+
+
+class FamilyMemberPermission(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    no = models.CharField(max_length=10, unique=True, verbose_name='编号', default=0)
+    name = models.CharField(max_length=50, verbose_name=u'权限名称', default='')
+    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序,越小越靠前')
+    describe = models.CharField(max_length=128, blank=True, verbose_name='权限描述', default=0)
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'family_member_permission'
+        verbose_name = '家庭成员权限'
+        verbose_name_plural = verbose_name
+
+
+class FamilyMember(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    user = models.ForeignKey(Device_User, to_field='userID', default='', on_delete=models.CASCADE,
+                             verbose_name='关联用户表id')
+    user_name = models.CharField(max_length=64, db_index=True, verbose_name=u'用户名', default='', blank=True)
+    family = models.ForeignKey(UserFamily, to_field='id', default='', on_delete=models.CASCADE,
+                               verbose_name='关联用户家庭id')
+    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序,越小越靠前')
+    identity = models.SmallIntegerField(default=0, verbose_name='状态{0:普通成员,1:屋主}')
+    permission = models.ForeignKey(FamilyMemberPermission, to_field='id', default='', on_delete=models.CASCADE,
+                                   verbose_name='关联用户家庭id')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'family_member'
+        verbose_name = '家庭成员'
+        verbose_name_plural = verbose_name
+
+
+class FamilyRoom(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    name = models.CharField(max_length=128, verbose_name=u'房间名称', default='', blank=True)
+    family = models.ForeignKey(UserFamily, to_field='id', default='', on_delete=models.CASCADE,
+                               verbose_name='关联用户家庭id')
+    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序,越小越靠前')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'family_room'
+        verbose_name = '家庭房间'
+        verbose_name_plural = verbose_name
+
+
+class GatewaySubDevice(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    device = models.ForeignKey(Device_Info, to_field='id', default='', on_delete=models.CASCADE,
+                               verbose_name='关联设备信息id')
+    device_type = models.SmallIntegerField(default=0, verbose_name=u'设备类型')
+    nickname = models.CharField(default='', max_length=32, verbose_name=u'设备名称')
+    ieee_addr = models.CharField(default='', max_length=64, verbose_name=u'长地址')
+    src_addr = models.CharField(default='', max_length=16, verbose_name=u'短地址')
+    status = models.SmallIntegerField(default=0, verbose_name='状态')  # 0:关闭, 1:开启
+    is_tampered = models.SmallIntegerField(default=0, verbose_name='拆动状态')  # 0:正常, 1:被拆动
+    mac = models.CharField(default='', max_length=32, verbose_name=u'mac地址')
+    device_model = models.CharField(default='', max_length=16, verbose_name=u'设备型号')
+    manufacturer = models.CharField(default='', max_length=16, verbose_name=u'制造商')
+    sensor_serial = models.CharField(default='', max_length=32, verbose_name=u'传感器序列号')
+    firmware_version = models.CharField(default='', max_length=32, verbose_name=u'固件版本')
+    hardware_version = models.CharField(default='', max_length=32, verbose_name=u'硬件版本')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'gateway_sub_device'
+        verbose_name = '网关子设备'
+        verbose_name_plural = verbose_name
+
+
+class FamilyRoomDevice(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    room_id = models.IntegerField(default=0, blank=True, verbose_name=u'房间id')
+    family_id = models.IntegerField(default=0, blank=True, verbose_name=u'家庭id')
+    device = models.ForeignKey(Device_Info, to_field='id', default='', on_delete=models.CASCADE,
+                               verbose_name='关联设备信息id')
+    sub_device = models.IntegerField(default=0, blank=True, verbose_name='关联子设备信息id')
+    sort = models.IntegerField(default=0, blank=True, verbose_name=u'排序,越小越靠前')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'family_room_device'
+        verbose_name = '家庭房间关联设备'
+        verbose_name_plural = verbose_name
+
+
+class FamilyMemberJoin(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    user = models.ForeignKey(Device_User, to_field='userID', default='', on_delete=models.CASCADE,
+                             verbose_name='关联用户表id')
+    family = models.ForeignKey(UserFamily, to_field='id', default='', on_delete=models.CASCADE,
+                               verbose_name='关联用户家庭id')
+    status = models.SmallIntegerField(default=0, verbose_name='状态{0:未确认,1:拒绝,2:同意}')
+    # 0:家庭所有者搜索邀请,1:成员扫码加入
+    type = models.SmallIntegerField(default=0, verbose_name='类型')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'family_member_join'
+        verbose_name = '家庭成员加入'
+        verbose_name_plural = verbose_name
+
+
+class SensorRecord(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记ID')
+    gateway_sub_device_id = models.IntegerField(default=0, blank=True, verbose_name=u'网关子设备id')
+    alarm = models.CharField(default='', max_length=32, verbose_name=u'消息内容')
+    event_type = models.SmallIntegerField(default=0, verbose_name=u'消息类型')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'sensor_record'
+        verbose_name = '传感器记录'
+        verbose_name_plural = verbose_name
+        app_label = 'PushModel'
+
+
+class UnicomCombo(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    package_id = models.CharField(default='', max_length=32, verbose_name=u'联通套餐id')
+    combo_name = models.CharField(default='', max_length=32, verbose_name=u'套餐名称')
+    status = models.SmallIntegerField(default=0, verbose_name='状态{0:开启,1:停用}')
+    flow_total = models.IntegerField(default=0, blank=True, verbose_name=u'流量总量值 单位(MB)')
+    expiration_days = models.IntegerField(default=0, blank=True, verbose_name=u'有效期天数')
+    expiration_type = models.SmallIntegerField(default=0, verbose_name=u'有效期类型,0=天,1=月,2=年')
+    pay_type = models.ManyToManyField(to='Pay_Type', verbose_name='付款类型', db_table='unicom_combo_pay_type')
+    price = models.CharField(blank=True, max_length=32, verbose_name=u'价格')
+    sort = models.IntegerField(default=0, blank=True, verbose_name=u'排序,越小越靠前')
+    remark = models.TextField(blank=True, default='', verbose_name=u'描述信息')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    is_show = models.SmallIntegerField(default=1, verbose_name=u'是否显示,0:不显示,1:显示')
+    is_del = models.BooleanField(blank=True, default=False, verbose_name=u'是否删除默认false')
+
+    class Meta:
+        db_table = 'unicom_combo'
+        verbose_name = '联通套餐表'
+        verbose_name_plural = verbose_name
+
+
+class UnicomComboOrderInfo(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    renew_list_id = models.CharField(default='', max_length=32, verbose_name=u'联通订购成功套餐队列id')
+    status = models.SmallIntegerField(default=0, verbose_name='状态{0:未使用,1:已使用,2:已过期}')
+    orders = models.ForeignKey(Order_Model, to_field='orderID', default='', on_delete=models.CASCADE,
+                               verbose_name='关联订单表')
+    combo = models.ForeignKey(UnicomCombo, to_field='id', default='', on_delete=models.CASCADE,
+                              verbose_name=u'联通套餐表')
+    activation_time = models.IntegerField(default=0, verbose_name='激活时间')
+    expire_time = models.IntegerField(default=0, verbose_name='过期时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    is_del = models.BooleanField(blank=True, default=False, verbose_name=u'是否删除')
+
+    class Meta:
+        db_table = 'unicom_combo_order_info'
+        verbose_name = '联通套餐订单信息表'
+        verbose_name_plural = verbose_name
+
+
+class UnicomDeviceInfo(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    serial_no = models.CharField(default='', max_length=32, verbose_name=u'设备序列号')
+    user_id = models.CharField(blank=True, max_length=32, verbose_name=u'用户id')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'unicom_device_info'
+        verbose_name = '联通设备信息'
+        verbose_name_plural = verbose_name
+
+
+class UnicomDeviceQueueMonitoringPush(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    serial_no = models.CharField(default='', max_length=32, verbose_name=u'序列号')
+    sign = models.CharField(default='', max_length=32, verbose_name=u'验证签名')
+    time = models.CharField(default='', max_length=32, verbose_name=u'推送时间(yyyymmddhhmiss)')
+    type = models.CharField(default='', max_length=32, verbose_name=u'推送类型:DEVICE_QUEUE_MONITORING:设队列监控;')
+    current_renew_list_id = models.CharField(default='', max_length=32, verbose_name=u'队列ID')
+    no_queue_available = models.SmallIntegerField(default=0, verbose_name=u'是否无可用队列;1:是;0:否')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'unicom_device_queue_monitoring_push'
+        verbose_name = '联通设备队列监控推送表'
+        verbose_name_plural = verbose_name
+
+
+class UnicomDeviceStatusChangePush(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
+    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    serial_no = models.CharField(default='', max_length=32, verbose_name=u'序列号')
+    sign = models.CharField(default='', max_length=32, verbose_name=u'验证签名')
+    time = models.CharField(default='', max_length=32, verbose_name=u'推送时间(yyyymmddhhmiss)')
+    # 变更类型: DEVICE_REAL_NAME_STATUS_CHANGE:实名状态变更;DEVICE_STATUS_CHANGE:设备状态变更;
+    type = models.CharField(default='', max_length=32, verbose_name=u'变更类型')
+    # 之前值:设备状态变更 1: 已激活;2: 可激活;3: 已停用;4: 已失效;5: 可测试;6: 库存;7: 已更换;8: 已清除;
+    previous_val = models.CharField(default='', max_length=32, verbose_name=u'之前值:')
+    # 当前值:设备状态变更 1:已激活;2:可激活;3:已停用;4:已失效;5:可测试;6:库存;7:已更换;8:已清除;
+    current_val = models.CharField(default='', max_length=32, verbose_name=u'当前值:')
+    reason = models.SmallIntegerField(default=0, verbose_name=u'变更原因编码:请查看【信息提示码】')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'unicom_device_status_change_push'
+        verbose_name = '联通设备状态变更推送表'
+        verbose_name_plural = verbose_name

+ 8 - 16
Object/IOTCore/IotObject.py

@@ -19,23 +19,15 @@ class IOTClient:
                                        aws_secret_access_key=AWS_IOT_SES_ACCESS_CHINA_SECRET)
                                        aws_secret_access_key=AWS_IOT_SES_ACCESS_CHINA_SECRET)
             # 终端节点: https://cn-northwest-1.console.amazonaws.cn/iot/home?region=cn-northwest-1#/settings
             # 终端节点: https://cn-northwest-1.console.amazonaws.cn/iot/home?region=cn-northwest-1#/settings
             self.endpoint = 'a250bbr0p9u7as-ats.iot.cn-northwest-1.amazonaws.com.cn'
             self.endpoint = 'a250bbr0p9u7as-ats.iot.cn-northwest-1.amazonaws.com.cn'
-            self.iotrole = AWS_IOT_SES_ACCESS_CHINA_ROLE
+            self.iot_role = AWS_IOT_SES_ACCESS_CHINA_ROLE
 
 
-        elif region_id == 2:
-            # 亚太新加坡
-            self.client = boto3.client('iot', region_name=AWS_IOT_SES_ACCESS_FOREIGN_REGION_ASIA,
-                                       aws_access_key_id=AWS_IOT_SES_ACCESS_FOREIGN_ID,
-                                       aws_secret_access_key=AWS_IOT_SES_ACCESS_FOREIGN_SECRET)
-            self.endpoint = 'a2rqy12o004ad8-ats.iot.ap-southeast-1.amazonaws.com'
-            self.iotrole = AWS_IOT_SES_ACCESS_FOREIGN_ROLE
-
-        elif region_id == 3:
+        elif region_id == 2 or region_id == 3:
             # 美东弗吉尼亚
             # 美东弗吉尼亚
             self.client = boto3.client('iot', region_name=AWS_IOT_SES_ACCESS_FOREIGN_REGION_AMERICA,
             self.client = boto3.client('iot', region_name=AWS_IOT_SES_ACCESS_FOREIGN_REGION_AMERICA,
                                        aws_access_key_id=AWS_IOT_SES_ACCESS_FOREIGN_ID,
                                        aws_access_key_id=AWS_IOT_SES_ACCESS_FOREIGN_ID,
                                        aws_secret_access_key=AWS_IOT_SES_ACCESS_FOREIGN_SECRET)
                                        aws_secret_access_key=AWS_IOT_SES_ACCESS_FOREIGN_SECRET)
             self.endpoint = 'a2rqy12o004ad8-ats.iot.us-east-1.amazonaws.com'
             self.endpoint = 'a2rqy12o004ad8-ats.iot.us-east-1.amazonaws.com'
-            self.iotrole = AWS_IOT_SES_ACCESS_FOREIGN_ROLE
+            self.iot_role = AWS_IOT_SES_ACCESS_FOREIGN_ROLE
 
 
         elif region_id == 4:
         elif region_id == 4:
             # 西欧爱尔兰
             # 西欧爱尔兰
@@ -43,7 +35,7 @@ class IOTClient:
                                        aws_access_key_id=AWS_IOT_SES_ACCESS_FOREIGN_ID,
                                        aws_access_key_id=AWS_IOT_SES_ACCESS_FOREIGN_ID,
                                        aws_secret_access_key=AWS_IOT_SES_ACCESS_FOREIGN_SECRET)
                                        aws_secret_access_key=AWS_IOT_SES_ACCESS_FOREIGN_SECRET)
             self.endpoint = 'a2rqy12o004ad8-ats.iot.eu-west-1.amazonaws.com'
             self.endpoint = 'a2rqy12o004ad8-ats.iot.eu-west-1.amazonaws.com'
-            self.iotrole = AWS_IOT_SES_ACCESS_FOREIGN_ROLE
+            self.iot_role = AWS_IOT_SES_ACCESS_FOREIGN_ROLE
 
 
     def create_provisioning_claim(self, templateName):
     def create_provisioning_claim(self, templateName):
 
 
@@ -145,17 +137,17 @@ class IOTClient:
                 templateBody=templateBody,
                 templateBody=templateBody,
                 parameters=parameters
                 parameters=parameters
             )
             )
-            topicsql = "SELECT * FROM 'my/things/" + ThingName + "/shadow/update_lwt'"
+            topic_sql = "SELECT * FROM 'my/things/{}/shadow/update_lwt'".format(ThingName)
             self.client.create_topic_rule(
             self.client.create_topic_rule(
-                ruleName= ThingName + '_LWT',
+                ruleName=ThingName + '_LWT',
                 topicRulePayload={
                 topicRulePayload={
-                    "sql": topicsql,
+                    "sql": topic_sql,
                     "ruleDisabled": False,
                     "ruleDisabled": False,
                     "awsIotSqlVersion": "2016-03-23",
                     "awsIotSqlVersion": "2016-03-23",
                     'actions': [
                     'actions': [
                         {
                         {
                             'republish': {
                             'republish': {
-                                'roleArn': self.iotrole,
+                                'roleArn': self.iot_role,
                                 'topic': '$$aws/things/' + ThingName + '/shadow/update',
                                 'topic': '$$aws/things/' + ThingName + '/shadow/update',
                                 'qos': 1
                                 'qos': 1
                             }
                             }

+ 3 - 1
Object/ResponseObject.py

@@ -113,6 +113,7 @@ class ResponseObject(object):
             10054: 'The AI service has expired',
             10054: 'The AI service has expired',
             10055: 'The AI does not recognize any labels',
             10055: 'The AI does not recognize any labels',
             10056: 'The device has enabled automatic renewal of cloud storage package and cannot be transferred for the time being',
             10056: 'The device has enabled automatic renewal of cloud storage package and cannot be transferred for the time being',
+            10057: "Can't delete",
         }
         }
         data_cn = {
         data_cn = {
             0: '成功',
             0: '成功',
@@ -219,6 +220,7 @@ class ResponseObject(object):
             10054: 'AI服务已过期',
             10054: 'AI服务已过期',
             10055: 'AI没有识别到任何标签',
             10055: 'AI没有识别到任何标签',
             10056: '该设备已开通云存套餐自动续费,暂时无法转移',
             10056: '该设备已开通云存套餐自动续费,暂时无法转移',
+            10057: '不能删除',
         }
         }
         if self.lang == 'cn':
         if self.lang == 'cn':
             msg = data_cn
             msg = data_cn
@@ -234,7 +236,7 @@ class ResponseObject(object):
             message = '系统错误,code不存在'
             message = '系统错误,code不存在'
         print(self.lang == 'cn')
         print(self.lang == 'cn')
         print(msg)
         print(msg)
-        if self.returntype=='pc':
+        if self.returntype == 'pc':
             return {'code': code, 'msg': message, 'data': res, 'error_code': code}
             return {'code': code, 'msg': message, 'data': res, 'error_code': code}
         return {'result_code': code, 'reason': message, 'result': res, 'error_code': code}
         return {'result_code': code, 'reason': message, 'result': res, 'error_code': code}
 
 

+ 256 - 0
Object/UnicomObject.py

@@ -0,0 +1,256 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : UnicomObject.py
+@Time    : 2022/6/17 11:03
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import base64
+import json
+
+import requests
+from Crypto.Cipher import AES
+from decimal import Decimal
+from Object.utils import SM3Util
+
+from Ansjer.config import unicomAppUrl, unicomAppId, unicomAppSecret, unicomTenantId, \
+    unicomEncodeKey, unicomIvKey, unicomUserName, unicomPassword, unicomPushKey
+from Object.utils.SymmetricCryptoUtil import AESencrypt
+
+"""
+联通4Gapi
+具体参数查看接口文档
+https://www.showdoc.com.cn/unicomJYHapi/8158648460007467
+"""
+
+
+class UnicomObjeect:
+    def __init__(self):
+        self.appUrl = unicomAppUrl
+        self.appId = unicomAppId
+        self.appSecret = unicomAppSecret
+        self.tenantId = unicomTenantId
+        self.encodeKey = unicomEncodeKey
+        self.ivKey = unicomIvKey
+        self.username = unicomUserName
+        self.password = unicomPassword
+        self.pushKey = unicomPushKey
+        self.headers = {'Tenant': self.tenantId, 'content-type': 'application/x-www-form-urlencoded'}
+
+    # pip install snowland-smx
+    def createSign(self, reverse=False, **sign_params):
+        """
+        调用接口(API)时需要对请求参数进行签名(sign)验证,
+        算法:
+        根据参数名称将你的所有请求参数按照字母先后顺序排序: key = value & key = value,对除签名外的所有请求参数按
+        key
+        做的升序排列。
+        如:将
+        foo = 1, bar = 2, baz = 3
+        排序为
+        bar = 2, baz = 3, foo = 1
+        参数名和参数值链接后,得到拼装字符串(注意:参数名与参数值左右两边不能包含空格)
+        bar = 2 & baz = 3 & foo = 1
+        将
+        pushkey拼接到参数字符尾部进行
+        SM3
+        加密,再转化成大写,格式是
+        (SM3(key1=value1 & key2=value2 &...& key= pushKey)).upcase
+        @param reverse:
+        @param sign_params:
+        @return:
+        """
+        dict_2 = dict(sorted(sign_params.items(), key=lambda item: item[0], reverse=reverse))
+        data_list = []
+        for item in dict_2.items():
+            if item[0] and item[1]:
+                data_list.append("{}={}".format(item[0], item[1]))
+        val = '&'.join(data_list)
+        push_key = '&key={}'.format(self.pushKey)
+        val = val + push_key
+        return SM3Util.Hash_sm3(val).upper()
+
+    def get_login_authorization(self):
+        """
+        获取登录授权
+        注意登录认证Authorization和登录后的请求认证不一样
+        算法:appId+":"+appSecret base64转码生成 前面加Basic
+        @return: "Basic " + base64_data
+        """
+        voucher = self.appId + ':' + self.appSecret
+        base64_data = str(base64.b64encode(voucher.encode("utf-8")), "utf-8")
+        return "Basic " + base64_data
+
+    def get_encode_password(self):
+        """
+        获取对称加密
+        @return: encrypt_pwd
+        """
+        aes = AESencrypt(self.encodeKey.encode('utf-8'), AES.MODE_CBC, self.ivKey.encode('utf-8'),
+                         paddingMode="ZeroPadding",
+                         characterSet='utf-8')
+        encrypt_pwd = aes.encryptFromString(self.password)
+        return encrypt_pwd
+
+    def generate_token(self):
+        """
+        生成令牌
+        @return: token
+        """
+        url = self.appUrl + '/auc/oauth/token'
+        pwd = self.get_encode_password()
+        body = {'username': self.username, 'password': pwd, 'grant_type': 'password', 'scope': 'server'}
+        headers = self.headers
+        headers['Authorization'] = self.get_login_authorization()
+        response_data = requests.post(url, data=body, headers=headers)
+        response_data = json.loads(response_data.text)
+        return response_data['access_token']
+
+    def refresh_token(self, refresh_token):
+        """
+        刷新令牌
+        @param refresh_token:
+        @return:
+        """
+        url = self.appUrl + '/auc/oauth/token?grant_type=refresh_token'
+        body = {'refresh_token': refresh_token, 'grant_type': 'refresh_token'}
+        headers = self.headers
+        headers['Authorization'] = self.get_login_authorization()
+        response_data = requests.post(url, data=body, headers=headers)
+        return response_data.text
+
+    def business_unify_headers(self):
+        """
+        业务统一headers
+        在请求头中增加key为Authorization,value为"Bearer " + token
+        @return: headers
+        """
+        token = self.generate_token()
+        headers = self.headers
+        headers['Authorization'] = 'Bearer ' + token
+        return headers
+
+    # 业务api  注意 get与post 请求数据类型不同 post使用:application/json
+    def verify_device(self, **re_params):
+        """
+        验证设备
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/device/verify-device'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def query_device_status(self, **re_params):
+        """
+        查询设备状态
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/device/device-status'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def update_device_state(self, **re_data):
+        """
+        修改设备状态
+        @param re_data:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/device/device-state'
+        headers = self.business_unify_headers()
+        headers['content-type'] = 'application/json'
+        return requests.post(url, data=json.dumps(re_data), headers=headers)
+
+    def query_device_usage_history(self, **re_params):
+        """
+        查询设备用量历史
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/usage/device-usage-history'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def query_current_renew_list_usage_details(self, **re_params):
+        """
+        查询设备当前队列用量详情
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/usage/current-renewlist-usage-details'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def get_device_batch_detail(self, **re_data):
+        """
+        查询设备当前队列用量详情
+        @return:
+        """
+        url = self.appUrl + '/platform/api/device/batch-detail'
+        headers = self.business_unify_headers()
+        headers['content-type'] = 'application/json'
+        return requests.post(url, data=json.dumps(re_data), headers=headers)
+
+    def query_package_list(self, **re_params):
+        """
+        查询套餐列表
+        @return:
+        """
+        url = self.appUrl + '/platform/api/package/list'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def query_renewal_list(self, **re_params):
+        """
+        续费套餐列表
+        @param re_params:
+        @return:
+        """
+        url = self.appUrl + '/platform/api/package/list'
+        return requests.get(url, params=re_params, headers=self.business_unify_headers())
+
+    def async_buy_package(self, **re_data):
+        """
+        查询设备当前队列用量详情
+        @return:
+        """
+        url = self.appUrl + '/platform/api/package/async-buy-package'
+        headers = self.business_unify_headers()
+        headers['content-type'] = 'application/json'
+        return requests.post(url, data=json.dumps(re_data), headers=headers)
+
+
+if __name__ == '__main__':
+    price = '12.13'
+    print(float(price))
+    discount = '6'
+    dd = Decimal(price) - Decimal(discount)
+    print(dd.quantize(Decimal('0.00')))
+
+    unicom_api = UnicomObjeect()
+    data = {'foo': 1, 'bar': 2, 'baz': 3}
+    print(unicom_api.createSign(**data))
+    # result = unicom_api.generate_token()
+    # result = unicom_api.refresh_token('5d0c0f30-99bd-4f17-9614-3524495b05d4')
+    params = {'iccid': '89860620170009628001'}
+    response = unicom_api.verify_device(**params)
+    # response = unicom_api.query_device_status(**params)
+    # response = unicom_api.update_device_state(**params)
+    # response = unicom_api.query_device_usage_history(**params)
+    # response = unicom_api.query_current_renew_list_usage_details(**params)
+    # unicom_api.get_device_batch_detail()
+    # response = unicom_api.query_package_list(**params)
+    # response = unicom_api.query_renewal_list(**params)
+
+    if response.status_code == 200:
+        res_dict = json.loads(response.text)
+        print(res_dict)
+    response_json = {
+        "success": True,
+        "msg": "操作成功",
+        "code": 0,
+        "data": {
+            "iccid": "8986062018007784202",
+            "completeIccid": "89860620180077842020",
+            "status": 1
+        }
+    }
+    print(response_json['data']['iccid'])
+    print(response.status_code)

+ 237 - 0
Object/utils/SM3Util.py

@@ -0,0 +1,237 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : SM3Util.py
+@Time    : 2022/6/28 8:34
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+# -*- encoding: utf-8 -*-
+"""
+@File    : SM32.py
+@Time    : 2022/6/28 9:49
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+from math import ceil
+
+IV = "7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e"
+IV = int(IV.replace(" ", ""), 16)
+a = []
+for i in range(0, 8):
+    a.append(0)
+    a[i] = (IV >> ((7 - i) * 32)) & 0xFFFFFFFF
+IV = a
+
+
+def out_hex(list1):
+    for i in list1:
+        print("%08x" % i)
+    print("\n")
+
+
+def rotate_left(a, k):
+    k = k % 32
+    return ((a << k) & 0xFFFFFFFF) | ((a & 0xFFFFFFFF) >> (32 - k))
+
+
+T_j = []
+for i in range(0, 16):
+    T_j.append(0)
+    T_j[i] = 0x79cc4519
+for i in range(16, 64):
+    T_j.append(0)
+    T_j[i] = 0x7a879d8a
+
+
+def FF_j(X, Y, Z, j):
+    if 0 <= j < 16:
+        ret = X ^ Y ^ Z
+    elif 16 <= j < 64:
+        ret = (X & Y) | (X & Z) | (Y & Z)
+    return ret
+
+
+def GG_j(X, Y, Z, j):
+    if 0 <= j < 16:
+        ret = X ^ Y ^ Z
+    elif 16 <= j < 64:
+        # ret = (X | Y) & ((2 ** 32 - 1 - X) | Z)
+        ret = (X & Y) | ((~ X) & Z)
+    return ret
+
+
+def P_0(X):
+    return X ^ (rotate_left(X, 9)) ^ (rotate_left(X, 17))
+
+
+def P_1(X):
+    return X ^ (rotate_left(X, 15)) ^ (rotate_left(X, 23))
+
+
+def CF(V_i, B_i):
+    W = []
+    for i in range(16):
+        weight = 0x1000000
+        data = 0
+        for k in range(i * 4, (i + 1) * 4):
+            data = data + B_i[k] * weight
+            weight = int(weight / 0x100)
+        W.append(data)
+
+    for j in range(16, 68):
+        W.append(0)
+        W[j] = P_1(W[j - 16] ^ W[j - 9] ^ (rotate_left(W[j - 3], 15))) ^ (rotate_left(W[j - 13], 7)) ^ W[j - 6]
+        str1 = "%08x" % W[j]
+    W_1 = []
+    for j in range(0, 64):
+        W_1.append(0)
+        W_1[j] = W[j] ^ W[j + 4]
+        str1 = "%08x" % W_1[j]
+
+    A, B, C, D, E, F, G, H = V_i
+    """
+    print "00",
+    out_hex([A, B, C, D, E, F, G, H])
+    """
+    for j in range(0, 64):
+        SS1 = rotate_left(((rotate_left(A, 12)) + E + (rotate_left(T_j[j], j))) & 0xFFFFFFFF, 7)
+        SS2 = SS1 ^ (rotate_left(A, 12))
+        TT1 = (FF_j(A, B, C, j) + D + SS2 + W_1[j]) & 0xFFFFFFFF
+        TT2 = (GG_j(E, F, G, j) + H + SS1 + W[j]) & 0xFFFFFFFF
+        D = C
+        C = rotate_left(B, 9)
+        B = A
+        A = TT1
+        H = G
+        G = rotate_left(F, 19)
+        F = E
+        E = P_0(TT2)
+
+        A = A & 0xFFFFFFFF
+        B = B & 0xFFFFFFFF
+        C = C & 0xFFFFFFFF
+        D = D & 0xFFFFFFFF
+        E = E & 0xFFFFFFFF
+        F = F & 0xFFFFFFFF
+        G = G & 0xFFFFFFFF
+        H = H & 0xFFFFFFFF
+        """
+        str1 = "%02d" % j
+        if str1[0] == "0":
+            str1 = ' ' + str1[1:]
+        print str1,
+        out_hex([A, B, C, D, E, F, G, H])
+        """
+
+    V_i_1 = [A ^ V_i[0], B ^ V_i[1], C ^ V_i[2], D ^ V_i[3], E ^ V_i[4], F ^ V_i[5], G ^ V_i[6], H ^ V_i[7]]
+    return V_i_1
+
+
+def hash_msg(msg):
+    # print(msg)
+    len1 = len(msg)
+    reserve1 = len1 % 64
+    msg.append(0x80)
+    reserve1 = reserve1 + 1
+    # 56-64, add 64 byte
+    range_end = 56
+    if reserve1 > range_end:
+        range_end = range_end + 64
+
+    for i in range(reserve1, range_end):
+        msg.append(0x00)
+
+    bit_length = len1 * 8
+    bit_length_str = [bit_length % 0x100]
+    for i in range(7):
+        bit_length = int(bit_length / 0x100)
+        bit_length_str.append(bit_length % 0x100)
+    for i in range(8):
+        msg.append(bit_length_str[7 - i])
+
+    # print(msg)
+
+    group_count = round(len(msg) / 64)
+
+    B = []
+    for i in range(0, group_count):
+        B.append(msg[i * 64:(i + 1) * 64])
+
+    V = [IV]
+    for i in range(0, group_count):
+        V.append(CF(V[i], B[i]))
+
+    y = V[i + 1]
+    result = ""
+    for i in y:
+        result = '%s%08x' % (result, i)
+    return result
+
+
+def str2byte(msg):  # 字符串转换成byte数组
+    ml = len(msg)
+    msg_byte = []
+    msg_bytearray = msg.encode('utf-8')
+    for i in range(ml):
+        msg_byte.append(msg_bytearray[i])
+    return msg_byte
+
+
+def byte2str(msg):  # byte数组转字符串
+    ml = len(msg)
+    str1 = b""
+    for i in range(ml):
+        str1 += b'%c' % msg[i]
+    return str1.decode('utf-8')
+
+
+def hex2byte(msg):  # 16进制字符串转换成byte数组
+    ml = len(msg)
+    if ml % 2 != 0:
+        msg = '0' + msg
+    ml = int(len(msg) / 2)
+    msg_byte = []
+    for i in range(ml):
+        msg_byte.append(int(msg[i * 2:i * 2 + 2], 16))
+    return msg_byte
+
+
+def byte2hex(msg):  # byte数组转换成16进制字符串
+    ml = len(msg)
+    hexstr = ""
+    for i in range(ml):
+        hexstr = hexstr + ('%02x' % msg[i])
+    return hexstr
+
+
+def Hash_sm3(msg, Hexstr=0):
+    if Hexstr:
+        msg_byte = hex2byte(msg)
+    else:
+        msg_byte = str2byte(msg)
+    return hash_msg(msg_byte)
+
+
+def KDF(Z, klen):  # Z为16进制表示的比特串(str),klen为密钥长度(单位byte)
+    klen = int(klen)
+    ct = 0x00000001
+    rcnt = ceil(klen / 32)
+    Zin = hex2byte(Z)
+    Ha = ""
+    for i in range(rcnt):
+        msg = Zin + hex2byte('%08x' % ct)
+        # print(msg)
+        Ha = Ha + hash_msg(msg)
+        # print(Ha)
+        ct += 1
+    return Ha[0: klen * 2]
+
+
+if __name__ == '__main__':
+    y = Hash_sm3('aee694b9e5908ee9878de590afe7949f010000003d2e8b123c2e8b1211180000be3e', 1)
+    print(y)
+
+    # klen = 19
+    # print(KDF("57E7B63623FAE5F08CDA468E872A20AFA03DED41BF1403770E040DC83AF31A67991F2B01EBF9EFD8881F0A0493000603", klen))

+ 216 - 0
Object/utils/SymmetricCryptoUtil.py

@@ -0,0 +1,216 @@
+from Crypto.Cipher import AES
+import base64
+import binascii
+
+
+# 数据类
+class MData:
+    def __init__(self, data=b"", characterSet='utf-8'):
+        # data肯定为bytes
+        self.data = data
+        self.characterSet = characterSet
+
+    def saveData(self, FileName):
+        with open(FileName, 'wb') as f:
+            f.write(self.data)
+
+    def fromString(self, data):
+        self.data = data.encode(self.characterSet)
+        return self.data
+
+    def fromBase64(self, data):
+        self.data = base64.b64decode(data.encode(self.characterSet))
+        return self.data
+
+    def fromHexStr(self, data):
+        self.data = binascii.a2b_hex(data)
+        return self.data
+
+    def toString(self):
+        return self.data.decode(self.characterSet)
+
+    def toBase64(self):
+        return base64.b64encode(self.data).decode()
+
+    def toHexStr(self):
+        return binascii.b2a_hex(self.data).decode()
+
+    def toBytes(self):
+        return self.data
+
+    def __str__(self):
+        try:
+            return self.toString()
+        except Exception:
+            return self.toBase64()
+
+
+"""
+封装类
+"""
+
+
+class AESencrypt:
+    def __init__(self, encode_key, mode, iv_key=b'', paddingMode="NoPadding", characterSet="utf-8"):
+        """
+        构建一个AES对象
+        key: 秘钥,字节型数据
+        mode: 使用模式,只提供两种,AES.MODE_CBC, AES.MODE_ECB
+        iv: iv偏移量,字节型数据
+        paddingMode: 填充模式,默认为NoPadding, 可选NoPadding,ZeroPadding,PKCS5Padding,PKCS7Padding
+        characterSet: 字符集编码
+        """
+        self.key = encode_key
+        self.mode = mode
+        self.iv = iv_key
+        self.characterSet = characterSet
+        self.paddingMode = paddingMode
+        self.data = ""
+
+    @classmethod
+    def __zero_padding(cls, data):
+        data += b'\x00'
+        while len(data) % 16 != 0:
+            data += b'\x00'
+        return data
+
+    @classmethod
+    def __strip_zero_padding(cls, data):
+        data = data[:-1]
+        while len(data) % 16 != 0:
+            data = data.rstrip(b'\x00')
+            if data[-1] != b"\x00":
+                break
+        return data
+
+    def __PKCS5_7Padding(self, data):
+        needSize = 16 - len(data) % 16
+        if needSize == 0:
+            needSize = 16
+        return data + needSize.to_bytes(1, 'little') * needSize
+
+    def __StripPKCS5_7Padding(self, data):
+        paddingSize = data[-1]
+        return data.rstrip(paddingSize.to_bytes(1, 'little'))
+
+    def __paddingData(self, data):
+        if self.paddingMode == "NoPadding":
+            if len(data) % 16 == 0:
+                return data
+            else:
+                return self.__zero_padding(data)
+        elif self.paddingMode == "ZeroPadding":
+            return self.__zero_padding(data)
+        elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding":
+            return self.__PKCS5_7Padding(data)
+        else:
+            print("不支持Padding")
+
+    def __stripPaddingData(self, data):
+        if self.paddingMode == "NoPadding":
+            return self.__strip_zero_padding(data)
+        elif self.paddingMode == "ZeroPadding":
+            return self.__strip_zero_padding(data)
+
+        elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding":
+            return self.__StripPKCS5_7Padding(data)
+        else:
+            print("不支持Padding")
+
+    def setCharacterSet(self, characterSet):
+        """
+        设置字符集编码
+        characterSet: 字符集编码
+        """
+        self.characterSet = characterSet
+
+    def setPaddingMode(self, mode):
+        """
+        设置填充模式
+        mode: 可选NoPadding,ZeroPadding,PKCS5Padding,PKCS7Padding
+        """
+        self.paddingMode = mode
+
+    def decryptFromBase64(self, entext):
+        """
+        从base64编码字符串编码进行AES解密
+        entext: 数据类型str
+        """
+        mData = MData(characterSet=self.characterSet)
+        self.data = mData.fromBase64(entext)
+        return self.__decrypt()
+
+    def decryptFromHexStr(self, entext):
+        """
+        从hexstr编码字符串编码进行AES解密
+        entext: 数据类型str
+        """
+        mData = MData(characterSet=self.characterSet)
+        self.data = mData.fromHexStr(entext)
+        return self.__decrypt()
+
+    def decryptFromString(self, entext):
+        """
+        从字符串进行AES解密
+        entext: 数据类型str
+        """
+        mData = MData(characterSet=self.characterSet)
+        self.data = mData.fromString(entext)
+        return self.__decrypt()
+
+    def decryptFromBytes(self, entext):
+        """
+        从二进制进行AES解密
+        entext: 数据类型bytes
+        """
+        self.data = entext
+        return self.__decrypt()
+
+    def encryptFromString(self, data):
+        """
+        对字符串进行AES加密
+        data: 待加密字符串,数据类型为str
+        """
+        self.data = data.encode(self.characterSet)
+        return self.__encrypt()
+
+    def __encrypt(self):
+        """
+        加密数据
+        @return:
+        """
+        if self.mode == AES.MODE_CBC:
+            aes = AES.new(self.key, self.mode, self.iv)
+        elif self.mode == AES.MODE_ECB:
+            aes = AES.new(self.key, self.mode)
+        else:
+            print("不支持这种模式")
+            return
+
+        data = self.__paddingData(self.data)
+        enData = aes.encrypt(data)
+        return MData(enData)
+
+    def __decrypt(self):
+        if self.mode == AES.MODE_CBC:
+            aes = AES.new(self.key, self.mode, self.iv)
+        elif self.mode == AES.MODE_ECB:
+            aes = AES.new(self.key, self.mode)
+        else:
+            print("不支持这种模式")
+            return
+        data = aes.decrypt(self.data)
+        mData = MData(self.__stripPaddingData(data), characterSet=self.characterSet)
+        return mData
+
+
+if __name__ == '__main__':
+    key = b"1234567812345678"
+    iv = b"0000000000000000"
+    aes = AESencrypt(key, AES.MODE_CBC, iv, paddingMode="ZeroPadding", characterSet='utf-8')
+
+    str_data = "dddd321123."
+    rData = aes.encryptFromString(str_data)
+    print("加密:", rData.toBase64())
+    rData = aes.decryptFromBase64(rData.toBase64())
+    print("解密:", rData)

+ 66 - 22
Service/CommonService.py

@@ -3,27 +3,29 @@
 import base64
 import base64
 import datetime
 import datetime
 import time
 import time
+from base64 import encodebytes
 from pathlib import Path
 from pathlib import Path
 from random import Random
 from random import Random
+
+import OpenSSL.crypto as ct
 import ipdb
 import ipdb
 import requests
 import requests
 import simplejson as json
 import simplejson as json
 from django.core import serializers
 from django.core import serializers
-from django.http import HttpResponseRedirect
 from django.utils import timezone
 from django.utils import timezone
 from pyipip import IPIPDatabase
 from pyipip import IPIPDatabase
-from Ansjer.config import BASE_DIR, UNICODE_ASCII_CHARACTER_SET, SERVER_DOMAIN_SSL
-import OpenSSL.crypto as ct
-from base64 import encodebytes
+
+from Ansjer.config import BASE_DIR, SERVER_DOMAIN_SSL, CONFIG_INFO, CONFIG_TEST, CONFIG_CN
 from Controller.CheckUserData import RandomStr
 from Controller.CheckUserData import RandomStr
-from Model.models import iotdeviceInfoModel, Device_Info
-from Service.ModelService import ModelService
+from Model.models import iotdeviceInfoModel, Device_Info, CountryModel, RegionModel, UIDModel
 
 
 
 
 class CommonService:
 class CommonService:
     # 添加模糊搜索
     # 添加模糊搜索
     @staticmethod
     @staticmethod
-    def get_kwargs(data={}):
+    def get_kwargs(data=None):
+        if data is None:
+            data = {}
         kwargs = {}
         kwargs = {}
         for (k, v) in data.items():
         for (k, v) in data.items():
             if v is not None and v != u'':
             if v is not None and v != u'':
@@ -46,7 +48,7 @@ class CommonService:
         key_list = []
         key_list = []
         value_list = []
         value_list = []
         for k, v in request_dict.items():
         for k, v in request_dict.items():
-            key_list.append(k[k.index('[')+1:k.index(']')] if 'meta' in k else k)
+            key_list.append(k[k.index('[') + 1:k.index(']')] if 'meta' in k else k)
             if v == 'true':
             if v == 'true':
                 v = True
                 v = True
             elif v == 'false':
             elif v == 'false':
@@ -72,8 +74,10 @@ class CommonService:
         return mb_size
         return mb_size
 
 
     @staticmethod
     @staticmethod
-    def get_param_flag(data=[]):
+    def get_param_flag(data=None):
         # print(data)
         # print(data)
+        if data is None:
+            data = []
         flag = True
         flag = True
         for v in data:
         for v in data:
             if v is None:
             if v is None:
@@ -286,17 +290,17 @@ class CommonService:
             return ''
             return ''
         for i in range(start, end):
         for i in range(start, end):
             if i == 1:
             if i == 1:
-                content = RandomStr(3, False)+content+RandomStr(3, False)
+                content = RandomStr(3, False) + content + RandomStr(3, False)
                 content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
                 content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
             if i == 2:
             if i == 2:
-                content = RandomStr(2, False)+str(content)+RandomStr(2, False)
+                content = RandomStr(2, False) + str(content) + RandomStr(2, False)
                 content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
                 content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
             if i == 3:
             if i == 3:
-                content = RandomStr(1, False)+str(content)+RandomStr(1, False)
+                content = RandomStr(1, False) + str(content) + RandomStr(1, False)
                 content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
                 content = base64.b64encode(str(content).encode("utf-8")).decode('utf8')
         return content
         return content
 
 
-    #把格式化时间转换成时间戳
+    # 把格式化时间转换成时间戳
     @staticmethod
     @staticmethod
     def str_to_timestamp(str_time=None, format='%Y-%m-%d %H:%M:%S'):
     def str_to_timestamp(str_time=None, format='%Y-%m-%d %H:%M:%S'):
         if str_time:
         if str_time:
@@ -305,9 +309,6 @@ class CommonService:
             return int(result)
             return int(result)
         return int(time.time())
         return int(time.time())
 
 
-
-
-
     # 把时间戳转换成格式化
     # 把时间戳转换成格式化
     @staticmethod
     @staticmethod
     def timestamp_to_str(timestamp=None, format='%Y-%m-%d %H:%M:%S'):
     def timestamp_to_str(timestamp=None, format='%Y-%m-%d %H:%M:%S'):
@@ -318,8 +319,7 @@ class CommonService:
         else:
         else:
             return time.strptime(format)
             return time.strptime(format)
 
 
-
-    #计算N个月后的时间戳
+    # 计算N个月后的时间戳
     @staticmethod
     @staticmethod
     def calcMonthLater(addMonth, unix_timestamp=None):
     def calcMonthLater(addMonth, unix_timestamp=None):
         if unix_timestamp:
         if unix_timestamp:
@@ -346,8 +346,8 @@ class CommonService:
         for is_format in range(4):
         for is_format in range(4):
             try:
             try:
                 date_format = '{now_year}-{now_month}-{now_day} {now_hour}:{now_min}:{now_second}' \
                 date_format = '{now_year}-{now_month}-{now_day} {now_hour}:{now_min}:{now_second}' \
-                    .format(now_year=now_year,now_month=now_month,now_day=now_day,now_hour=now_hour,
-                            now_min=now_min,now_second=now_second)
+                    .format(now_year=now_year, now_month=now_month, now_day=now_day, now_hour=now_hour,
+                            now_min=now_min, now_second=now_second)
                 timestamps = CommonService.str_to_timestamp(date_format)
                 timestamps = CommonService.str_to_timestamp(date_format)
             except Exception as e:
             except Exception as e:
                 if str(e) == 'day is out of range for month':
                 if str(e) == 'day is out of range for month':
@@ -476,7 +476,13 @@ class CommonService:
 
 
     @staticmethod
     @staticmethod
     def req_publish_mqtt_msg(thing_name, topic_name, msg):
     def req_publish_mqtt_msg(thing_name, topic_name, msg):
-        # 通用发布MQTT消息函数
+        """
+        通用发布MQTT消息函数
+        @param thing_name: 物品名
+        @param topic_name: 主题名
+        @param msg: 消息内容
+        @return: boolean
+        """
         if not all([thing_name, topic_name, msg]):
         if not all([thing_name, topic_name, msg]):
             return False
             return False
 
 
@@ -582,12 +588,50 @@ GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
                 return uid
                 return uid
         return serial_number
         return serial_number
 
 
+    @staticmethod
+    def get_full_serial_number(uid, serial_number, device_type):
+        """
+        根据uid查询返回完整序列号
+        @param uid: uid
+        @param serial_number: 序列号
+        @param device_type: 设备类型
+        @return: full_serial_number
+        """
+        p2p_type = str(UIDModel.objects.filter(uid=uid).values('p2p_type')[0]['p2p_type'])
+        # 设备类型转为16进制并补齐4位
+        device_type = hex(device_type)[2:]
+        device_type = (4 - len(device_type)) * '0' + device_type
+        full_serial_number = serial_number + p2p_type + device_type
+        return full_serial_number
+
     # 根据企业标识返回物品名
     # 根据企业标识返回物品名
     @staticmethod
     @staticmethod
     def get_thing_name(company_mark, thing_name_suffix):
     def get_thing_name(company_mark, thing_name_suffix):
         if company_mark == '11A':
         if company_mark == '11A':
             return 'Ansjer_Device_' + thing_name_suffix
             return 'Ansjer_Device_' + thing_name_suffix
         elif company_mark == '11L':
         elif company_mark == '11L':
-            return 'Loocam_Device_' + thing_name_suffix
+            return 'LC_' + thing_name_suffix
         else:
         else:
             return thing_name_suffix
             return thing_name_suffix
+
+    @staticmethod
+    def confirm_region_id(request):
+        """
+        根据配置信息确定region_id
+        @param request: 请求体
+        @return: region_id
+        """
+        region_id = 3
+        if CONFIG_INFO == CONFIG_TEST or CONFIG_INFO == CONFIG_CN:
+            region_id = 1
+        else:  # 国外配置暂时通过ip确认
+            ip = CommonService.get_ip_address(request)
+            ipInfo = CommonService.getIpIpInfo(ip, 'CN')
+            if ipInfo['country_code']:
+                country_qs = CountryModel.objects.filter(country_code=ipInfo['country_code']).values('region__id')
+                if country_qs.exists():
+                    region_id = country_qs[0]['region__id']
+            else:  # 不存在默认返回美洲地区api
+                region_qs = RegionModel.objects.filter(continent_code='NA').values("id")
+                region_id = region_qs[0]['id']
+        return region_id

+ 90 - 4
Service/EquipmentInfoService.py

@@ -7,8 +7,9 @@
 @Software: PyCharm
 @Software: PyCharm
 """
 """
 import datetime
 import datetime
+import logging
 import time
 import time
-
+import itertools
 from django.db.models import Value, CharField
 from django.db.models import Value, CharField
 
 
 from Model.models import EquipmentInfoMonday, EquipmentInfoTuesday, EquipmentInfoWednesday, EquipmentInfoThursday, \
 from Model.models import EquipmentInfoMonday, EquipmentInfoTuesday, EquipmentInfoWednesday, EquipmentInfoThursday, \
@@ -165,10 +166,9 @@ class EquipmentInfoService:
         if user_id:
         if user_id:
             qs = qs.filter(device_user_id=user_id)
             qs = qs.filter(device_user_id=user_id)
         if event_type:
         if event_type:
-            # 兼容AI查询
+            # 多类型查询
             if ',' in event_type:
             if ',' in event_type:
-                eventTypeList = event_type.split(',')
-                eventTypeList = [int(i.strip()) for i in eventTypeList]
+                eventTypeList = cls.get_comb_event_type(event_type)
                 qs = qs.filter(event_type__in=eventTypeList)
                 qs = qs.filter(event_type__in=eventTypeList)
             else:
             else:
                 qs = qs.filter(event_type=event_type)
                 qs = qs.filter(event_type=event_type)
@@ -220,3 +220,89 @@ class EquipmentInfoService:
             item.pop('border_coords')
             item.pop('border_coords')
             item.pop('tab_val')
             item.pop('tab_val')
         return qs_page
         return qs_page
+
+    @classmethod
+    def get_comb_event_type(cls, event_type):
+        """
+        重新组合ai消息类型查询,使其支持ai多标签查询
+        @param event_type: 消息类型
+        @return: event_type_list 消息类型数组
+        """
+        event_type_list = event_type.split(',')
+        event_type_list = [int(i.strip()) for i in event_type_list]
+        ai_event_type_list = []
+        for key, val in enumerate(event_type_list):
+            if val <= 4:  # 分离出ai类型,以便后续组合ai标签,目前只存在4个ai类型1,2,3,4
+                ai_event_type_list.append(val)
+                del (event_type_list[key])
+        if len(ai_event_type_list) < 1:
+            return event_type_list
+        ai_event_type_list.sort()
+        type = [1, 2, 3, 4]  # AI目前所有的标签,1人,2车,3宠物,4包裹,后续有新类型需要这里加, 后续会优化,存在表里,包裹存对应的aws标签
+        comb_ai_event_type = []
+        seen = set()
+        for i in range(1, len(type) + 1):  # 计算所有组合,如[1, 2, 3, 4], 4取1,4取2,4取3,4取4
+            for s in itertools.combinations(type, i):
+                if s not in seen:  # 去除重复项, 如a=[1,2,3,4,4],会有两个[1,2,3,4,4],[1,2,3,4,4]的组合
+                    seen.add(s)
+                    s_list = list(s)
+                    for ai_event_type in ai_event_type_list:
+                        if ai_event_type in s_list:  # 排除没有选择的标签组合
+                            if s_list not in comb_ai_event_type:
+                                s_list = [str(v) for v in s_list]
+                                comb_ai_event_type.append(s_list)
+        regroup_list = []
+        for val in comb_ai_event_type:  # 组合ai类型组合,如[[2,3],[1,3]] -> [23, 13]
+            val = ''.join(val)
+            regroup_list.append(int(val))
+        event_type_list = regroup_list + event_type_list  # 加上普通移动消息类型
+        return event_type_list
+
+    @classmethod
+    def get_all_comb_event_type(cls):
+        """
+        计算ai消息类型全组合
+        @return: event_type_list ai所有消息类型数组
+        """
+        type = [1, 2, 3, 4]  # AI目前所有的标签,1人,2车,3宠物,4包裹,后续有新类型需要这里加, 后续会优化,存在表里,包裹存对应的aws标签
+        comb_ai_event_type = []
+        for i in range(1, len(type) + 1):  # 计算所有组合,如[1, 2, 3, 4], 4取1,4取2,4取3,4取4
+            for s in itertools.combinations(type, i):
+                    s_list = list(s)
+                    s_list = [str(v) for v in s_list]
+                    comb_ai_event_type.append(s_list)
+        regroup_list = []
+        for val in comb_ai_event_type:  # 组合ai类型组合,如[[2,3],[1,3]] -> [23, 13]
+            val = ''.join(val)
+            regroup_list.append(int(val))
+        return regroup_list
+
+    @staticmethod
+    def get_equipment_info_obj(dt, **kwargs):
+        """
+        根据日期判断是星期几,返回相应的对象实例
+        @param dt: 日期 例:2022-03-03
+        @param kwargs: 设备信息属性值
+        @return: 星期一至星期天equipment_info对象实例
+        """
+        logger = logging.getLogger('info')
+        week = LocalDateTimeUtil.date_to_week(dt)
+        logger.info('本周{}'.format(str(week)))
+        equipment_info = None
+        if week == 1:
+            equipment_info = EquipmentInfoMonday(**kwargs)
+        elif week == 2:
+            equipment_info = EquipmentInfoTuesday(**kwargs)
+        elif week == 3:
+            equipment_info = EquipmentInfoWednesday(**kwargs)
+        elif week == 4:
+            equipment_info = EquipmentInfoThursday(**kwargs)
+        elif week == 5:
+            equipment_info = EquipmentInfoFriday(**kwargs)
+        elif week == 6:
+            equipment_info = EquipmentInfoSaturday(**kwargs)
+        elif week == 7:
+            equipment_info = EquipmentInfoSunday(**kwargs)
+        logger.info(type(equipment_info))
+        logger.info(equipment_info)
+        return equipment_info

+ 1 - 1
Service/MiscellService.py

@@ -34,9 +34,9 @@ class MyserviceDynamodb():
     def __session(self):
     def __session(self):
         try:
         try:
             session = Session(aws_access_key_id=self.access_key, aws_secret_access_key=self.secret_key,region_name=self.region)
             session = Session(aws_access_key_id=self.access_key, aws_secret_access_key=self.secret_key,region_name=self.region)
+            return session
         except:
         except:
             print("Failed to connect session in region{0}".format(self.region))
             print("Failed to connect session in region{0}".format(self.region))
-        return session
 
 
     # 添加access_log表数据
     # 添加access_log表数据
     def access_log_item_put(self,table_name,data_list):
     def access_log_item_put(self,table_name,data_list):

+ 181 - 0
Service/PayService.py

@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+# 支付类
+
+
+class PaymentService:
+
+    # 返回支付失败html内容
+    @staticmethod
+    def get_pay_error_content():
+        return '''
+<!DOCTYPE html>
+<html>
+<head>
+	<!--浏览器不缓存-->
+	<meta http-equiv="Pragma" content="no-cache">
+	<meta http-equiv="Cache-Control" content="no-cache">
+	<meta http-equiv="Expires" content="0">
+	<!--utf-8-->
+    <meta http-equiv="content-type" content="text/html;charset=utf-8">
+    <!-- viewport的<meta>标签,这个标签可以修改在大部分的移动设备上面的显示,为了确保适当的绘制和触屏缩放。-->
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link rel="shortcut icon" href="https://test.zositechc.cn/web/images/favicon.ico" type="image/x-icon"  charset="utf-8"/>
+    <title>Trading particulars</title>
+    <style>
+    	.title_head{
+    		height: 50px;
+    		border-radius: 5px;
+    		background-color: #c3c6c7;
+    		text-align: center;
+    		line-height: 50px;
+    	}
+    	.content{
+    		text-align: center;
+    		margin-top: 50px;
+    		font-size: 20px;
+    		color : #ec7648
+    	}
+    	.content_img{
+    		width: 60px;
+    		height: 60px;
+    	}
+    	.bottom{
+    		 margin-bottom: 10px;
+    		 margin-top: 250px;
+    		 color : #ec7648
+    	}
+    	.bottom_div{
+    		border: 1px solid #ec7648;
+    		line-height: 38px;
+    		text-align: center;
+    		width: 100px;
+    		height: 38px;
+    		border-radius: 5px;
+    	}
+
+    	.bottom_div:hover{
+    		background-color: #dde4e2;
+    	}
+    </style>
+</head>
+<body>
+	<div class="title_head">Trading particulars</div>
+    <div class="content">
+    	<p >
+    		<img src="https://test.zositechc.cn/web/images/failed.jpg" class="content_img">
+    		<br />
+    		Payment failure
+    	</p>
+    </div>
+    <center class="bottom">
+    	<div class="bottom_div" onclick="payOKButton()">
+    	 Finish
+    	</div>
+    </center>
+    <script> 	    // 点击付款成功按钮
+    function payOKButton() {
+        // 复杂数据
+        console.log('success')
+        window.location.href="https://www.baidu.com?page=closePage";
+    }
+	</script>
+</body>
+</html>
+                '''
+
+    # 返回支付成功html内容
+    @staticmethod
+    def get_pay_ok_content(lang, pay_type):
+        title = "支付成功"
+        complete = '完成'
+        if lang == 'cn':
+            if pay_type == "10":
+                title = "体验成功"
+            if pay_type == "11":
+                title = "兑换成功"
+        else:
+            title = "Payment successful"
+            complete = 'complete'
+            if pay_type == "10":
+                title = "Successful experience"
+            if pay_type == "11":
+                title = "Successful exchange"
+
+        return '''
+        <html>
+        <head>
+                <!--浏览器不缓存-->
+                <meta http-equiv="Pragma" content="no-cache">
+                <meta http-equiv="Cache-Control" content="no-cache">
+                <meta http-equiv="Expires" content="0">
+                <!--utf-8-->
+            <meta http-equiv="content-type" content="text/html;charset=utf-8">
+            <!-- viewport的<meta>标签,这个标签可以修改在大部分的移动设备上面的显示,为了确保适当的绘制和触屏缩放。-->
+            <meta name="viewport" content="width=device-width, initial-scale=1.0">
+            <link rel="shortcut icon" href="https://test.zositechc.cn/web/images/favicon.ico" type="image/x-icon" charset="utf-8">
+            <title>''' + title + '''</title>
+            <style>
+                    .title_head{
+                            height: 50px;
+                            border-radius: 5px;
+                            background-color: #c3c6c7;
+                            text-align: center;
+                            line-height: 50px;
+                    }
+                    .content{
+                            text-align: center;
+                            margin-top: 50px;
+                            font-size: 15px;
+                            color:#0000008A;
+
+                    }
+                    .content_img{
+        					margin-bottom:15px;
+                            width: 60px;
+                            height: 60px;
+                    }
+                    .bottom{
+                             margin-bottom: 10px;
+                             margin-top: 250px;
+                             color : white;
+                    }
+                    .bottom_div{
+                            border: 1px solid #68c9c5;
+                            line-height: 38px;
+                            text-align: center;
+                            width: 100px;
+                            height: 38px;
+                            border-radius: 30px;
+        					background-color:#68c9c5;
+                    }
+
+                    .bottom_div:hover{
+                            background-color: #dde4e2;
+                    }
+            </style>
+        </head>
+        <body style="" rlt="1" inmaintabuse="true">
+
+            <div class="content">
+                    <p>
+        					<img src="https://test.zositechc.cn/web/images/success.png" class="content_img">
+                            <br>
+                            ''' + title + '''
+                    </p>
+            </div>
+            <center class="bottom">
+                    <div class="bottom_div" onclick="payOKButton()">
+                     ''' + complete + '''
+                    </div>
+            </center>
+            <script src="//hm.baidu.com/hm.js?eaa57ca47dacb4ad4f5a257001a3457c"></script><script>             // 点击付款成功按钮
+            function payOKButton() {
+                // 复杂数据
+                console.log('success')
+                window.location.href="https://www.baidu.com?page=closePage"
+            }
+                </script>
+
+
+                <div id="qds" style="display:none;"></div></body></html>
+                '''

BIN
requirements.txt