فهرست منبع

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

guanhailong 2 سال پیش
والد
کامیت
1ef099b876
43فایلهای تغییر یافته به همراه1992 افزوده شده و 326 حذف شده
  1. 14 2
      AdminController/DeviceManagementController.py
  2. 5 7
      AdminController/UnicomManageController.py
  3. 2 2
      Ansjer/cn_config/config_test.py
  4. 2 0
      Ansjer/config.py
  5. 2 0
      Ansjer/server_urls/algorithm_shop_url.py
  6. 2 1
      Ansjer/server_urls/loocam_url.py
  7. 6 2
      Ansjer/urls.py
  8. 1 1
      Controller/AdminManage.py
  9. 7 1
      Controller/AiController.py
  10. 172 5
      Controller/AlgorithmShop/AlgorithmShopController.py
  11. 54 62
      Controller/CloudStorage.py
  12. 1 1
      Controller/CloudVod.py
  13. 86 12
      Controller/Cron/CronTaskController.py
  14. 9 18
      Controller/DetectController.py
  15. 38 23
      Controller/DetectControllerV2.py
  16. 0 2
      Controller/DeviceManage.py
  17. 0 4
      Controller/DeviceShare.py
  18. 29 0
      Controller/EquipmentInfo.py
  19. 2 14
      Controller/EquipmentManager.py
  20. 66 5
      Controller/EquipmentManagerV3.py
  21. 1 1
      Controller/EquipmentStatus.py
  22. 0 7
      Controller/FileController.py
  23. 29 0
      Controller/InitController.py
  24. 7 7
      Controller/LogManager.py
  25. 0 5
      Controller/PctestController.py
  26. 14 11
      Controller/RegionController.py
  27. 18 5
      Controller/SensorGateway/EquipmentFamilyController.py
  28. 99 4
      Controller/SensorGateway/GatewayDeviceController.py
  29. 812 0
      Controller/SensorGateway/SmartSocketController.py
  30. 182 55
      Controller/SerialNumberController.py
  31. 96 12
      Controller/TestApi.py
  32. 0 4
      Controller/UIDPreview.py
  33. 0 2
      Controller/UidSetController.py
  34. 4 16
      Controller/UserController.py
  35. 1 1
      Controller/shareUserPermission.py
  36. 140 3
      Model/models.py
  37. 47 0
      Object/AWS/AWSIoTDataPlaneUtil.py
  38. 3 25
      Object/RedisObject.py
  39. 4 2
      Object/ResponseObject.py
  40. 29 0
      Service/CommonService.py
  41. 4 3
      Service/EquipmentInfoService.py
  42. 1 0
      Service/TemplateService.py
  43. 3 1
      Service/VodHlsService.py

+ 14 - 2
AdminController/DeviceManagementController.py

@@ -11,11 +11,13 @@ 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, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, \
-    AWS_SES_ACCESS_REGION
+    AWS_SES_ACCESS_REGION, UNUSED_SERIAL_REDIS_LIST
 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, AppVersionNumber, UIDCompanySerialModel
+    AppBundle, App_Info, AppDeviceType, DeviceNameLanguage, AppVersionNumber, UIDCompanySerialModel, UIDModel, \
+    CompanySerialModel
 from Object.AWS.AmazonS3Util import AmazonS3Util
+from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -463,6 +465,10 @@ class DeviceManagement(View):
                     uid_company_serial_qs = UIDCompanySerialModel.objects.filter(
                         company_serial__serial_number__in=serial_number_list).values('uid__uid')
                     uidList = [item[key] for item in uid_company_serial_qs for key in item]
+                    # 解绑uid数据,重置序列号状态
+                    UIDModel.objects.filter(uid__in=uidList).update(status=0)
+                    UIDCompanySerialModel.objects.filter(uid__uid__in=uidList).delete()
+                    CompanySerialModel.objects.filter(serial_number__in=serial_number_list).update(status=1)
                 # 根据删除项删除相关数据
                 if '设备信息数据' in delDataOptions:
                     Device_Info.objects.filter(UID__in=uidList).delete()
@@ -486,6 +492,12 @@ class DeviceManagement(View):
                     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='')
+
+                # 序列号加入重置状态redis列表
+                if serialNumberList is not None:
+                    redis_obj = RedisObject()
+                    for serial in serial_number_list:
+                        redis_obj.rpush(UNUSED_SERIAL_REDIS_LIST, serial)
             return response.json(0)
         except Exception as e:
             print(e)

+ 5 - 7
AdminController/UnicomManageController.py

@@ -453,10 +453,10 @@ class UnicomManageControllerView(View):
         @param response: 响应对象
         @param return:
         """
-        userName = request_dict.get('userName', None)
+        userId = request_dict.get('userId', None)
         serialNo = request_dict.get('serialNo', None)
         comboId = request_dict.get('comboId', None)
-        if not all([userName, serialNo, comboId]):
+        if not all([userId, serialNo, comboId]):
             return response.json(444)
         try:
             while transaction.atomic():
@@ -464,10 +464,8 @@ class UnicomManageControllerView(View):
                     .values('id', 'combo_name', 'price', 'virtual_price', 'remark', 'combo_type').order_by('sort')
                 if not combo_info_qs.exists():
                     return response.json(173)
-                device_user_qs = Device_User.objects.filter(username=userName).values('userID')
-                userID = device_user_qs[0]['userID'] if device_user_qs.exists() else ''
                 unicom_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serialNo,
-                                                                        user_id=userID).values \
+                                                                        user_id=userId).values \
                     ('user_id', 'iccid', 'serial_no')
                 if not unicom_device_info_qs.exists():
                     return response.json(173)
@@ -478,7 +476,7 @@ class UnicomManageControllerView(View):
                 unicom_combo = UnicomComboView.create_combo_order_info(order_id=order_id, activate_type=1, iccid=icc_id,
                                                                        combo_id=comboId)
                 if unicom_combo is False:
-                    return False
+                    return response.json(178)
                 # 获取套餐信息
                 combo_info_vo = combo_info_qs[0]
                 c_time = n_time
@@ -486,7 +484,7 @@ class UnicomManageControllerView(View):
                 uid = CommonService.query_uid_with_serial(serial_no)
                 rank_id, ai_rank_id = UnicomComboView.get_cloud_or_ai_combo()  # 生成订单必须添加该字段
                 order_dict = {'orderID': order_id, 'UID': uid, 'rank_id': rank_id, 'ai_rank_id': ai_rank_id,
-                              'userID_id': userID, 'desc': combo_info_vo['combo_name'], 'payType': 10,
+                              'userID_id': userId, 'desc': combo_info_vo['combo_name'], 'payType': 10,
                               'payTime': c_time, 'price': combo_info_vo['price'], 'addTime': c_time,
                               'updTime': c_time, 'status': 1,
                               'unify_combo_id': str(combo_info_vo['id']), 'order_type': 2,

+ 2 - 2
Ansjer/cn_config/config_test.py

@@ -27,8 +27,8 @@ LOG_BUCKET = 'ansjer-statres'                       # 日志存储桶
 PUSH_CLOUD_PHOTO = 'push-cloud-photo'               # 推送云相册存储桶
 
 # redis节点
-SERVER_HOST = 'backendserver.3xavzq.0001.cnw1.cache.amazonaws.com.cn'
-PUSH_REDIS_ADDRESS = 'pushredis.3xavzq.0001.cnw1.cache.amazonaws.com.cn'
+SERVER_HOST = '127.0.0.1'
+PUSH_REDIS_ADDRESS = '127.0.0.1'
 # ======================================================================================================================
 
 # 域名

+ 2 - 0
Ansjer/config.py

@@ -18,6 +18,8 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 # 序列号redis列表
 USED_SERIAL_REDIS_LIST = 'used_serial_redis_list'
 UNUSED_SERIAL_REDIS_LIST = 'unused_serial_redis_list'
+RESET_REGION_ID_SERIAL_REDIS_LIST = 'reset_region_id_serial_redis_list'
+
 # 地区id列表
 REGION_ID_LIST = [1, 2, 3, 4, 5]
 

+ 2 - 0
Ansjer/server_urls/algorithm_shop_url.py

@@ -16,4 +16,6 @@ urlpatterns = [
     re_path(r'^api/(?P<operation>.*)$', AlgorithmShopController.AlgorithmShopView.as_view()),
     re_path(r'^cron/(?P<operation>.*)$', CronCloudPhotoController.CronCloudPhotoView.as_view()),
     re_path(r'^photo/(?P<operation>.*)$', CloudPhotoController.CronCloudPhotoView.as_view()),
+    re_path(r'^open/(?P<operation>.*)$', AlgorithmShopController.AlgorithmShopView.as_view()),
+
 ]

+ 2 - 1
Ansjer/server_urls/loocam_url.py

@@ -9,7 +9,7 @@
 from django.urls import re_path
 
 from Controller.SensorGateway import GatewayFamilyRoomController, SubDeviceController, GatewayFamilyMemberController, \
-    EquipmentFamilyController, GatewayDeviceController, SmartSceneController
+    EquipmentFamilyController, GatewayDeviceController, SmartSceneController, SmartSocketController
 
 urlpatterns = [
     re_path(r'^sensor/gateway/(?P<operation>.*)$', EquipmentFamilyController.EquipmentFamilyView.as_view()),
@@ -19,4 +19,5 @@ urlpatterns = [
     re_path(r'^gateway/subdevice/(?P<operation>.*)$', SubDeviceController.GatewaySubDeviceView.as_view()),
     re_path(r'^gateway/device/info/(?P<operation>.*)$', GatewayDeviceController.GatewayDeviceView.as_view()),
     re_path(r'^smartscene/(?P<operation>.*)$', SmartSceneController.SmartSceneView.as_view()),
+    re_path(r'^open/socket/(?P<operation>.*)$', SmartSocketController.SmartSocketView.as_view()),
 ]

+ 6 - 2
Ansjer/urls.py

@@ -22,7 +22,7 @@ from Controller import FeedBack, EquipmentOTA, EquipmentInfo, AdminManage, AppIn
     OrderTaskController, HistoryUIDController, UIDManageUserController, SerialNumberController, CompanyController, \
     RegionController, VPGController, LanguageController, TestController, DeviceConfirmRegion, S3GetStsController, \
     DetectControllerV2, PcInfo, PctestController, DeviceDebug, PaymentCycle, \
-    DeviceLogController, CouponController, AiController, ShadowController, SuperPasswordTool
+    DeviceLogController, CouponController, AiController, ShadowController, SuperPasswordTool, InitController
 from Controller.Cron import CronTaskController
 from Controller.MessagePush import EquipmentMessagePush
 from Controller.SensorGateway import SensorGatewayController, EquipmentFamilyController
@@ -30,6 +30,7 @@ from Controller.Surveys import CloudStorageController
 from Controller.UserDevice import UserDeviceShareController
 
 urlpatterns = [
+    re_path(r'init/(?P<operation>.*)', InitController.InitView.as_view()),
     re_path(r'^testApi/(?P<operation>.*)', TestApi.testView.as_view()),
     re_path(r'^account/authcode', UserController.authCodeView.as_view()),
     re_path(r'^v3/account/generatepictureCodeView/$', UserController.generatePictureCodeView.as_view()),
@@ -200,7 +201,7 @@ urlpatterns = [
     re_path(r'^faq/(?P<operation>.*)$', FAQController.FAQView.as_view()),
     re_path(r'^ios/authsign', UserController.AppleAuthLogin.as_view()),
     re_path(r'^appLog/(?P<operation>.*)$', AppLogController.AppLogView.as_view()),
-    re_path(r'^deviceLog/(?P<operation>.*)$', DeviceLogController.DeviceLogView.as_view()),
+    re_path(r'deviceLog/(?P<operation>.*)$', DeviceLogController.DeviceLogView.as_view()),
     re_path(r'^local/(?P<operation>.*)$', UserController.LocalUserView.as_view()),
     re_path(r'^account/updateUserCountry', UserController.updateUserCountry),
     re_path(r'^equipmentVersionLimit/(?P<operation>.*)$', EquipmentVersionLimit.EquipmentVersionLimitView.as_view()),
@@ -248,8 +249,10 @@ urlpatterns = [
     re_path(r'^api/device/share/(?P<operation>.*)$', UserDeviceShareController.UserDeviceShareView.as_view()),
     re_path(r'^app/sensor/gateway/(?P<operation>.*)$', EquipmentFamilyController.EquipmentFamilyView.as_view()),
     re_path(r'^loocam/', include("Ansjer.server_urls.loocam_url")),
+    re_path(r'^api/loocam/', include("Ansjer.server_urls.loocam_url")),
     re_path(r'^unicom/', include("Ansjer.server_urls.unicom_url")),
     re_path(r'^algorithm-shop/', include("Ansjer.server_urls.algorithm_shop_url")),
+    re_path(r'^api/algorithm/', include("Ansjer.server_urls.algorithm_shop_url")),
     re_path(r'^kvs/', include("Ansjer.server_urls.kvs_url")),
     re_path('appAccout/(?P<operation>.*)', SuperPasswordTool.SuperPasswordView.as_view()),
     re_path('sensorGateway/(?P<operation>.*)', SensorGatewayController.SensorGateway.as_view()),
@@ -293,6 +296,7 @@ urlpatterns = [
     re_path(r'^cron/update/(?P<operation>.*)', CronTaskController.CronUpdateDataView.as_view()),
     re_path(r'^cron/collect/(?P<operation>.*)', CronTaskController.CronCollectDataView.as_view()),
 
+    # 国内域名备案网站/错误路径
     re_path('(?P<path>.*)', LogManager.errorPath),
 
 ]

+ 1 - 1
Controller/AdminManage.py

@@ -178,7 +178,7 @@ class AdminManage(TemplateView):
         own_perm = ModelService.check_perm(userID, 30)
         if own_perm:
             count = int(Device_User.objects.count())
-            redisObj = RedisObject(db=3)
+            redisObj = RedisObject()
             onlines = int(redisObj.get_size())
             print(onlines)
             return response.json(0, {"onlinenum": onlines, "no_onlinenum": count - onlines})

+ 7 - 1
Controller/AiController.py

@@ -467,6 +467,7 @@ class AiView(View):
         @request_dict tz: 时区
         @request_dict detect_group: 检测类型
         @request_dict interval: 推送间隔
+        @request_dict domain_name: 域名
         @param user_id: 用户id
         @param response: 响应
         @return: response
@@ -482,6 +483,7 @@ class AiView(View):
         tz = request_dict.get('tz', '0')
         detect_group = request_dict.get('detect_group', None)
         interval = request_dict.get('interval', None)
+        domain_name = request_dict.get('domain_name', None)
 
         if not all([appBundleId, app_type, token_val, uid, m_code, status]):
             return response.json(444, 'appBundleId, app_type, token_val, uid,m_code, status')
@@ -568,7 +570,11 @@ class AiView(View):
                 etk = etkObj.encrypt(uid)
 
                 # mqtt通知设备开启AI识别功能
-                aiIdentificationUrl = '{}AiService/identification'.format(DETECT_PUSH_DOMAINS)
+                push_url = DETECT_PUSH_DOMAINS
+                # 欧洲域名固定返回欧洲域名
+                if domain_name in ['api.zositeche.com', 'api.loocam3.com', 'common.neutral3.com']:
+                    push_url = 'https://push.zositeche.com/'
+                aiIdentificationUrl = '{}AiService/identification'.format(push_url)
                 msg = {
                     'commandType': 'AIEnable',
                     'payload': {

+ 172 - 5
Controller/AlgorithmShop/AlgorithmShopController.py

@@ -9,14 +9,15 @@
 import logging
 import time
 
-from django.db.models import F
+from django.db.models import F, Value, CharField
 from django.views.generic.base import View
 
-from Model.models import DeviceAlgorithmExplain, DeviceAlgorithmBanner, DeviceUidAlgorithmType, DeviceTypeAlgorithmInfo
+from Model.models import DeviceAlgorithmExplain, DeviceAlgorithmBanner, DeviceUidAlgorithmType, \
+    DeviceTypeAlgorithmInfo, DeviceAppScenario, DeviceScenarioLangInfo, DeviceAlgorithmScenario
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 
-logger = logging.getLogger('info')
+LOGGER = logging.getLogger('info')
 
 
 class AlgorithmShopView(View):
@@ -44,6 +45,167 @@ class AlgorithmShopView(View):
             return self.get_algorithm_details(request_dict, response)
         elif operation == 'save':
             return self.algorithm_setting_save(request_dict, response)
+        elif operation == 'getScenarioList':  # 获取应用场景数据列表
+            return self.get_scenario_list(request_dict, response)
+        elif operation == 'getAlgorithmListByScenarioId':  # 根据应用场景id获取算法列表
+            return self.get_scenario_algorithm_list(request_dict, response)
+        else:
+            return response.json(0)
+
+    @classmethod
+    def get_algorithm_list_by_scenario_id(cls, scenario_id, lang):
+        """
+        根据应用场景ID查询算法信息列表
+        @param scenario_id: 场景ID
+        @param lang: 语言
+        @return: 算法类型信息
+        """
+        try:
+            if not scenario_id or scenario_id == 0:
+                return []
+            # 根据场景id查询关联的算法id
+            algorithm_scenario_qs = DeviceAlgorithmScenario.objects.filter(scenario_id=scenario_id) \
+                .order_by('sort').values('algorithm_id')
+            if not algorithm_scenario_qs.exists():
+                return []
+            algorithm_list = []
+            for item in algorithm_scenario_qs:
+                algorithm_id = item['algorithm_id']
+                # 根据算法id查询多语言数据
+                algorithm_list.append(cls.get_lang_info_by_algorithm_id(algorithm_id, lang, None))
+            return algorithm_list
+        except Exception as e:
+            LOGGER.info('***get_algorithm_list_by_scenario_id,errLine:{}, errMsg:{}'
+                        .format(e.__traceback__.tb_lineno, repr(e)))
+            return []
+
+    @classmethod
+    def get_lang_info_by_algorithm_id(cls, algorithm_id, lang, uid):
+        """
+        根据算法id查询多语言数据详情
+        @param uid: 设备uid
+        @param algorithm_id: 算法id
+        @param lang: 语言
+        @return: 算法多语言数据详情
+        """
+        try:
+            algorithm_qs = DeviceAlgorithmExplain.objects.filter(algorithm_type_id=algorithm_id, lang=lang) \
+                .values('algorithm_type__icon_url', 'algorithm_type__id',
+                        'title', 'subtitle', 'algorithm_type__image_url',
+                        'algorithm_type__basic_function', 'concerning',
+                        'price', 'algorithm_type__tag', 'algorithm_type__status')
+            if not algorithm_qs.exists():
+                return {}
+            setting = ''  # 当前支持设置的算法功能json
+            # 存在uid则查询当前uid是否支持该算法
+            if uid:
+                setting = cls.get_uid_algorithm_info(algorithm_id, uid)
+                setting = setting if setting else {'status': 0, 'function': {}}
+            data = {
+                'typeId': algorithm_qs[0]['algorithm_type__id'],
+                'iconUrl': algorithm_qs[0]['algorithm_type__icon_url'],
+                'imageUrl': algorithm_qs[0]['algorithm_type__image_url'],
+                'title': algorithm_qs[0]['title'],
+                'subtitle': algorithm_qs[0]['subtitle'],
+                'basicFunction': algorithm_qs[0]['algorithm_type__basic_function'],
+                'concerning': algorithm_qs[0]['concerning'],
+                'price': algorithm_qs[0]['price'],
+                'tag': algorithm_qs[0]['algorithm_type__tag'],
+                'status': algorithm_qs[0]['algorithm_type__status'],
+                'setting': setting
+            }
+            return data
+        except Exception as e:
+            LOGGER.info('***get_lang_info_by_algorithm_id,errLine:{}, errMsg:{}'
+                        .format(e.__traceback__.tb_lineno, repr(e)))
+            return {}
+
+    @classmethod
+    def get_algorithm_list(cls, lang):
+        """
+        获取所有算法数据列表
+        @return: 算法数据列表
+        """
+        algorithm_qs = DeviceAlgorithmExplain.objects.filter(lang=lang).order_by('algorithm_type__sort') \
+            .annotate(iconUrl=F('algorithm_type__icon_url'),
+                      typeId=F('algorithm_type__id'),
+                      imageUrl=F('algorithm_type__image_url'),
+                      basicFunction=F('algorithm_type__basic_function'),
+                      tag=F('algorithm_type__tag'), status=F('algorithm_type__status'),
+                      setting=Value('', output_field=CharField())) \
+            .values('iconUrl', 'imageUrl', 'title', 'subtitle', 'concerning', 'basicFunction', 'price', 'tag', 'status',
+                    'setting', 'typeId')
+        if not algorithm_qs.exists():
+            return []
+        return list(algorithm_qs)
+
+    @classmethod
+    def get_scenario_list(cls, request_dist, response):
+        """
+        获取应用场景列表
+        @param request_dist: lang
+        @param response: 响应结果
+        @return: 应用场景列表
+        """
+        try:
+            lang = request_dist.get('lang', 'en')
+            if not lang:
+                return response.json(444)
+            # 获取应用场景列表
+            scenario_qs = DeviceAppScenario.objects.filter().exclude(type=0).all().order_by('sort') \
+                .values('id', 'type', 'cver_url', 'banner_url')
+            scenario_list = []
+            if not scenario_qs.exists():
+                return response.json(0, scenario_list)
+
+            for item in scenario_qs:
+                scenario_vo = {'id': item['id'], 'cverUrl': item['cver_url'], 'bannerUrl': item['banner_url'],
+                               'name': '', 'content': ''}
+                # 获取根据语言应用场景信息
+                scenario_info_qs = DeviceScenarioLangInfo.objects.filter(lang=lang, scenario_id=item['id']) \
+                    .values('name', 'content')
+                if not scenario_info_qs.exists():
+                    continue
+                scenario_vo['name'] = scenario_info_qs[0]['name']
+                scenario_vo['content'] = scenario_info_qs[0]['content']
+                # 根据应用场景id查询关联算法类型数据
+                # scenario_vo['algorithmList'] = cls.get_algorithm_list_by_scenario_id(item['id'], lang)
+                scenario_list.append(scenario_vo)
+            # 获取所有算法图标地址以及算法名称
+            algorithm_qs = DeviceAlgorithmExplain.objects.filter(lang=lang).order_by('algorithm_type__sort') \
+                .annotate(algorithmId=F('algorithm_type__id'), algorithmType=F('algorithm_type__type'),
+                          iconUrl=F('algorithm_type__icon_url'),
+                          algorithmName=F('title')).values('algorithmId', 'algorithmType', 'iconUrl', 'algorithmName')
+            scenario_qs = DeviceAppScenario.objects.filter(type=0) \
+                .values('cver_url', 'banner_url')
+            scenario_banner = {}
+            if scenario_qs.exists():
+                scenario_banner['cverUrl'] = scenario_qs[0]['cver_url']
+                scenario_banner['bannerUrl'] = scenario_qs[0]['banner_url']
+            result_dto = {'scenarioList': scenario_list, 'scenarioUrl': scenario_banner}
+            if algorithm_qs.exists():
+                result_dto['iconList'] = list(algorithm_qs)
+            return response.json(0, result_dto)
+        except Exception as e:
+            LOGGER.info('接口异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(500, repr(e))
+
+    @classmethod
+    def get_scenario_algorithm_list(cls, request_dist, response):
+        """
+        获取应用场景关联算法列表
+        @param request_dist:  scenarioId、lang
+        @param response: 响应结果
+        @return: 算法列表
+        """
+        scenario_id = request_dist.get('scenarioId', None)
+        lang = request_dist.get('lang', 'en')
+        result_dto = {'scenarioBannerUrl': ''}
+        if not scenario_id:
+            result_dto['algorithmList'] = cls.get_algorithm_list(lang)
+            return response.json(0, result_dto)
+        result_dto['algorithmList'] = cls.get_algorithm_list_by_scenario_id(scenario_id, lang)
+        return response.json(0, result_dto)
 
     @classmethod
     def get_algorithm_banner(cls, response):
@@ -72,7 +234,12 @@ class AlgorithmShopView(View):
         try:
             lang = request_dict.get('lang', 'en')
             uid = request_dict.get('uid', None)
-            algorithm_qs = DeviceAlgorithmExplain.objects.filter(lang=lang).order_by('algorithm_type__sort') \
+            version = request_dict.get('version', 'v1')
+            algorithm_qs = DeviceAlgorithmExplain.objects.filter(lang=lang)
+            types = [0, 1, 3, 4, 5]
+            if version == 'v1':
+                algorithm_qs = algorithm_qs.filter(algorithm_type__type__in=types)
+            algorithm_qs = algorithm_qs.order_by('algorithm_type__sort') \
                 .values('algorithm_type__id', 'algorithm_type__type',
                         'algorithm_type__icon_url',
                         'title', 'subtitle', 'algorithm_type__image_url',
@@ -99,7 +266,7 @@ class AlgorithmShopView(View):
             return response.json(0, algorithm_list)
         except Exception as e:
             print('查询算法小店列表异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
-            return response.json(177, repr(e))
+            return response.json(500, repr(e))
 
     @classmethod
     def get_algorithm_details(cls, request_dict, response):

+ 54 - 62
Controller/CloudStorage.py

@@ -4,7 +4,6 @@ import base64
 import datetime
 import json
 import logging
-import ssl
 import sys
 import time
 from decimal import Decimal
@@ -27,7 +26,7 @@ from Controller.CloudPhoto.CloudServiceController import CloudServiceController
 from Controller.PaymentCycle import Paypal
 from Model.models import Device_Info, Order_Model, Store_Meal, VodHlsModel, UID_Bucket, StsCrdModel, \
     ExperienceContextModel, Pay_Type, CDKcontextModel, Device_User, SysMsgModel, Unused_Uid_Meal, PromotionRuleModel, \
-    VideoPlaybackTimeModel, CouponModel, VodBucketModel, VodHlsSummary, VodHlsTag
+    VideoPlaybackTimeModel, CouponModel, VodBucketModel, VodHlsSummary
 from Object.AWS.AmazonS3Util import AmazonS3Util
 from Object.AWS.S3Email import S3Email
 from Object.AliPayObject import AliPayObject
@@ -42,9 +41,6 @@ from Service.CommonService import CommonService
 from Service.PayService import PaymentService
 from Service.VodHlsService import SplitVodHlsObject
 
-ssl._create_default_https_context = ssl._create_unverified_context
-LOGGER = logging.getLogger('info')
-
 
 # 设备信息添加
 class CloudStorageView(View):
@@ -402,7 +398,7 @@ class CloudStorageView(View):
                         "Effect": "Allow",
                         "Action": "s3:*",
                         "Resource": ["{aws_arn}:::{bucket_name}/{uid_channel}*".
-                                         format(aws_arn=aws_arn, bucket_name=bucket_name, uid_channel=storage)]
+                                     format(aws_arn=aws_arn, bucket_name=bucket_name, uid_channel=storage)]
                     }
                 ]
             }
@@ -478,8 +474,8 @@ class CloudStorageView(View):
                 "dvQsModelOverTime": device_info_qs_time_over,
             })
 
-        # if device_info_qs[0]['vodPrimaryUserID'] != user_id:
-        #     return response.json(10034)
+        if device_info_qs[0]['vodPrimaryUserID'] != user_id:
+            return response.json(10034)
         now_time = int(time.time())
         uid_bucket_qs = UID_Bucket.objects.filter(uid=uid, endTime__gte=now_time, channel=channel).values(
             'bucket_id').order_by('addTime')
@@ -619,16 +615,6 @@ class CloudStorageView(View):
                 return response.json(10, {'msg': '设备未开启云存'})
 
             # 保存云存信息数据
-            # 创建旧表数据
-            VodHlsModel.objects.create(
-                uid=uid,
-                channel=channel,
-                time=start_time,
-                endTime=end_time,
-                bucket_id=bucket_id,
-                fg=fg,
-                sec=sec,
-            )
             # 创建分表数据
             split_vod_hls_obj = SplitVodHlsObject()
             vod_vo, week = split_vod_hls_obj.creat_vod_hls_data(uid=uid, channel=channel, start_time=start_time,
@@ -669,6 +655,7 @@ class CloudStorageView(View):
         uid = request_dict.get('uid', None)
         status = request_dict.get('status', None)
         channel = request_dict.get('channel', None)
+        domain_name = request_dict.get('domain_name', None)
         if not all([uid, status, channel]):
             return response.json(444, 'uid,status,channel')
         device_info_qs = Device_Info.objects.filter(userID_id=user_id, UID=uid, isShare=False, isExist=1).values(
@@ -686,10 +673,13 @@ class CloudStorageView(View):
             return response.json(0)
         uid_obj = UidTokenObject()
         uid_obj.generate(data={'uid': uid, 'channel': channel})
-        uid_tk_url = "{SERVER_DOMAIN_SSL}cloudstorage/getsignsts?uidToken={uidToken}". \
-            format(uidToken=uid_obj.token, SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
-        store_hls_url = "{SERVER_DOMAIN_SSL}cloudstorage/storeplaylist?uidToken={uidToken}". \
-            format(uidToken=uid_obj.token, SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+
+        # 欧洲域名固定返回欧洲域名
+        urls = SERVER_DOMAIN_SSL
+        if domain_name in ['api.zositeche.com', 'api.loocam3.com', 'common.neutral3.com']:
+            urls = 'https://api.zositeche.com/'
+        uid_tk_url = '{}cloudstorage/getsignsts?uidToken={}'.format(urls, uid_obj.token)
+        store_hls_url = '{}cloudstorage/storeplaylist?uidToken={}'.format(urls, uid_obj.token)
         return response.json(0, {'uidTkUrl': uid_tk_url, 'storeHlsUrl': store_hls_url})
 
     @staticmethod
@@ -825,11 +815,12 @@ class CloudStorageView(View):
                         device_name = CommonService.get_full_serial_number(uid, serial_number, device_type)
                     else:
                         device_name = uid
-                    sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功购买云存套餐',
-                                         'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
-                                             "%b %dth,%Y", time.localtime())]
+                    sys_msg_text_list = [
+                        '温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功购买云存套餐',
+                        'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
+                            "%b %dth,%Y", time.localtime())]
                     self.do_vod_msg_notice(uid, channel, userid, lang, sys_msg_text_list, 'SMS_219738485')
-                    red_url = "{SERVER_DOMAIN_SSL}web/paid2/success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+                    red_url = "{}web/paid2/success.html".format(SERVER_DOMAIN_SSL)
                     if lang != 'cn':
                         red_url = red_url.replace('success.html', 'en_success.html')
                     redis_obj.del_data(key=order_id + 'do_notify')
@@ -846,7 +837,7 @@ class CloudStorageView(View):
             if order_qs:
                 order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
             redis_obj.del_data(key=order_id + 'do_notify')
-            red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            red_url = "{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL)
             if lang != 'cn':
                 red_url = red_url.replace('fail.html', 'en_fail.html')
             return HttpResponseRedirect(red_url)
@@ -884,7 +875,7 @@ class CloudStorageView(View):
         promotion_rule_id = ''
         try:
             if not order_id:
-                red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+                red_url = "{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL)
                 if lang != 'cn':
                     red_url = red_url.replace('fail.html', 'en_fail.html')
                 return HttpResponseRedirect(red_url)
@@ -898,7 +889,7 @@ class CloudStorageView(View):
             payers = payment.execute({"payer_id": payer_id})
             logger.info(payers)
             if not payers:
-                red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+                red_url = "{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL)
                 if lang != 'cn':
                     red_url = red_url.replace('fail.html', 'en_fail.html')
                 redis_obj.del_data(key=order_id + 'do_notify')
@@ -978,13 +969,14 @@ class CloudStorageView(View):
                     device_name = CommonService.get_full_serial_number(uid, serial_number, device_type)
                 else:
                     device_name = uid
-                sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功购买云存套餐',
-                                     'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
-                                         "%b %dth,%Y", time.localtime())]
+                sys_msg_text_list = [
+                    '温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功购买云存套餐',
+                    'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
+                        "%b %dth,%Y", time.localtime())]
 
                 self.do_vod_msg_notice(uid, channel, userid, lang, sys_msg_text_list, 'SMS_219738485')
 
-                red_url = "{SERVER_DOMAIN_SSL}web/paid2/success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+                red_url = "{}web/paid2/success.html".format(SERVER_DOMAIN_SSL)
                 if lang != 'cn':
                     red_url = red_url.replace('success.html', 'en_success.html')
                 redis_obj.del_data(key=order_id + 'do_notify')
@@ -995,7 +987,7 @@ class CloudStorageView(View):
             logger.info(repr(e))
             if order_qs:
                 order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
-            red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            red_url = "{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL)
             if lang != 'cn':
                 red_url = red_url.replace('fail.html', 'en_fail.html')
             redis_obj.del_data(key=order_id + 'do_notify')
@@ -1113,9 +1105,10 @@ class CloudStorageView(View):
                         device_name = CommonService.get_full_serial_number(uid, serial_number, device_type)
                     else:
                         device_name = uid
-                    sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功购买云存套餐',
-                                         'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
-                                             "%b %dth,%Y", time.localtime())]
+                    sys_msg_text_list = [
+                        '温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功购买云存套餐',
+                        'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
+                            "%b %dth,%Y", time.localtime())]
                     self.do_vod_msg_notice(uid, channel, userid, lang, sys_msg_text_list, 'SMS_219738485')
                     redis_obj.del_data(key=order_id + 'do_notify')
                     return HttpResponse("<xml>\
@@ -1239,11 +1232,11 @@ class CloudStorageView(View):
 
                 return response.json(0, {"redirectUrl": sub_info['url'], "orderID": order_id})
             # 正常扣款
-            call_clc_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            call_clc_url = "{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL)
             if lang != 'cn':
                 call_clc_url = call_clc_url.replace('fail.html', 'en_fail.html')
-            call_sub_url = "{SERVER_DOMAIN_SSL}cloudstorage/dopaypalcallback?orderID={orderID}&lang={lang}". \
-                format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, orderID=order_id, lang=lang)
+            call_sub_url = "{}cloudstorage/dopaypalcallback?orderID={}&lang={}".format(SERVER_DOMAIN_SSL, order_id,
+                                                                                       lang)
 
             paypalrestsdk.configure(PAYPAL_CRD)
             payment = paypalrestsdk.Payment({
@@ -1281,10 +1274,9 @@ class CloudStorageView(View):
                     out_trade_no=order_id,
                     total_amount=price,
                     subject=subject,
-                    return_url="{SERVER_DOMAIN_SSL}web/paid2/success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL),
-                    notify_url="{SERVER_DOMAIN_SSL}cloudstorage/doalicallback".format(
-                        SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL),
-                    quit_url="{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL),
+                    return_url="{}web/paid2/success.html".format(SERVER_DOMAIN_SSL),
+                    notify_url="{}cloudstorage/doalicallback".format(SERVER_DOMAIN_SSL),
+                    quit_url="{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL),
                     passback_params=quote("lang=" + lang)
                 )
 
@@ -1310,7 +1302,7 @@ class CloudStorageView(View):
 
         elif pay_type == 3:
             pay = WechatPayObject()
-            notify_url = "{SERVER_DOMAIN_SSL}cloudstorage/dowechatnotify".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
+            notify_url = "{}cloudstorage/dowechatnotify".format(SERVER_DOMAIN_SSL)
             content = CommonService.Package_Type(0, content)  # 云存套餐
             # 获取参数
             parameter_dict = pay.get_parameter(order_id, content, float(price) * 100, ip, notify_url,
@@ -1468,35 +1460,35 @@ class CloudStorageView(View):
                     device_name = CommonService.get_full_serial_number(uid, serial_number, device_type)
                 else:
                     device_name = uid
-                sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功购买云存套餐',
-                                     'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
-                                         "%b %dth,%Y", time.localtime())]
+                sys_msg_text_list = [
+                    '温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功购买云存套餐',
+                    'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
+                        "%b %dth,%Y", time.localtime())]
 
-                return_url = "{SERVER_DOMAIN_SSL}cloudstorage/payOK?lang={lang}".format(
-                    SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, lang=lang)
+                return_url = "{}cloudstorage/payOK?lang={}".format(SERVER_DOMAIN_SSL, lang)
                 if pay_type == 10:
                     ExperienceContextModel.objects.create(
                         experience_type=0,
                         uid=uid,
                         do_time=now_time
                     )
-                    return_url = "{SERVER_DOMAIN_SSL}cloudstorage/payOK?paytype=10&lang={lang}".format(
-                        SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, lang=lang)
+                    return_url = "{}cloudstorage/payOK?paytype=10&lang={}".format(SERVER_DOMAIN_SSL, lang)
                     date_time = time.strftime("%Y-%m-%d", time.localtime())
-                    sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功开通云存体验套餐',
-                                         'Dear customer,you already subscribed the free trial cloud storage service successfully for device ' + device_name + ' on ' + time.strftime(
-                                             "%b %dth,%Y", time.localtime())]
+                    sys_msg_text_list = [
+                        '温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功开通云存体验套餐',
+                        'Dear customer,you already subscribed the free trial cloud storage service successfully for device ' + device_name + ' on ' + time.strftime(
+                            "%b %dth,%Y", time.localtime())]
                     sms = 'SMS_222870823'
                 if pay_type == 11:
                     update_dict = {'is_activate': 1, 'order': order_id}
                     CDKcontextModel.objects.filter(cdk=cdk).update(**update_dict)
-                    return_url = "{SERVER_DOMAIN_SSL}cloudstorage/payOK?paytype=11&lang={lang}".format(
-                        SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, lang=lang)
+                    return_url = "{}cloudstorage/payOK?paytype=11&lang={}".format(SERVER_DOMAIN_SSL, lang)
 
                     date_time = time.strftime("%Y-%m-%d", time.localtime())
-                    sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功兑换云存套餐',
-                                         'Dear customer, you already redeemed for the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
-                                             "%b %dth,%Y", time.localtime())]
+                    sys_msg_text_list = [
+                        '温馨提示:尊敬的客户,您的' + device_name + '设备在' + date_time + '已成功兑换云存套餐',
+                        'Dear customer, you already redeemed for the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
+                            "%b %dth,%Y", time.localtime())]
                     sms = 'SMS_219748439'
 
                 self.do_vod_msg_notice(uid, channel, user_id, lang, sys_msg_text_list, sms)
@@ -2000,6 +1992,6 @@ class CloudStorageView(View):
             order_qs.update(**update_dict)
             return response.json(0)
         except Exception as e:
-            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
-            print(e)
+            logger = logging.getLogger('info')
+            logger.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
             return response.json(500, repr(e))

+ 1 - 1
Controller/CloudVod.py

@@ -14,7 +14,7 @@ from django.views.decorators.csrf import csrf_exempt
 from django.views.generic.base import View
 
 from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, OSS_ROLE_ARN, SERVER_DOMAIN, PAYPAL_CRD
-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, OssCrdModel, UID_Bucket, StsCrdModel, \
     VodBucketModel
 from Object.AliPayObject import AliPayObject
 from Object.ResponseObject import ResponseObject

+ 86 - 12
Controller/Cron/CronTaskController.py

@@ -9,7 +9,6 @@
 # @Software: PyCharm
 import datetime
 import logging
-import threading
 import time
 
 import requests
@@ -17,11 +16,12 @@ from django.db import connection, connections, transaction
 from django.db.models import Q, Sum, Count
 from django.views import View
 
-from Ansjer.config import USED_SERIAL_REDIS_LIST, UNUSED_SERIAL_REDIS_LIST
+from Ansjer.config import USED_SERIAL_REDIS_LIST, UNUSED_SERIAL_REDIS_LIST, CONFIG_INFO, CONFIG_US, \
+    RESET_REGION_ID_SERIAL_REDIS_LIST
 from Model.models import Device_User, Device_Info, UidSetModel, UID_Bucket, Unused_Uid_Meal, Order_Model, StsCrdModel, \
     VodHlsModel, ExperienceContextModel, AiService, VodHlsSummary, VideoPlaybackTimeModel, DeviceUserSummary, \
     CountryModel, DeviceTypeModel, OrdersSummary, DeviceInfoSummary, CompanySerialModel, \
-    CloudLogModel, UidCloudStorageCount, UserExModel
+    CloudLogModel, UidCloudStorageCount, UserExModel, DeviceDomainRegionModel
 from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.utils import LocalDateTimeUtil
@@ -144,7 +144,7 @@ class CronDelDataView(View):
         nowTime = int(time.time())
         try:
             cursor = connection.cursor()
-            month_ago_time = nowTime - 30 * 24 * 60 * 60  # 删除1个月前的数据
+            month_ago_time = nowTime - 3 * 30 * 24 * 60 * 60  # 删除3个月前的数据
             sql = 'DELETE FROM `vod_hls` WHERE endTime<{} LIMIT 50000'.format(month_ago_time)
             cursor.execute(sql)
             cursor.close()
@@ -234,6 +234,8 @@ class CronUpdateDataView(View):
             return self.reqUpdateSerialStatus(response)
         elif operation == 'updateSerialStatus':  # 更新序列号状态
             return self.updateSerialStatus(request_dict, response)
+        elif operation == 'reset-region-id':  # 重置地区id
+            return self.reset_region_id(request_dict, response)
         else:
             return response.json(404)
 
@@ -326,24 +328,33 @@ class CronUpdateDataView(View):
     def reqUpdateSerialStatus(cls, response):
         redis_obj = RedisObject()
         logger = logging.getLogger('info')
+
         # 更新已使用序列号其他服务器的状态
         used_serial_redis_list = redis_obj.lrange(USED_SERIAL_REDIS_LIST, 0, -1)  # 读取redis已使用序列号
-        logger.info('---请求更新序列号接口---used_serial_redis_list:{}---status:{}'.format(used_serial_redis_list, 3))
         if used_serial_redis_list:
+            logger.info('---请求更新已使用序列号列表---used_serial_redis_list:{}'.format(used_serial_redis_list))
             used_serial_redis_list = [str(i, 'utf-8') for i in used_serial_redis_list]
             cls.do_request_function(used_serial_redis_list, 3)
+
         # 更新未使用序列号其他服务器的状态
         unused_serial_redis_list = redis_obj.lrange(UNUSED_SERIAL_REDIS_LIST, 0, -1)  # 读取redis未使用序列号
-        logger.info('---请求更新序列号接口---unused_serial_redis_list:{}---status:{}'.format(unused_serial_redis_list, 1))
         if unused_serial_redis_list:
+            logger.info('---请求更新未使用序列号列表---unused_serial_redis_list:{}'.format(unused_serial_redis_list))
             unused_serial_redis_list = [str(i, 'utf-8') for i in unused_serial_redis_list]
             cls.do_request_function(unused_serial_redis_list, 1)
+
+        # 重置地区id
+        reset_region_id_serial_redis_list = redis_obj.lrange(RESET_REGION_ID_SERIAL_REDIS_LIST, 0, -1)  # 读取redis未使用序列号
+        if reset_region_id_serial_redis_list:
+            logger.info('---请求重置地区id的序列号列表---:{}'.format(reset_region_id_serial_redis_list))
+            reset_region_id_serial_redis_list = [str(i, 'utf-8') for i in reset_region_id_serial_redis_list]
+            cls.do_request_reset_region_id(reset_region_id_serial_redis_list)
         return response.json(0)
 
     @staticmethod
     def do_request_function(serial_redis_list, status):
         """
-        请求更新序列号线程
+        请求更新序列号状态
         @param serial_redis_list: 序列号redis列表
         @param status: 状态, 1: 未使用, 3: 已占用
         """
@@ -357,16 +368,34 @@ class CronUpdateDataView(View):
         logger = logging.getLogger('info')
         logger.info('---请求更新序列号线程---data:{},orders_domain_name_list:{}'.format(data, orders_domain_name_list))
         try:
-            flag = 0  # 请求标志位
+            requests_failed_flag = False  # 请求失败标志位
             for domain_name in orders_domain_name_list:
                 url = '{}cron/update/updateSerialStatus'.format(domain_name)
                 response = requests.post(url=url, data=data, timeout=5)
-                logger.info('---请求更新序列号响应时间---time:{}'.format(response.elapsed.total_seconds()))
+                logger.info('---请求更新序列号响应时间---:{}'.format(response.elapsed.total_seconds()))
                 result = response.json()
-                if result['result_code'] != 0:  # 请求失败修改标志位
-                    flag = 1
+                if result['result_code'] != 0:  # 请求失败标志位置位
+                    requests_failed_flag = True
                     break
-            if flag == 0:  # 请求成功删除redis序列号
+
+                # 状态为未使用,重置美洲服的地区id
+                if status == 1:     # 美洲服直接更新
+                    if CONFIG_INFO == CONFIG_US:
+                        DeviceDomainRegionModel.objects.filter(~Q(region_id=0), serial_number__in=serial_redis_list).\
+                            update(region_id=0)
+                    else:   # 其他服请求到美洲服更新
+                        req_url = 'https://www.dvema.com/cron/update/reset-region-id'
+                        req_data = {
+                            'serial_redis_list': str(serial_redis_list)
+                        }
+                        response = requests.post(url=req_url, data=req_data, timeout=5)
+                        logger.info('---请求重置地区id响应时间---:{}'.format(response.elapsed.total_seconds()))
+                        result = response.json()
+                        if result['result_code'] != 0:  # 请求失败标志位置位
+                            requests_failed_flag = True
+                            break
+
+            if not requests_failed_flag:  # 请求成功删除redis序列号
                 if status == 1:
                     for i in serial_redis_list:
                         redis_obj.lrem(UNUSED_SERIAL_REDIS_LIST, 0, i)
@@ -376,6 +405,30 @@ class CronUpdateDataView(View):
         except Exception as e:
             logger.info('---更新序列号状态异常---:{}'.format(repr(e)))
 
+    @staticmethod
+    def do_request_reset_region_id(reset_region_id_serial_redis_list):
+        """
+        请求重置地区id
+        @param reset_region_id_serial_redis_list: 序列号redis列表
+        """
+        redis_obj = RedisObject()
+        logger = logging.getLogger('info')
+        requests_failed_flag = False  # 请求失败标志位
+        data = {
+            'serial_redis_list': str(reset_region_id_serial_redis_list),
+        }
+        url = 'https://www.dvema.com/cron/update/reset-region-id'
+
+        try:
+            response = requests.post(url=url, data=data, timeout=5)
+            result = response.json()
+            if result['result_code'] != 0:  # 请求失败标志位置位
+                requests_failed_flag = True
+            if not requests_failed_flag:  # 请求成功删除redis序列号
+                for serial in reset_region_id_serial_redis_list:
+                    redis_obj.lrem(RESET_REGION_ID_SERIAL_REDIS_LIST, 0, serial)
+        except Exception as e:
+            logger.info('---请求重置地区id异常---:{}'.format(repr(e)))
 
     @staticmethod
     def updateSerialStatus(request_dict, response):
@@ -402,6 +455,27 @@ class CronUpdateDataView(View):
             logger.info('---更新序列号状态异常---:{}'.format(repr(e)))
             return response.json(500)
 
+    @staticmethod
+    def reset_region_id(request_dict, response):
+        """
+        重置地区id
+        @param request_dict: 请求参数
+        @request_dict serial_redis_list: 序列号redis列表
+        @param response: 响应对象
+        """
+        serial_redis_list = request_dict.get('serial_redis_list', None)
+        logger = logging.getLogger('info')
+        logger.info('---重置地区id参数---serial_redis_list:{}'.format(serial_redis_list))
+        if not serial_redis_list:
+            return response.json(444)
+        try:
+            serial_redis_list = eval(serial_redis_list)
+            DeviceDomainRegionModel.objects.filter(serial_number__in=serial_redis_list).update(region_id=0)
+            return response.json(0)
+        except Exception as e:
+            logger.info('---重置地区id异常---:{}'.format(repr(e)))
+            return response.json(500)
+
 
 class CronCollectDataView(View):
     def get(self, request, *args, **kwargs):

+ 9 - 18
Controller/DetectController.py

@@ -26,7 +26,7 @@ from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, DETECT_PUSH
     JPUSH_CONFIG, FCM_CONFIG, APNS_CONFIG, \
     BASE_DIR, APNS_MODE, SERVER_TYPE
 from Ansjer.config import PUSH_REDIS_ADDRESS
-from Model.models import Device_Info, VodHlsModel, Equipment_Info, UidSetModel, UidPushModel, SysMsgModel, \
+from Model.models import Device_Info, Equipment_Info, UidSetModel, UidPushModel, SysMsgModel, \
     VodBucketModel
 from Object.ETkObject import ETkObject
 from Object.RedisObject import RedisObject
@@ -190,6 +190,7 @@ class DetectControllerView(View):
         # 设备语言
         lang = request_dict.get('lang', 'en')
         tz = request_dict.get('tz', '0')
+        domain_name = request_dict.get('domain_name', None)
         # 消息提醒功能新增
 
         # 如果传空上来,就默认为0
@@ -207,17 +208,6 @@ class DetectControllerView(View):
         # 判断推送类型对应key是否存在
         print('push_type:', push_type)
 
-        if push_type == '0':
-            if appBundleId not in APNS_CONFIG.keys():
-                return response.json(904)
-        elif push_type == '1':
-            if appBundleId not in FCM_CONFIG.keys():
-                return response.json(904)
-        elif push_type == '2':
-            if appBundleId not in JPUSH_CONFIG.keys():
-                return response.json(904)
-        else:
-            return response.json(173)
         dvqs = Device_Info.objects.filter(userID_id=userID, UID=uid)
         status = int(status)
         # 获取用户区域
@@ -313,15 +303,18 @@ class DetectControllerView(View):
                 # utko.generate(data={'uid': uid})
                 etkObj = ETkObject(etk='')
                 etk = etkObj.encrypt(uid)
-                detectUrl = "{DETECT_PUSH_DOMAIN}notify/push?etk={etk}". \
-                    format(etk=etk, DETECT_PUSH_DOMAIN=DETECT_PUSH_DOMAIN)
+                if domain_name in ['api.zositeche.com', 'api.loocam3.com', 'common.neutral3.com']:
+                    detectUrl = 'http://push.zositeche.com/notify/push?etk={etk}'.format(etk=etk)
+                else:
+                    detectUrl = "{DETECT_PUSH_DOMAIN}notify/push?etk={etk}". \
+                        format(etk=etk, DETECT_PUSH_DOMAIN=DETECT_PUSH_DOMAIN)
                 return response.json(0, {'detectUrl': detectUrl})
         else:
             return response.json(14)
 
     def do_delete_redis(self, uid, detect_interval=0):
         keyPattern = '{uid}*'.format(uid=uid)
-        redisObj = RedisObject(db=6, SERVER_HOST=PUSH_REDIS_ADDRESS)
+        redisObj = RedisObject()
         keys = redisObj.get_keys(keyPattern)
         if keys:
             for key in keys:
@@ -342,10 +335,8 @@ class DetectControllerView(View):
         if dvqs.exists():
             uid_set_qs = UidSetModel.objects. \
                 filter(uid=uid, uidpushmodel__userID_id=userID)
-            # redisObj = RedisObject(db=8)
-            # redisObj.del_data(key='uid_qs_' + userID)
             if uid_set_qs.exists():
-                uid_set_qs.update(interval=int(interval))
+                uid_set_qs.update(detect_interval=int(interval))
             else:
                 return response.json(173)
         else:

+ 38 - 23
Controller/DetectControllerV2.py

@@ -79,6 +79,7 @@ class DetectControllerViewV2(View):
         company_secrete = request_dict.get('company_secrete', None)
         region = request_dict.get('region', None)  # app必须传:1:国外,2:国内
         electricity_status = request_dict.get('electricity_status', None)
+        domain_name = request_dict.get('domain_name', None)
         if not region:
             return response.json(444, 'region')
         region = int(region)
@@ -125,9 +126,9 @@ class DetectControllerViewV2(View):
             # 检测类型
             if 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
+            # 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:
                 interval = int(interval)
@@ -161,21 +162,34 @@ class DetectControllerViewV2(View):
 
             # 初始化UidPushModel推送表
             if electricity_status:
-                uid_push_create_dict = {
-                    'uid_set_id': uid_set_id,
-                    'userID_id': userID,
-                    'appBundleId': appBundleId,
-                    'app_type': app_type,
-                    'push_type': push_type,
-                    'token_val': token_val,
-                    'm_code': m_code,
-                    'addTime': nowTime,
-                    'updTime': nowTime,
-                    'lang': lang,
-                    'tz': tz
-                }
-                # 绑定设备推送
-                UidPushModel.objects.create(**uid_push_create_dict)
+                uid_push_qs = UidPushModel.objects.filter(userID_id=userID, m_code=m_code, uid_set__uid=uid)
+                if uid_push_qs.exists():
+                    uid_push_update_dict = {
+                        'appBundleId': appBundleId,
+                        'app_type': app_type,
+                        'push_type': push_type,
+                        'token_val': token_val,
+                        'updTime': nowTime,
+                        'lang': lang,
+                        'tz': tz
+                    }
+                    uid_push_qs.update(**uid_push_update_dict)
+                else:
+                    uid_push_create_dict = {
+                        'uid_set_id': uid_set_id,
+                        'userID_id': userID,
+                        'appBundleId': appBundleId,
+                        'app_type': app_type,
+                        'push_type': push_type,
+                        'token_val': token_val,
+                        'm_code': m_code,
+                        'addTime': nowTime,
+                        'updTime': nowTime,
+                        'lang': lang,
+                        'tz': tz
+                    }
+                    # 绑定设备推送
+                    UidPushModel.objects.create(**uid_push_create_dict)
                 return response.json(0)
 
             if status == 0:
@@ -226,6 +240,9 @@ class DetectControllerViewV2(View):
                 else:
                     url = DETECT_PUSH_DOMAIN_JIUAN
                     urls = DETECT_PUSH_DOMAINS_JIUAN
+                if domain_name in ['api.zositeche.com', 'api.loocam3.com', 'common.neutral3.com']:
+                    url = 'http://push.zositeche.com/'
+                    urls = 'https://push.zositeche.com/'
                 detectUrl = "{DETECT_PUSH_DOMAIN}notifyV2/push?etk={etk}&company_secrete={company_secrete}&region={region}". \
                     format(etk=etk, company_secrete=company_secrete, DETECT_PUSH_DOMAIN=url, region=region)
                 detectUrls = "{DETECT_PUSH_DOMAIN_V2}notifyV2/push?etk={etk}&company_secrete={company_secrete}&region={region}". \
@@ -238,7 +255,7 @@ class DetectControllerViewV2(View):
 
     def do_delete_redis(self, uid, detect_interval=0):
         keyPattern = '{uid}*'.format(uid=uid)
-        redisObj = RedisObject(db=6, SERVER_HOST=PUSH_REDIS_ADDRESS)
+        redisObj = RedisObject()
         keys = redisObj.get_keys(keyPattern)
         if keys:
             for key in keys:
@@ -418,10 +435,8 @@ class DetectControllerViewV2(View):
         if dvqs.exists():
             uid_set_qs = UidSetModel.objects. \
                 filter(uid=uid, uidpushmodel__userID_id=userID)
-            # redisObj = RedisObject(db=8)
-            # redisObj.del_data(key='uid_qs_' + userID)
             if uid_set_qs.exists():
-                uid_set_qs.update(interval=int(interval))
+                uid_set_qs.update(detect_interval=int(interval))
             else:
                 return response.json(173)
         else:
@@ -474,7 +489,7 @@ class PushNotificationView(View):
         eto = ETkObject(etk)
         uid = eto.uid
         if len(uid) == 20:
-            redisObj = RedisObject(db=6)
+            redisObj = RedisObject()
             # pkey = '{uid}_{channel}_ptl'.format(uid=uid, channel=channel)
             pkey = '{uid}_ptl'.format(uid=uid)
             ykey = '{uid}_redis_qs'.format(uid=uid)

+ 0 - 2
Controller/DeviceManage.py

@@ -102,8 +102,6 @@ class DeviceManage(View):
 
     def delete(self, request_dict, userID, response):
         own_perm = ModelService.check_perm(userID=userID, permID=10)
-        # redisObj = RedisObject(db=8)
-        # redisObj.del_data(key='uid_qs_' + userID)
         if own_perm is True:
             id = request_dict.get('id', None)
             if id:

+ 0 - 4
Controller/DeviceShare.py

@@ -185,8 +185,6 @@ class DeviceShareView(View):
                     sharerDvqs.data_joined = None
                     sharerDvqs.save()
                     UserDeviceShareView.qrcode_share_channel_permission_save(userID, UID)
-                    # redisObj = RedisObject(db=8)
-                    # redisObj.del_data(key='uid_qs_' + userID)
                 except Exception as e:
                     return response.json(10, repr(e))
                 else:
@@ -247,8 +245,6 @@ class DeviceShareView(View):
         id = request_dict.get('id', None)
         if id:
             try:
-                # redisObj = RedisObject(db=8)
-                # redisObj.del_data(key='uid_qs_' + userID)
                 Device_Info.objects.filter(id=id, primaryUserID=userID).delete()
             except Exception as e:
                 return response.json(10, repr(e))

+ 29 - 0
Controller/EquipmentInfo.py

@@ -53,6 +53,8 @@ class EquipmentInfo(View):
             return self.add_info(request_dict, userID, response)
         elif operation == 'update':
             return self.update_info(request_dict, userID, response)
+        elif operation == 'update-answer-status':
+            return self.update_answer_status(request_dict, userID, response)
         elif operation == 'delete':
             return self.delete_info(request_dict, userID, response)
         elif operation == 'findByTime':
@@ -207,6 +209,33 @@ class EquipmentInfo(View):
             else:
                 return response.json(444)
 
+    @staticmethod
+    def update_answer_status(request_dict, user_id, response):
+        """
+        更新一键通话消息状态为已接听
+        @param request_dict:
+        @param user_id: 用户id
+        @param response:
+        @return:
+        """
+        ei_id = request_dict.getlist('id', None)
+        if ei_id is None:
+            return response.json(444)
+        count = 0
+        tab_val = int(ei_id[0:1])
+        ei_id = int(ei_id[1:])
+        eq = EquipmentInfoService.get_equipment_info_model('', tab_val)
+        eq = eq.filter(id=ei_id)
+        if not eq.exists():
+            return response.json(173)
+        own_dev = ModelService.check_own_device(user_id, eq[0].device_uid)
+        if own_dev:
+            count += 1
+            eq.update(answer_status=1)
+            return response.json(0, {'update_success': count})
+        else:
+            return response.json(14)
+
     def delete_info(self, request_dict, userID, response):
         id_list = request_dict.getlist('id[]', None)
         if id_list is None or len(id_list) < 1:

+ 2 - 14
Controller/EquipmentManager.py

@@ -92,8 +92,6 @@ def addNewUserEquipmentInterface(request):
         if dValid:
             return response.json(174)
         else:
-            # redisObj = RedisObject(db=8)
-            # redisObj.del_data(key='uid_qs_' + userID)
             UID = deviceData.get('UID', '')
             re_uid = re.compile(r'^[A-Za-z0-9]{20}$')
             if re_uid.match(UID):
@@ -162,9 +160,6 @@ def delUserEquipmentInterface(request):
     # 主用户删除设备全部删除
     try:
         dv_qs = Device_Info.objects.filter(userID_id=userID, id=id)
-        # redisObj = RedisObject(db=8)
-        # redisObj.del_data(key='uid_qs_' + userID)
-
         if dv_qs.exists():
             uid = dv_qs[0].UID
             asy = threading.Thread(target=ModelService.add_log,
@@ -659,8 +654,6 @@ def admin_addInterface(request):
         else:
             UID = deviceData.get('UID', '')
             re_uid = re.compile(r'^[A-Za-z0-9]{20}$')
-            # redisObj = RedisObject(db=8)
-            # redisObj.del_data(key='uid_qs_' + userID)
             if re_uid.match(UID):
                 userDevice = Device_Info(id=CommonService.getUserID(getUser=False), userID_id=userID,
                                          **deviceData)
@@ -740,9 +733,6 @@ def admin_modifyInterface(request):
         return response.json(404)
 
     deviceData = json.loads(deviceContent)
-    print(deviceData['UID'])
-    # redisObj = RedisObject(db=8)
-    # redisObj.del_data(key='uid_qs_' + userID)
     dValid = Device_Info.objects.filter(userID_id=userID, UID=deviceData['UID'])
     if dValid.exists():
         dValid_dict = CommonService.qs_to_dict(dValid)
@@ -834,7 +824,7 @@ def deleteInterface(request):
                 DetectControllerView().do_delete_redis(uid)
                 if up_qs.count() > 1:
                     UidPushModel.objects.filter(uid_set__uid=uid, userID_id=userID).delete()
-                    redisObj = RedisObject(db=6, SERVER_HOST=PUSH_REDIS_ADDRESS)
+                    redisObj = RedisObject()
                     ykey = '{uid}_redis_qs'.format(uid=uid)
                     if ykey:
                         redisObj.del_data(key=ykey)
@@ -935,7 +925,7 @@ def batchDeleteInterface(request):
                 DetectControllerView().do_delete_redis(uid)
                 if up_qs.count() > 1:
                     UidPushModel.objects.filter(uid_set__uid=uid, userID_id=userID).delete()
-                    redisObj = RedisObject(db=6, SERVER_HOST=PUSH_REDIS_ADDRESS)
+                    redisObj = RedisObject()
                     ykey = '{uid}_redis_qs'.format(uid=uid)
                     if ykey:
                         redisObj.del_data(key=ykey)
@@ -1238,8 +1228,6 @@ def update_uid_set(request):
         userID = tko.userID
         nowTime = int(time.time())
         dvqs = Device_Info.objects.filter(userID_id=userID)
-        # redisObj = RedisObject(db=8)
-        # redisObj.del_data(key='uid_qs_' + userID)
         if dvqs.exists():
             us_qs = UidSetModel.objects.filter(uid=uid)
             if us_qs.exists():

+ 66 - 5
Controller/EquipmentManagerV3.py

@@ -11,14 +11,15 @@ from django.db import transaction
 from django.db.models import Q
 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, SERVER_DOMAIN_LIST, SERVER_DOMAIN_TEST, \
+    SERVER_DOMAIN_CN, SERVER_DOMAIN_US, SERVER_DOMAIN_EUR
 from Controller.CheckUserData import RandomStr
 from Controller.DeviceConfirmRegion import Device_Region
 from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
 from Controller.UnicomCombo.UnicomComboController import UnicomComboView
 from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidChannelSetModel, \
     Device_User, iotdeviceInfoModel, UIDCompanySerialModel, UnicomDeviceInfo, CountryModel, \
-    DeviceCloudPhotoInfo
+    DeviceCloudPhotoInfo, UidPushModel
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -91,12 +92,24 @@ class EquipmentManagerV3(View):
         family_id = request_dict.get('familyId', None)
         room_id = request_dict.get('roomId', None)
 
+        m_code = request_dict.get('m_code', None)
+        appBundleId = request_dict.get('appBundleId', None)
+        app_type = request_dict.get('app_type', None)
+        push_type = request_dict.get('push_type', None)
+        token_val = request_dict.get('token_val', None)
+        lang = request_dict.get('lang', 'en')
+        tz = request_dict.get('tz', '0')
+
         if not NickName:
             NickName = UID[:6]
 
         if not all([UID, NickName, View_Account, Type, ChannelIndex]):  # Type和ChannelIndex可能为0
             return response.json(444, {'param': 'UID, NickName, View_Account, Type, ChannelIndex'})
 
+        if tz == '':
+            tz = 0
+        else:
+            tz = tz.replace("GMT", "")
         Type = int(Type)
         ChannelIndex = int(ChannelIndex)
 
@@ -116,7 +129,10 @@ class EquipmentManagerV3(View):
         View_Password = '' if Type in dvr_type_list else 'admin'
 
         id = CommonService.getUserID(getUser=False)
-        userName = Device_User.objects.get(userID=userID).username
+        device_user_qs = Device_User.objects.filter(userID=userID).values('username')
+        if not device_user_qs.exists():
+            return response.json(173)
+        userName = device_user_qs[0]['username']
         main_exist = Device_Info.objects.filter(UID=UID)
         main_exist = main_exist.filter(~Q(vodPrimaryUserID='')).values('vodPrimaryUserID', 'vodPrimaryMaster')
 
@@ -205,6 +221,36 @@ class EquipmentManagerV3(View):
                 UidSet = UidSetModel.objects.create(**uid_set_create_dict)
                 UidSet_id = UidSet.id
 
+            if all([token_val, m_code, appBundleId, app_type]):
+                uid_push_qs = UidPushModel.objects.filter(userID_id=userID, m_code=m_code, uid_set__uid=UID)
+                if uid_push_qs.exists():
+                    uid_push_update_dict = {
+                        'appBundleId': appBundleId,
+                        'app_type': app_type,
+                        'push_type': push_type,
+                        'token_val': token_val,
+                        'updTime': nowTime,
+                        'lang': lang,
+                        'tz': tz
+                    }
+                    uid_push_qs.update(**uid_push_update_dict)
+                else:
+                    uid_push_create_dict = {
+                        'uid_set_id': UidSet_id,
+                        'userID_id': userID,
+                        'appBundleId': appBundleId,
+                        'app_type': app_type,
+                        'push_type': push_type,
+                        'token_val': token_val,
+                        'm_code': m_code,
+                        'addTime': nowTime,
+                        'updTime': nowTime,
+                        'lang': lang,
+                        'tz': tz
+                    }
+                    # 绑定设备推送
+                    UidPushModel.objects.create(**uid_push_create_dict)
+
             # 查询uid_channel表有无该uid的数据
             uid_channel_set = UidChannelSetModel.objects.filter(uid_id=UidSet_id)
             if not uid_channel_set.exists():
@@ -316,6 +362,8 @@ class EquipmentManagerV3(View):
     def do_batch_add(self, userID, request_dict, response, request):
         # 批量添加设备
         uidContent = request_dict.get('uidContent', None)
+        family_id = request_dict.get('familyId', None)
+        room_id = request_dict.get('roomId', None)
 
         if not uidContent:
             return response.json(444, {'param': 'uidContent'})
@@ -357,7 +405,10 @@ class EquipmentManagerV3(View):
                         device_info_qs.delete()
 
                 id = CommonService.getUserID(getUser=False)
-                userName = Device_User.objects.get(userID=userID).username
+                device_user_qs = Device_User.objects.filter(userID=userID).values('username')
+                if not device_user_qs.exists():
+                    return response.json(173)
+                userName = device_user_qs[0]['username']
                 main_exist = Device_Info.objects.filter(UID=UID)
                 main_exist = main_exist.filter(~Q(vodPrimaryUserID='')).values('vodPrimaryUserID', 'vodPrimaryMaster')
 
@@ -464,6 +515,9 @@ class EquipmentManagerV3(View):
                                          version=version,
                                          vodPrimaryUserID=vodPrimaryUserID, vodPrimaryMaster=vodPrimaryMaster)
                 userDevice.save()
+                # 添加到家庭房间
+                if family_id:
+                    EquipmentFamilyView.family_room_device_save(family_id, room_id, userDevice.id, Type)
                 uid_serial_qs = UIDCompanySerialModel.objects.filter(uid__uid=UID)
                 if uid_serial_qs.exists():
                     uid_serial = uid_serial_qs[0]
@@ -692,6 +746,13 @@ class EquipmentManagerV3(View):
                 p['uid_version'] = ''
                 p['ucode'] = ''
             p['View_Password'] = self.encrypt_pwd(p['View_Password'])
+
+            # 判断设备是否支持4G
+            uid_set_qs =UidSetModel.objects.filter(uid=p['UID']).values('mobile_4g')
+            if uid_set_qs.exists():
+                uid_set_qs = uid_set_qs.first()
+                if uid_set_qs['mobile_4g'] == 1:
+                    p['isCameraOpenCloud'] = 0
             data.append(p)
         result = data
         return response.json(0, result)
@@ -950,7 +1011,7 @@ class EquipmentManagerV3(View):
         if dvq.exists():
             qs = Device_User.objects.filter(userID=dvq[0]['vodPrimaryUserID']).values('userID', 'NickName', 'username',
                                                                                       'userEmail', 'phone')
-            NickName = qs[0]['username']
+            NickName = qs[0]['NickName']
             phone = qs[0]['phone']
             username = qs[0]['username']
             qs = CommonService.qs_to_list(qs)

+ 1 - 1
Controller/EquipmentStatus.py

@@ -113,7 +113,7 @@ def getTZ(request):
         uid = c.decode('utf-8')
         if len(uid) == 20:
             print(uid)
-            redisObject = RedisObject(db=7)
+            redisObject = RedisObject()
             data = redisObject.get_data(key=ip)
             if data:
                 info = json.loads(data)

+ 0 - 7
Controller/FileController.py

@@ -95,18 +95,11 @@ class UploadUIDFileView(View):
         mac = MacModel.objects.filter().values('id', 'value', 'is_active')[0]
         if not mac['is_active']:
             return response.json(175)
-        # redisObject = RedisObject(db=3)
         key = ''
         tmpMac = mac['value']
         savePoint = None
         for item in keys:
             key = item.strip()
-            # value = redisObject.get_data(key)
-            # if value is False:
-            #     # redisObject.set_data(key, '1', 600)
-            # else:
-            #     duplicate.append(key)
-            #     continue
             bulk.append(UIDModel(
                 uid=item.strip(),
                 uid_extra='',

+ 29 - 0
Controller/InitController.py

@@ -0,0 +1,29 @@
+# @Author    : Rocky
+# @File      : InitController.py
+# @Time      : 2023/4/11 17:26
+from django.http import HttpResponse
+from django.views import View
+
+from Object.ResponseObject import ResponseObject
+
+
+class InitView(View):
+
+    def get(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.GET, operation)
+
+    def post(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        return self.validation(request.POST, operation)
+
+    def validation(self, request_dict, operation):
+        if operation == 'health-check':  # 负载均衡器健康检测接口
+            return self.health_check(request_dict)
+
+    @staticmethod
+    def health_check(request_dict):
+        response = ResponseObject()
+        return response.json(0)

+ 7 - 7
Controller/LogManager.py

@@ -9,7 +9,7 @@ from Service.ModelService import ModelService
 import time,os
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
-from Ansjer.config import BASE_DIR
+from Ansjer.config import BASE_DIR, CONFIG_INFO, CONFIG_CN
 
 
 def StatisticsData(request):
@@ -230,7 +230,7 @@ def errorPath(request, **kwargs):
     <meta charset="UTF-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Document</title>
+    <title>珠海安士佳电子有限公司</title>
     <link rel="stylesheet" href="index.css" </head>
 
     <body>
@@ -260,15 +260,15 @@ def errorPath(request, **kwargs):
         ></div>
         <div class="list con">
             <div class="item">
-                <img src="http://proff01a9a1.pic12.ysjianzhan.cn/upload/3.jpg">
+                <img src="https://ansjerfilemanager.s3.cn-northwest-1.amazonaws.com.cn/app/static/3.jpg">
                 <p>无线基站套装</p>
             </div>
             <div class="item">
-                <img src="http://proff01a9a1.pic12.ysjianzhan.cn/upload/1-1-C1.jpg">
+                <img src="https://ansjerfilemanager.s3.cn-northwest-1.amazonaws.com.cn/app/static/1-1-C1.jpg">
                 <p>C1</p>
             </div>
             <div class="item">
-                <img src="http://proff01a9a1.pic12.ysjianzhan.cn/upload/1-1-306.jpg">
+                <img src="https://ansjerfilemanager.s3.cn-northwest-1.amazonaws.com.cn/app/static/1-1-306.jpg">
                 <p>C306</p>
             </div>
         </div>
@@ -382,7 +382,7 @@ ul {
 
 .banner {
     height: 380px;
-    background: url('http://proff01a9a1.pic12.ysjianzhan.cn/upload/i0ja.jpg') no-repeat center;
+    background: url('https://ansjerfilemanager.s3.cn-northwest-1.amazonaws.com.cn/app/static/backdrop.jpg') no-repeat center;
     background-size: cover;
 }
 
@@ -448,7 +448,7 @@ ul {
 </style>
     """
 
-    if os.environ.get('DJANGO_SETTINGS_MODULE') == 'Ansjer.cn_config.formal_settings':
+    if CONFIG_INFO == CONFIG_CN:
         return HttpResponse(html)
     response = ResponseObject()
     return response.json(414)

+ 0 - 5
Controller/PctestController.py

@@ -527,11 +527,6 @@ class TokenObject1:
             self.lang = res.get('lang', None)
             self.job = res.get('job', None)
             self.user = res.get('user', '')
-            # 刷新登录时间
-            # if self.userID:
-            #     print(self.user)
-            #     redisObj = RedisObject(db=3)
-            #     redisObj.set_data(key=self.userID, val=self.user, expire=300)
 
         except jwt.ExpiredSignatureError as e:
             print('过期')

+ 14 - 11
Controller/RegionController.py

@@ -332,22 +332,25 @@ class RegionView(View):
                 country_qs = country_qs.annotate(api=F('country__region__zosi_api'))
             elif 'Loocam' in app_name:
                 country_qs = country_qs.annotate(api=F('country__region__loocam_api'))
+            elif '新中性' in app_name:
+                country_qs = country_qs.annotate(api=F('country__region__neutral_api'))
             else:
                 country_qs = country_qs.annotate(api=F('country__region__api'))
             country_qs = country_qs.values('country_id', 'country_name', 'api', 'push_api').order_by('country_id')
 
-            # app中国返回美洲域名
+            # app选择中国且不为中性,返回美洲域名
             if is_app:
-                for country in country_qs:
-                    if country['country_id'] == 1:
-                        country['push_api'] = 'https://push.dvema.com/'
-                        if 'Zosi' in app_name:
-                            country['api'] = 'https://api.zositech2.com/'
-                        elif 'Loocam' in app_name:
-                            country['api'] = 'https://api.loocam2.com/'
-                        else:
-                            country['api'] = 'https://www.dvema.com/'
-                        break
+                if '新中性' not in app_name:
+                    for country in country_qs:
+                        if country['country_id'] == 1:
+                            country['push_api'] = 'https://push.dvema.com/'
+                            if 'Zosi' in app_name:
+                                country['api'] = 'https://api.zositech2.com/'
+                            elif 'Loocam' in app_name:
+                                country['api'] = 'https://api.loocam2.com/'
+                            else:
+                                country['api'] = 'https://www.dvema.com/'
+                            break
             # AVSS
             else:
                 for country in country_qs:

+ 18 - 5
Controller/SensorGateway/EquipmentFamilyController.py

@@ -17,9 +17,10 @@ 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 Controller.SensorGateway.SmartSocketController import SmartSocketView
 from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidChannelSetModel, \
     iotdeviceInfoModel, UIDModel, Device_User, UserFamily, FamilyMember, FamilyMemberPermission, \
-    FamilyRoomDevice, FamilyRoom, FamilyMemberJoin, GatewaySubDevice, CountryModel
+    FamilyRoomDevice, FamilyRoom, FamilyMemberJoin, GatewaySubDevice, CountryModel, SocketInfo
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -216,7 +217,14 @@ class EquipmentFamilyView(View):
                         'tb_country': country
                     }
                     UidSetModel.objects.create(**uid_set_create_dict)
-                return response.json(0)
+                if int(device_type) == 201:  # 添加插座信息
+                    SmartSocketView.save_socket_switch(device_id, serial_number, 0)
+                res = {
+                    'deviceId': device_id,
+                    'nickName': nick_name,
+                    'serialNumber': serial_number
+                }
+                return response.json(0, res)
         except Exception as e:
             print(e)
             return response.json(177, repr(e))
@@ -764,7 +772,7 @@ class EquipmentFamilyView(View):
             'created_time': now_time
         }
 
-        category = 0 if device_type == 200 else 1
+        category = 0 if device_type == 200 or 201 else 1
         data['category'] = category
         # 查询类别排序
         family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=int(family_id), category=category).values(
@@ -795,7 +803,7 @@ class EquipmentFamilyView(View):
                 for item in device_info_qs:
                     device_id = item['id']
                     device_type = item['Type']
-                    if device_type == 200:
+                    if device_type == 200 or 201:
                         category = 0
                     else:
                         category = 1
@@ -1060,7 +1068,12 @@ class EquipmentFamilyView(View):
                             device_qs['data_joined'] = device_qs['data_joined'].strftime("%Y-%m-%d %H:%M:%S")
                         else:
                             device_qs['data_joined'] = ''
-                    if device_qs['Type'] == 200:
+                    if device_qs['Type'] == 200 or device_qs['Type'] == 201:
+                        if device_qs['Type'] == 201:
+                            socket_info_qs = SocketInfo.objects.filter(device_id=device_qs['id']).values(
+                                'status')
+                            device_qs['socketStatus'] = socket_info_qs.first()[
+                                'status'] if socket_info_qs.exists() else ''
                         gateways.append(device_qs)
                     else:
                         cameras.append(device_qs)

+ 99 - 4
Controller/SensorGateway/GatewayDeviceController.py

@@ -7,15 +7,18 @@
 @Software: PyCharm
 """
 import time
+import datetime
+import logging
 
 from django.db import transaction
 from django.db.models import Q
 from django.views.generic.base import View
+from decimal import Decimal
 
 from Ansjer.Config.gatewaySensorConfig import SMART_SCENE_TOPIC
 from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
 from Model.models import FamilyRoomDevice, FamilyRoom, GatewaySubDevice, Device_Info, UserFamily, FamilyMember, \
-    UidSetModel, iotdeviceInfoModel, SmartScene, SceneLog
+    UidSetModel, iotdeviceInfoModel, SmartScene, SceneLog, SocketInfo, SocketPowerStatistics, SocketSchedule
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -163,6 +166,18 @@ class GatewayDeviceView(View):
                         uid_set_qs = UidSetModel.objects.filter(uid=device_qs.first().UID)
                         if uid_set_qs.exists():
                             uid_set_qs.delete()
+                        socket_info_qs = SocketInfo.objects.filter(device_id=device_id)
+                        if socket_info_qs.exists():
+                            # 设备在不在线, 都发布重置
+                            serial_number = device_qs.first().serial_number
+                            cls.reset_device(serial_number)
+                            socket_info_qs.delete()
+                            socket_power_qs = SocketPowerStatistics.objects.filter(device_id=device_id)
+                            if socket_power_qs.exists():
+                                socket_power_qs.delete()
+                            socket_schedule_qs = SocketSchedule.objects.filter(device_id=device_id)
+                            if socket_schedule_qs.exists():
+                                socket_schedule_qs.delete()
 
                         # 如果有子设备,删除子设备和关联的场景数据
                         gateway_qs = GatewaySubDevice.objects.filter(device_id=device_id)
@@ -174,9 +189,9 @@ class GatewayDeviceView(View):
                             smart_scene_qs = SmartScene.objects.filter(device_id=device_id)
                         if smart_scene_qs.exists():
                             # 通知设备删除场景id
+                            smart_scene_info = smart_scene_qs.values('id')
                             serial_number = device_qs.first().serial_number
                             topic_name = SMART_SCENE_TOPIC.format(serial_number)
-                            smart_scene_info = smart_scene_qs.values('id')
                             for smart_scene in smart_scene_info:
                                 msg = {
                                     'smart_scene_delete': int(smart_scene['id'])
@@ -188,7 +203,7 @@ class GatewayDeviceView(View):
                                     return response.json(10044)
                                 time.sleep(0.3)
                             smart_scene_qs.delete()
-                        gateway_qs.delete()     # 删除子设备
+                        gateway_qs.delete()  # 删除子设备
                         scene_log_qs = SceneLog.objects.filter(device_id=device_id)
                         if scene_log_qs.exists():
                             scene_log_qs.delete()
@@ -243,6 +258,18 @@ class GatewayDeviceView(View):
             print(e)
             return response.json(177, repr(e))
 
+    @staticmethod
+    def reset_device(serial_number):
+        #  下发设备进行重置
+        LOGGER = logging.getLogger('info')
+        SOCKET_TOPIC_NAME = 'loocam/smart-socket/{}'  # 插座发布消息主题(因设备当前版本只能订阅一个主题)
+        topic_name = SOCKET_TOPIC_NAME.format(serial_number)
+        # 发布消息内容,重置设备
+        msg = {'type': 6, 'data': {'device_reset': 1}}
+        result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+        LOGGER.info('重置{}智能插座设备,发布MQTT消息结果{}'.format(serial_number, result))
+        return True
+
     @classmethod
     def gateway_device_list(cls, request_dict, response):
         """
@@ -287,8 +314,29 @@ class GatewayDeviceView(View):
                 'roomName': gateway_room_name,
                 'iot': iot_data,
                 'roomId': room_id,
-                'familyId': family_id
+                'familyId': family_id,
+                'power': 0,
+                'electricity': 0,
+                'countDownTime': 0,
+                'socketStatus': False,
+                'online': False,
+                'accumulatedTime': 0,
+                'start': False,
             }
+            if device_qs['device__Type'] == 201:
+                socket_info_qs = SocketInfo.objects.filter(device_id=device_id).values('online', 'type_switch',
+                                                                                       'status',
+                                                                                       'count_down_time', 'start')
+                if not socket_info_qs.exists():
+                    return response.json(173)
+                socket_data = cls.smart_socket(device_id, socket_info_qs)
+                gateway['power'] = socket_data['power']
+                gateway['electricity'] = socket_data['electricity']
+                gateway['countDownTime'] = socket_data['countDownTime']
+                gateway['accumulatedTime'] = socket_data['accumulatedTime']
+                gateway['socketStatus'] = socket_data['socketStatus']
+                gateway['online'] = socket_data['online']
+                gateway['start'] = socket_data['start']
             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')
 
@@ -331,6 +379,53 @@ class GatewayDeviceView(View):
             print(e.args)
             return response.json(500)
 
+    @classmethod
+    def smart_socket(cls, device_id, socket_info_qs):
+        """
+        查詢插座信息
+        """
+        nowTime = int(time.time())
+        today = datetime.date.today()
+        #  今天开始时间
+        today_start_time = int(time.mktime(time.strptime(str(today), '%Y-%m-%d')))
+        data = {
+            'power': 0,
+            'electricity': 0,
+            'countDownTime': 0,
+            'accumulatedTime': 0,
+            'socketStatus': False,
+            'online': False,
+            'start': False,
+        }
+        # 插座信息
+        socket_info_qs = socket_info_qs.filter(device_id=device_id).values('online', 'type_switch',
+                                                                           'status', 'count_down_time', 'start')
+        type_switch_list = [type_switch[v] for type_switch in socket_info_qs.values('type_switch') for v in type_switch]
+        #  判断开关类型 0:总开关,1:倒计时开关
+        if len(type_switch_list) == 2:
+            socket_info_qs = socket_info_qs.filter(type_switch=1)
+        else:
+            socket_info_qs = socket_info_qs.filter(type_switch=0)
+        # 插座信息
+        data['socketStatus'] = socket_info_qs[0]['status']
+        data['start'] = socket_info_qs[0]['start']
+        data['online'] = socket_info_qs[0]['online']
+        data['countDownTime'] = socket_info_qs[0]['count_down_time'] if socket_info_qs[0][
+            'count_down_time'] else 0
+        # 当前设备电量信息
+        socket_power_qs = SocketPowerStatistics.objects.filter(device_id=device_id, created_time__gte=today_start_time,
+                                                               created_time__lt=nowTime).values('accumulated_time',
+                                                                                                'power',
+                                                                                                'created_time',
+                                                                                                'electricity'). \
+            order_by('-created_time')
+        if not socket_power_qs.exists():
+            return data
+        data['power'] = socket_power_qs[0]['power']
+        data['electricity'] = socket_power_qs[0]['electricity'].quantize(Decimal("0.00"))
+        data['accumulatedTime'] = socket_power_qs[0]['accumulated_time']
+        return data
+
 #
 #                   ___====-_  _-====___
 #             _--^^^#####//      \\#####^^^--_

+ 812 - 0
Controller/SensorGateway/SmartSocketController.py

@@ -0,0 +1,812 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : SmartSocketController.py
+@Time    : 2023/3/17 11:52
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import calendar
+import datetime
+import logging
+import time
+from decimal import Decimal
+
+from dateutil.parser import parse
+from django.db import transaction
+from django.db.models import Sum, Count
+from django.http import QueryDict
+from django.views import View
+
+from Model.models import SocketInfo, SocketSchedule, Device_Info, SocketPowerStatistics, SceneLog, FamilyRoomDevice
+from Object.ResponseObject import ResponseObject
+from Object.utils import LocalDateTimeUtil
+from Service.CommonService import CommonService
+
+LOGGER = logging.getLogger('info')
+SOCKET_TOPIC_NAME = 'loocam/smart-socket/{}'  # 插座发布消息主题(因设备当前版本只能订阅一个主题)
+
+
+class SmartSocketView(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 delete(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        delete = QueryDict(request.body)
+        if not delete:
+            delete = request.GET
+        return self.validation(delete, request, operation)
+
+    def put(self, request, *args, **kwargs):
+        request.encoding = 'utf-8'
+        operation = kwargs.get('operation')
+        put = QueryDict(request.body)
+        return self.validation(put, request, operation)
+
+    def validation(self, request_dict, request, operation):
+        ResponseObject('cn')
+        if operation == 'savePowerStatistics':  # 保存电量上报统计
+            return self.save_power_statistics(request_dict, ResponseObject('cn'))
+        elif operation == 'reset':  # 设备复位
+            return self.socket_reset(request_dict, ResponseObject('cn'))
+        token_code, user_id, response = CommonService \
+            .verify_token_get_user_id(request_dict, request)
+        if token_code != 0:
+            return response.json(token_code)
+        if operation == 'saveSwitch':  # 添加插座开关
+            return self.save_switch(request_dict, response)
+        elif operation == 'saveCountDown':  # 添加插座倒计时
+            return self.save_count_down(request_dict, response)
+        elif operation == 'saveSchedule':  # 添加插座排程
+            return self.save_socket_schedule(request_dict, response)
+        elif operation == 'get-all-scene':  # 统计智能插座电量
+            return self.get_all_scene(request_dict, response)
+        elif operation == 'get-socket-schedule':  # 智能插座排程记录查询
+            return self.get_socket_schedule(request_dict, response)
+        elif operation == 'get-log':  # 智能插座开关日志记录查询
+            return self.get_log(request_dict, response)
+        elif operation == 'del-socket-schedule':  # 批量刪除排程
+            return self.del_socket_schedule(request_dict, response, user_id)
+        elif operation == 'get-unit-scene':  # 查詢設備每日/月用電量
+            return self.get_unit_scene(request_dict, response)
+        elif operation == 'get-schedule-data':  # 查询插座记录日期
+            return self.get_schedule_data(request_dict, response)
+        return response.json(404)
+
+    @classmethod
+    def socket_reset(cls, request_dict, response):
+        """
+        智能插座复位删除数据
+        """
+        try:
+            with transaction.atomic():
+                serial_number = request_dict.get('serialNumber', None)
+                if not serial_number:
+                    return response.json(444)
+                socket_info_qs = SocketInfo.objects.filter(serial_number=serial_number, type_switch=0)
+                if not socket_info_qs.exists():
+                    return response.json(173)
+                device_id = socket_info_qs.first().device_id
+                if socket_info_qs.first().status == 1:  # 设备电源开时 恢复为关闭状态
+                    socket_info_qs.update(status=0, updated_time=int(time.time()))
+                # 删除插座倒计时
+                SocketInfo.objects.filter(device_id=device_id).delete()
+                # 删除插座电量统计
+                SocketPowerStatistics.objects.filter(device_id=device_id).delete()
+                # 删除插座排程
+                SocketSchedule.objects.filter(device_id=device_id).delete()
+                # 删除插座开关日志
+                SceneLog.objects.filter(device_id=serial_number).delete()
+                # 删除设备管理家庭接口
+                FamilyRoomDevice.objects.filter(device_id=device_id).delete()
+                # 删除设备
+                Device_Info.objects.filter(id=device_id).delete()
+                LOGGER.info('智能插座{}设备已复位'.format(serial_number))
+                return response.json(0)
+        except Exception as e:
+            LOGGER.info('插座复位删除数据异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(177)
+
+    @classmethod
+    def save_power_statistics(cls, request_dict, response):
+        """
+        保存设备上报电量统计
+        """
+        try:
+            serial_number = request_dict.get('serialNumber', None)
+            watt = request_dict.get('electricity', 0.00)  # 功率
+            power = request_dict.get('power', 0.00)  # 负载功率
+            # 在线时长秒
+            accumulated_time = request_dict.get('accumulatedTime', None)
+            device_time = request_dict.get('deviceTime', None)
+            LOGGER.info('{}上报电量统计data:{}'.format(serial_number, request_dict))
+            if not all([serial_number, watt, power, accumulated_time, device_time]):
+                return response.json(444)
+            device_time = int(device_time)
+            watt = float(watt)
+            power = float(power)
+            accumulated_time = int(accumulated_time)
+            now_time = int(time.time())
+            start_time, end_time = LocalDateTimeUtil.get_today_date(True)
+            # 查询当前序列号当天是否有上传过电量统计
+            power_qs = SocketPowerStatistics.objects.filter(serial_number=serial_number,
+                                                            created_time__gt=start_time,
+                                                            created_time__lte=end_time)
+            data = {
+                'power': power,
+                'updated_time': now_time,
+                'watt': watt
+            }
+            if not power_qs.exists():  # 添加插座上报电量统计
+                socket_info_qs = SocketInfo.objects.filter(serial_number=serial_number).values('device_id')
+                if not socket_info_qs.exists():
+                    return response.json(173)
+                data['device_id'] = socket_info_qs[0]['device_id']
+                data['created_time'] = device_time
+                data['serial_number'] = serial_number
+                data['electricity'] = cls.calculated_power(watt, accumulated_time)
+                data['accumulated_time'] = accumulated_time
+                SocketPowerStatistics.objects.create(**data)
+                return response.json(0)
+            power_vo = power_qs.first()
+            # 累加在线时间目前是以分钟为单位
+            data['accumulated_time'] = power_vo.accumulated_time + accumulated_time
+            # kwh 千瓦时
+            kilowatt_hour = cls.calculated_power(watt, accumulated_time)
+            data['electricity'] = kilowatt_hour + float(power_vo.electricity)
+            # 所消耗累计功率
+            data['watt'] = float(power_vo.watt) + watt
+            # 更新当天电量统计
+            power_qs.update(**data)
+            return response.json(0)
+        except Exception as e:
+            LOGGER.info('智能插座电量存库异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(177)
+
+    @staticmethod
+    def calculated_power(watt, minute):
+        """
+        通过每分钟所消耗的功率(瓦)得到千瓦时kwh
+        """
+        if watt == 0 or watt < 0.1 or minute == 0:
+            return 0.00
+        hours = minute / 3600
+        kilowatt_hour = watt * hours / 1000
+        LOGGER.info('瓦计算得到千瓦时结果{}'.format(kilowatt_hour))
+        return kilowatt_hour
+
+    @staticmethod
+    def get_serial_number_by_device_id(deviceId):
+        """
+        根据设备ID获取序列号
+        """
+        device_info = Device_Info.objects.get(id=deviceId)
+        return device_info.serial_number
+
+    @classmethod
+    def save_switch(cls, request_dict, response):
+        """
+        添加开关
+        """
+        device_id = request_dict.get('deviceId', None)
+        status = request_dict.get('status', None)
+        if not all([device_id, status]):
+            return response.json(444)
+        serial_number = cls.get_serial_number_by_device_id(device_id)
+        # 保存数据库并下发MQTT消息到插座设备
+        result = cls.save_socket_switch(device_id, serial_number, int(status))
+        if not result:
+            return response.json(177)
+        return response.json(0)
+
+    @staticmethod
+    def save_socket_switch(device_id, serial_number, status, type_switch=0):
+        """
+        保存插座开关信息
+        @param device_id: 设备ID
+        @param serial_number: 序列号
+        @param status: 状态 0关,1开
+        @param type_switch: 0:总开关,1倒计时开关
+        @return: True | False
+        """
+        if not device_id:
+            return False
+        socket_info_qs = SocketInfo.objects.filter(device_id=device_id, type_switch=type_switch)
+        LOGGER.info('进入插座电源开关OR倒计时,类型:{}'.format(type_switch))
+        now_time = int(time.time())
+        try:
+            with transaction.atomic():
+                # 创建插座开关信息
+                if not socket_info_qs.exists():
+                    socket_dict = {"device_id": device_id,
+                                   "serial_number": serial_number,
+                                   "status": status,
+                                   "type_switch": type_switch,
+                                   "created_time": now_time,
+                                   "updated_time": now_time,
+                                   "online": True}
+                    SocketInfo.objects.create(**socket_dict)
+                    return True
+                if socket_info_qs.first().status != status:
+                    socket_info_qs.update(status=status, updated_time=now_time)
+                # 主题名称
+                topic_name = SOCKET_TOPIC_NAME.format(serial_number)
+                # 发布消息内容
+                msg = {'type': 1, 'data': {'deviceSwitch': status}}
+                result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+                LOGGER.info('智能插座开关设置发布MQTT消息结果{}'.format(result))
+                return True
+        except Exception as e:
+            LOGGER.info('智能插座异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
+    @classmethod
+    def save_count_down(cls, request_dict, response):
+        """
+        添加倒计时
+        """
+        device_id = request_dict.get('deviceId', None)
+        status = request_dict.get('status', None)
+        start = request_dict.get('start', None)
+        count_down_time = request_dict.get('countDownTime', None)
+        if not all([device_id, status, count_down_time]):
+            return response.json(444)
+        serial_number = cls.get_serial_number_by_device_id(device_id)
+        # 保存数据库并下发MQTT消息到插座设备
+        result = cls.save_socket_count_down(device_id, serial_number, int(status), int(start), int(count_down_time))
+        if not result:
+            return response.json(177)
+        return response.json(0)
+
+    @staticmethod
+    def save_socket_count_down(device_id, serial_number, status, start, count_down_time, type_switch=1):
+        """
+        保存插座倒计时信息
+        @param count_down_time: 倒计时时间戳
+        @param start: 是否启动倒计时 0:关闭,1:开始
+        @param device_id: 设备ID
+        @param serial_number: 序列号
+        @param status: 倒计时电源状态 0关,1开
+        @param type_switch: 0:总开关,1倒计时开关
+        @return:
+        """
+        if not device_id:
+            return False
+        socket_info_qs = SocketInfo.objects.filter(device_id=device_id, type_switch=type_switch)
+        now_time = int(time.time())
+        try:
+            with transaction.atomic():
+                # 创建插座倒计时信息
+                if not socket_info_qs.exists():
+                    socket_dict = {"device_id": device_id,
+                                   "serial_number": serial_number,
+                                   "status": status,
+                                   "type_switch": type_switch,
+                                   "created_time": now_time,
+                                   "updated_time": now_time,
+                                   "online": True,
+                                   "start": True if start == 1 else False,
+                                   "count_down_time": count_down_time}
+                    socket_info_qs = SocketInfo.objects.create(**socket_dict)
+                    count_down_id = socket_info_qs.id
+                else:
+                    socket_info_qs.update(status=status, count_down_time=count_down_time,
+                                          updated_time=now_time)
+                    count_down_id = socket_info_qs.first().id
+                # 主题名称
+                topic_name = SOCKET_TOPIC_NAME.format(serial_number)
+                # 发布消息内容
+                msg = {'type': 2,
+                       'data': {'powerType': status,
+                                'countDownId': count_down_id,
+                                'time': count_down_time,
+                                'start': start}}
+                result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+                LOGGER.info('智能插座倒计时发布MQTT消息结果{}'.format(result))
+                return True
+        except Exception as e:
+            LOGGER.info('智能插座异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
+    @classmethod
+    def save_socket_schedule(cls, request_dict, response):
+        """
+        插座添加排程
+        """
+        try:
+            device_id = request_dict.get('deviceId', None)
+            task_type = request_dict.get('timeType', None)
+            start_time = request_dict.get('startTime', None)
+            end_time = request_dict.get('endTime', 0)
+            repeat = request_dict.get('repeat', None)
+            task_id = request_dict.get('taskId', None)
+            device_switch = request_dict.get('deviceSwitch', None)
+            task_switch = request_dict.get('taskSwitch', None)
+            if not all([task_type, start_time, end_time, repeat, device_switch, task_switch]):
+                return response.json(444)
+            device_switch = int(device_switch)
+            task_switch = int(task_switch)
+            now_time = int(time.time())
+            task_type = int(task_type)
+            end_time = int(end_time) if task_type == 2 else 0
+            data = {'time_type': task_type, 'start_time': int(start_time), 'repeat': int(repeat),
+                    'switch_status': True if device_switch == 1 else False,
+                    'task_status': True if task_switch == 1 else False}
+            serial_number = cls.get_serial_number_by_device_id(device_id)
+            if task_id:  # 修改排程
+                task_id = int(task_id)
+                socket_schedule_qs = SocketSchedule.objects.filter(id=task_id)
+                if not socket_schedule_qs.exists():
+                    return response.json(174)
+                if end_time:
+                    data['end_time'] = end_time
+                data['updated_time'] = now_time
+                socket_schedule_qs.update(**data)
+            else:
+                # 查询是否已设置过当前排程
+                socket_s_qs = SocketSchedule.objects.filter(device_id=device_id,
+                                                            start_time=int(start_time),
+                                                            end_time=end_time,
+                                                            time_type=task_type)
+                if socket_s_qs.exists():
+                    return response.json(174)
+                schedule_count = SocketSchedule.objects.filter(device_id=device_id).count()
+                if schedule_count >= 30:
+                    return response.json(10061)
+                # 添加排程
+                data['device_id'] = device_id
+                data['end_time'] = end_time
+                data['serial_number'] = serial_number
+                data['updated_time'] = now_time
+                data['created_time'] = now_time
+                socket_schedule = SocketSchedule.objects.create(**data)
+                task_id = socket_schedule.id
+            # 将排程任务下发给设备
+            cls.send_socket_schedule(serial_number, task_id, task_type, int(start_time),
+                                     end_time, int(repeat), device_switch,
+                                     task_switch)
+            return response.json(0)
+        except Exception as e:
+            LOGGER.info('智能插座异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
+    @staticmethod
+    def send_socket_schedule(serial_number, task_id, time_type, start_time, end_time, repeat, device_switch,
+                             task_switch):
+        """
+        排程下发设备
+        @param serial_number: 序列号
+        @param task_id: 当前排程任务id
+        @param time_type: 任务类型 0:设定时间,1:设定时间段
+        @param start_time: 开启时间
+        @param end_time: 结束时间
+        @param repeat: 重复日期
+        @param device_switch: 任务执行后期望设备状态,0:关闭,1:开启
+        @param task_switch: 任务执行状态 0:不执行,1:执行
+        @return: True | False
+        """
+        msg = {
+            'type': 3,
+            'data': {'taskId': task_id, 'timeType': time_type,
+                     'startTime': start_time, 'endTime': end_time,
+                     'repeat': repeat,
+                     'deviceSwitch': device_switch,
+                     'taskSwitch': task_switch}
+        }
+        # 主题名称
+        topic_name = SOCKET_TOPIC_NAME.format(serial_number)
+        result = CommonService.req_publish_mqtt_msg(serial_number, topic_name, msg)
+        LOGGER.info('智能插座排程任务发布MQTT消息结果{}'.format(result))
+        return result
+
+    # 以下是查询智能插座接口
+    @staticmethod
+    def get_all_scene(request_dict, response):
+        """
+        统计智能插座电量
+        @request_dict serialNumber: 序列号
+        @request_dict unit: 时间单位
+        @param request_dict: 请求数据
+        @param response: 响应
+        @return: response
+        """
+        serial_number = request_dict.get('serialNumber', None)
+        # 确定是否会传值
+        if not all([serial_number]):
+            return response.json(444, {'error param': 'serialNumber'})
+        all_socket_power_qs = SocketPowerStatistics.objects.filter(serial_number=serial_number).values('electricity',
+                                                                                                       'accumulated_time',
+                                                                                                       'power',
+                                                                                                       'created_time'). \
+            order_by('-created_time')
+        if not all_socket_power_qs.exists():
+            return response.json(0, {})
+        try:
+            data = {}
+            # 设备累计电量
+            all_electricity = all_socket_power_qs.aggregate(total=Sum('electricity'))
+            data['electricityAll'] = all_electricity['total'].quantize(Decimal("0.00"))
+
+            # 本月电费
+            nowTime = int(time.time())
+            nowTime = CommonService.timestamp_to_str(nowTime)
+            year, month = str(nowTime).split('-')[0], str(nowTime).split('-')[1]
+            end = calendar.monthrange(int(year), int(month))[1]
+            startTime_now = parse('%s-%s-01 00:00:00' % (year, month))
+            endTime_now = parse('%s-%s-%s 23:59:59' % (year, month, end))
+            startTime_now = CommonService.str_to_timestamp(str(startTime_now))
+            endTime_now = CommonService.str_to_timestamp(str(endTime_now))
+            electricity = all_socket_power_qs.filter(created_time__gte=startTime_now,
+                                                     created_time__lt=endTime_now).aggregate(
+                total=Sum('electricity'))
+            if electricity['total'] != None:
+                data['electricityMonth'] = electricity['total'].quantize(Decimal("0.00"))
+            else:
+                data['electricityMonth'] = 0
+
+            # 获取当前日期
+            nowTime = int(time.time())
+            today = datetime.date.today()
+            #  今天开始时间
+            today_start_time = int(time.mktime(time.strptime(str(today), '%Y-%m-%d')))
+            today_socket_power_qs = all_socket_power_qs.filter(created_time__gte=today_start_time,
+                                                               created_time__lt=nowTime).values('electricity',
+                                                                                                'accumulated_time',
+                                                                                                'power',
+                                                                                                'created_time')
+            # 当天使用电量
+            data['electricityToday'] = today_socket_power_qs[0]['electricity'].quantize(
+                Decimal("0.00")) if today_socket_power_qs.exists() else 0
+            # 当天累计时长
+            data['accumulated_time'] = today_socket_power_qs[0][
+                'accumulated_time'] if today_socket_power_qs.exists() else 0
+            # 当前功率
+            data['power'] = today_socket_power_qs[0]['power'] if today_socket_power_qs.exists() else 0
+
+            # 昨天使用电量
+            yesterday = today - datetime.timedelta(days=1)
+            # 昨天开始时间戳
+            yesterday_start_time = int(time.mktime(time.strptime(str(yesterday), '%Y-%m-%d')))
+            # 昨天结束时间戳
+            yesterday_end_time = int(time.mktime(time.strptime(str(today), '%Y-%m-%d'))) - 1
+            socket_qs = all_socket_power_qs.filter(created_time__gte=yesterday_start_time,
+                                                   created_time__lt=yesterday_end_time).values('electricity')
+            if socket_qs.exists():
+                data['electricityYesterday'] = socket_qs[0]['electricity'].quantize(Decimal("0.00"))
+            else:
+                data['electricityYesterday'] = 0
+            return response.json(0, data)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_socket_schedule(request_dict, response):
+        """
+        智能插座排程记录查询
+        @param request_dict: 请求参数
+        @request_dict page: 页数
+        @request_dict size: 条数
+        @request_dict serialNumber: 设备序列号
+        @param response: 响应对象
+        @return: response
+        """
+        page = request_dict.get('pageNo', None)
+        size = request_dict.get('pageSize', None)
+        serial_number = request_dict.get('serialNumber', None)
+
+        if not all([page, size, serial_number]):
+            return response.json(444)
+        page, size = int(page), int(size)
+        socket_schedule_qs = SocketSchedule.objects.filter(serial_number=serial_number).values('switch_status',
+                                                                                               'start_time',
+                                                                                               'end_time',
+                                                                                               'repeat',
+                                                                                               'task_status',
+                                                                                               'time_type',
+                                                                                               'created_time',
+                                                                                               'updated_time',
+                                                                                               'device_id',
+                                                                                               'id').order_by(
+            '-created_time')[(page - 1) * size:page * size]
+        if not socket_schedule_qs.exists():
+            return response.json(0, [])
+        try:
+            schedule_list = []
+            for socket_schedule in socket_schedule_qs:
+                schedule_list.append({
+                    'taskId': socket_schedule['id'],
+                    'deviceID': socket_schedule['device_id'],
+                    'serialNumber': serial_number,
+                    'timeType': socket_schedule['time_type'],
+                    'startTime': socket_schedule['start_time'],
+                    'endTime': socket_schedule['end_time'],
+                    'switchStatus': socket_schedule['switch_status'],
+                    'taskStatus': socket_schedule['task_status'],
+                    # 进制
+                    'repeat': socket_schedule['repeat'],
+                })
+            return response.json(0, schedule_list)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_log(request_dict, response):
+        """
+        智能插座开关日志记录查询
+        @param request_dict: 请求参数
+        @request_dict page: 页数
+        @request_dict size: 条数
+        @request_dict serialNumber: 设备序列号
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param response: 响应对象
+        @return: response
+        # 日誌擦護用序列號查詢
+        """
+        page = request_dict.get('page', None)
+        size = request_dict.get('size', None)
+        serial_number = request_dict.get('serialNumber', None)
+        startTime = request_dict.get('startTime', None)
+        endTime = request_dict.get('endTime', None)
+        if not all([page, size, serial_number]):
+            return response.json(444, {'errno: page or size or serial_number'})
+        page, size = int(page), int(size)
+
+        try:
+            if startTime is None and endTime is None:
+                scene_log_qs = SceneLog.objects.filter(device_id=serial_number).values('tasks', 'status',
+                                                                                       'created_time').order_by(
+                    '-created_time')[(page - 1) * size:page * size]
+                if not scene_log_qs.exists():
+                    return response.json(0, [])
+            else:
+                scene_log_qs = SceneLog.objects.filter(device_id=serial_number, created_time__gte=startTime,
+                                                       created_time__lt=endTime).values('tasks', 'status',
+                                                                                        'created_time').order_by(
+                    '-created_time')[(page - 1) * size:page * size]
+                if not scene_log_qs.exists():
+                    return response.json(0, [])
+            log_list = []
+            for scene_log in scene_log_qs:
+                data = {
+                    'serialNumber': serial_number,
+                    'tasks': scene_log['tasks'] if scene_log['tasks'] else '',
+                    'status': scene_log['status'],
+                    'createdTime': scene_log['created_time'],
+                }
+                log_list.append(data)
+            return response.json(0, log_list)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @classmethod
+    def splittings_time(cls, startTime, endTime, unit):
+        """
+        根據時間單位分割時間
+        """
+        diction = {}
+        time_list = []
+        # 开始时间
+        startTime = CommonService.timestamp_to_str(int(startTime))
+        endTime = CommonService.timestamp_to_str(int(endTime))
+        startYear, startMonth, startDay = \
+            str(startTime).split('-')[0], str(startTime).split('-')[1], str(startTime).split('-')[2]
+        # 结束时间
+        endYear, endMonth, endDay = str(endTime).split('-')[0], str(endTime).split('-')[1], str(endTime).split('-')[
+            2]
+        if unit == 'week' or unit == 'month':
+            startTime = parse('%s-%s-%s' % (startYear, startMonth, startDay))
+            endTime = parse('%s-%s-%s' % (endYear, endMonth, endDay))
+            time_list = CommonService.cutting_time(startTime, endTime, time_unit='day')
+        elif unit == 'year':
+            startYear, startMonth = int(startTime.split('-')[0]), int(startTime.split('-')[1])
+            endYear, endMonth = int(endTime.split('-')[0]), int(endTime.split('-')[1])
+            # 获取下个月的第一天
+            if startMonth == 12:
+                startYear += 1
+                startMonth = 1
+            else:
+                startMonth += 1
+            #  计算(开始月,结束月)
+            startTime = parse('%s-%s-01 00:00:00' % (str(startYear), str(startMonth)))
+            # 获取上个月最后一天
+            if endMonth == 1:
+                endYear -= 1
+                endMonth = 12
+            else:
+                endMonth -= 1
+            endDay = calendar.monthrange(endYear, endMonth)[1]
+            endTime = parse('%s-%s-%s 23:59:59' % (str(endYear), str(endMonth), endDay))
+            time_list = CommonService.cutting_time(startTime, endTime, time_unit='month')
+            #  开始月的时间区间
+            startMonth_time = CommonService.str_to_timestamp(str(startTime))
+            #  结束月的时间区间
+            endMonth_time = CommonService.str_to_timestamp(str(endTime))
+            diction['startMonth_time'] = startMonth_time
+            diction['endMonth_time'] = endMonth_time
+        diction['time_list'] = time_list
+        return diction
+
+    @staticmethod
+    def del_socket_schedule(request_dict, response, user_id):
+        """
+        批量刪除排程
+        @param request_dict: 请求参数
+        @param user_id: 用戶user_id
+        @request_dict ids: 排程id
+        @request_dict serialNumber: 设备序列号
+        @param response: 响应对象
+        @return: response
+        """
+        try:
+            with transaction.atomic():
+                ids = request_dict.get('ids', None)
+                serial_number = request_dict.get('serialNumber', None)
+                if not all({ids, serial_number}):
+                    return response.json(444, {'error param': 'id or serialNumber'})
+                device_info_qs = Device_Info.objects.filter(userID_id=user_id, serial_number=serial_number)
+                if not device_info_qs.exists():
+                    return response.json(173)
+                socket_schedule_qs = SocketSchedule.objects.filter(id__in=ids.split(','))
+                if not socket_schedule_qs.exists():
+                    return response.json(173)
+                # 发布MQTT消息通知设备删除排程任务
+                for val in socket_schedule_qs:
+                    if val.task_status:
+                        switch_status = 1 if val.switch_status else 0
+                        result = SmartSocketView.send_socket_schedule(val.serial_number, val.id, val.time_type,
+                                                                      val.start_time, val.end_time,
+                                                                      val.repeat, switch_status, 0)
+                        LOGGER.info('删除排程发布结果:{}'.format(result))
+                socket_schedule_qs.delete()
+                return response.json(0)
+        except Exception as e:
+            LOGGER.info('插座排程删除数据异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(177)
+
+    @classmethod
+    def get_unit_scene(cls, request_dict, response):
+        """
+        查詢設備每日/月用電量
+        @request_dict serialNumber: 设备序列号
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serialNumber', None)
+        unit = request_dict.get('unit', None)
+        startTime = request_dict.get('startTime', None)
+        endTime = request_dict.get('endTime', None)
+        if not all([unit, startTime, endTime, serial_number]):
+            return response.json(500, {'errno': 'unit or startTime or endTime or serialNumber'})
+        try:
+            socket_power_qs = SocketPowerStatistics.objects.filter(serial_number=serial_number). \
+                values('electricity', 'accumulated_time', 'power', 'created_time')
+            if not socket_power_qs.exists():
+                return response.json(0, {})
+            #  时间和功耗
+            data = {}
+            new_list = []
+            socket_qs = socket_power_qs.filter(created_time__gte=startTime, created_time__lt=endTime).aggregate(
+                electricity=Sum('electricity'), accumulatedTime=Sum('accumulated_time'))
+            data['electricityTimeAll'] = Decimal(socket_qs['electricity']).quantize(Decimal("0.00")) if socket_qs[
+                'electricity'] else 0
+            data['accumulatedTimeAll'] = socket_qs['accumulatedTime'] if socket_qs['accumulatedTime'] else 0
+
+            #  分割时间
+            diction = cls.splittings_time(startTime, endTime, unit)
+            if unit == 'year':
+                # 开始月
+                socket_qs = socket_power_qs.filter(created_time__gte=startTime,
+                                                   created_time__lt=diction['startMonth_time']).aggregate(
+                    electricity=Sum('electricity'), accumulatedTime=Sum('accumulated_time'))
+                electricity = Decimal(socket_qs['electricity']).quantize(Decimal("0.00")) if socket_qs[
+                    'electricity'] else 0
+                # 標記月日
+                subscript = cls.get_subscript(unit, startTime)
+                new_list.append({
+                    'subscript': subscript,
+                    'time': int(startTime),
+                    'electricity': round(electricity, 1)
+                })
+            # 查询天月
+            for item in diction['time_list']:
+                socket_qs = socket_power_qs.filter(created_time__gte=item[0],
+                                                   created_time__lt=item[1]).aggregate(
+                    electricity=Sum('electricity'))
+                electricity = Decimal(socket_qs['electricity']).quantize(Decimal("0.00")) if socket_qs[
+                    'electricity'] else 0
+                # 標記月日
+                subscript = cls.get_subscript(unit, item[0])
+                new_list.append({
+                    'subscript': subscript,
+                    'time': item[0],
+                    'electricity': round(electricity, 1)
+                })
+
+            if unit == 'year':
+                # 结束月
+                socket_qs = socket_power_qs.filter(created_time__gte=diction['endMonth_time'],
+                                                   created_time__lt=endTime).aggregate(
+                    electricity=Sum('electricity'))
+                electricity = Decimal(socket_qs['electricity']).quantize(Decimal("0.00")) if socket_qs[
+                    'electricity'] else 0
+                # 標記月日
+                subscript = cls.get_subscript(unit, endTime)
+                new_list.append({
+                    'subscript': subscript,
+                    'time': int(endTime),
+                    'electricity': round(electricity, 1)
+                })
+            #  降序排序
+            # new_list.sort(key=lambda k: k["time"], reverse=True)
+            data['week_or_month_or_year'] = new_list
+            return response.json(0, data)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @classmethod
+    def get_subscript(cls, unit, time_stamp):
+        """
+        標記月日
+        @param unit: 时间单位
+        @param time_stamp: 时间戳
+        @return: subscript
+        """
+        time_tuple = time.localtime(int(time_stamp))  # 把时间戳转换成时间元祖
+        time_tuple = time.strftime('%Y-%m-%d-%w', time_tuple)  # 把时间元祖转换成格式化好的时间
+        if unit == 'week' or unit == 'year':
+            if unit == 'week':
+                subscript = int(str(time_tuple).split('-')[3])
+                return subscript
+            else:
+                Year, Month, Day = int(time_tuple.split('-')[0]), int(time_tuple.split('-')[1]), int(
+                    time_tuple.split('-')[2])
+                subscript = datetime.date(Year, Month, Day).month
+                subscript -= 1
+                return subscript
+        else:
+            Year, Month, Day = int(time_tuple.split('-')[0]), int(time_tuple.split('-')[1]), int(
+                time_tuple.split('-')[2])
+            subscript = datetime.date(Year, Month, Day).day
+            subscript -= 1
+            return subscript
+
+    @staticmethod
+    def get_schedule_data(request_dict, response):
+        """
+        查询插座日志记录日期
+        @request_dict serialNumber: 设备序列号
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @return: response
+        """
+        serial_number = request_dict.get('serialNumber', None)
+        if not serial_number:
+            return response.json(444, {'error': 'serialNumber'})
+
+        try:
+            socket_schedule_qs = SceneLog.objects.extra(
+                select={'date': "FROM_UNIXTIME(created_time,'%%Y-%%m-%%d')"}).values('date').filter(
+                device_id=serial_number).annotate(count=Count('created_time')).order_by('-date')[:31]
+            schedule_date_list = []
+            for socket_schedule in socket_schedule_qs:
+                schedule_date_list.append({
+                    'timestamp': CommonService.str_to_timestamp(socket_schedule['date'], '%Y-%m-%d'),
+                    'count': socket_schedule['count'],
+                    'format': socket_schedule['date']
+                })
+            return response.json(0, schedule_date_list)
+        except Exception as e:
+            return response.json(500, repr(e))

+ 182 - 55
Controller/SerialNumberController.py

@@ -7,8 +7,9 @@ import requests
 from django.db import transaction
 from django.views import View
 
-from Ansjer.config import CRCKey, CONFIG_INFO, CONFIG_TEST, CONFIG_US, \
-    CONFIG_CN, USED_SERIAL_REDIS_LIST, UNUSED_SERIAL_REDIS_LIST, SERVER_DOMAIN_US, REGION_ID_LIST
+from Ansjer.config import CRCKey, CONFIG_INFO, CONFIG_US, \
+    CONFIG_CN, USED_SERIAL_REDIS_LIST, UNUSED_SERIAL_REDIS_LIST, SERVER_DOMAIN_US, REGION_ID_LIST, SERVER_DOMAIN_TEST, \
+    SERVER_DOMAIN_LIST, SERVER_DOMAIN_CN, SERVER_DOMAIN_EUR, RESET_REGION_ID_SERIAL_REDIS_LIST
 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, \
@@ -46,6 +47,8 @@ class SerialNumberView(View):
             return self.do_attach_uid(request_dict, response, request)
         elif operation == 'detachUID':  # 解绑uid
             return self.do_detach_uid(request, request_dict, response)
+        elif operation == 'get-uid':  # app获取uid
+            return self.get_uid(request_dict, response, request)
         elif operation == 'create':  # 创建序列号
             return self.do_create(request_dict, response)
         elif operation == 'getUID':  # 根据序列号获取uid
@@ -60,6 +63,10 @@ class SerialNumberView(View):
             return self.reset_region_id(request_dict, response)
         elif operation == 'get-status':  # 重置地区id
             return self.check_serial_status(request_dict, response)
+        elif operation == 'getUidRegion':  # 根据序列号获取uid地区
+            return self.get_uid_region(request_dict, response)
+        elif operation == 'getGlobalUidRegion':  # 获取序列号在全球服绑定uid的地区
+            return self.get_global_uid_region(request_dict, response)
         else:
             return response.json(414)
 
@@ -94,15 +101,15 @@ class SerialNumberView(View):
 
     def do_attach_uid(self, request_dict, response, request):
         serial_number = request_dict.get('serial_number', None)
-        # token = request_dict.get('token', None)
-        # time_stamp = request_dict.get('time_stamp', None)
-        #
-        # if not all([serial_number, token, time_stamp]):
-        #     return response.json(444)
-        #
-        # # 时间戳token校验
-        # if not CommonService.check_time_stamp_token(token, time_stamp):
-        #     return response.json(13)
+        token = request_dict.get('token', None)
+        time_stamp = request_dict.get('time_stamp', None)
+
+        if not all([serial_number, token, time_stamp]):
+            return response.json(444)
+
+        # 时间戳token校验
+        if not CommonService.check_time_stamp_token(token, time_stamp):
+            return response.json(13)
 
         now_time = int(time.time())
         serial = serial_number[0:6]
@@ -119,6 +126,12 @@ class SerialNumberView(View):
             company_secret = 'ZsKWcxdD'
 
         try:
+            # 判断序列号是否刚解绑,刚解绑1分钟内不能进行绑定
+            redisObj = RedisObject()
+            unused_serial_redis_list = redisObj.lrange(UNUSED_SERIAL_REDIS_LIST, 0, -1)
+            unused_serial_redis_list = [str(i, 'utf-8') for i in unused_serial_redis_list]
+            if serial in unused_serial_redis_list:
+                return response.json(5)
             # 判断序列号是否已和企业关联
             company_serial_qs = CompanySerialModel.objects.filter(company__secret=company_secret, serial_number=serial)
             if not company_serial_qs.exists():
@@ -130,7 +143,6 @@ class SerialNumberView(View):
             elif company_serial.status == 1:  # 绑定uid
                 # redis加锁,防止同一个序列号重复绑定
                 key = serial + 'do_attach_uid'
-                redisObj = RedisObject()
                 isLock = redisObj.CONN.setnx(key, 1)
                 redisObj.CONN.expire(key, 60)
                 if not isLock:
@@ -309,24 +321,23 @@ class SerialNumberView(View):
         @param redis_obj: redis对象
         @return:
         """
-        # 测试服不处理
-        if CONFIG_INFO != CONFIG_TEST:
-            redis_obj.rpush(USED_SERIAL_REDIS_LIST, serial)
-
-            vpg_id = 1
-            if CONFIG_INFO == 'us':
-                vpg_id = 3
-            elif CONFIG_INFO == 'eur':
-                vpg_id = 4
-            p2p_type = int(p2p_type)
-
-            # 剩余uid数量少于2000邮件提醒
-            unused_uid_count = UIDModel.objects.filter(vpg_id=vpg_id, p2p_type=p2p_type, status=0).count()
-            warning_count = 2000
-            if unused_uid_count < warning_count:
-                platform = '尚云' if p2p_type == 1 else 'tutk'
-                email_content = '{}服{]的uid数量少于{}个,请及时处理'.format(CONFIG_INFO, platform, warning_count)
-                S3Email().faEmail(email_content, 'servers@ansjer.com')
+        # 写入已使用序列号redis列表
+        redis_obj.rpush(USED_SERIAL_REDIS_LIST, serial)
+
+        vpg_id = 1
+        if CONFIG_INFO == 'us':
+            vpg_id = 3
+        elif CONFIG_INFO == 'eur':
+            vpg_id = 4
+        p2p_type = int(p2p_type)
+
+        # 剩余uid数量少于2000邮件提醒
+        unused_uid_count = UIDModel.objects.filter(vpg_id=vpg_id, p2p_type=p2p_type, status=0).count()
+        warning_count = 2000
+        if unused_uid_count < warning_count:
+            platform = '尚云' if p2p_type == 1 else 'tutk'
+            email_content = '{}服{]的uid数量少于{}个,请及时处理'.format(CONFIG_INFO, platform, warning_count)
+            S3Email().faEmail(email_content, 'servers@ansjer.com')
 
     @staticmethod
     def log_and_send_email(request, company_serial_id, serial, now_time):
@@ -339,12 +350,12 @@ class SerialNumberView(View):
         """
         send_email = S3Email()
         try:
-            if CONFIG_INFO == 'cn':
+            if CONFIG_INFO != 'us':
                 return {}
             # 判断当前序列号是否绑定UID
             uid_serial_qs = UIDCompanySerialModel.objects.filter(company_serial_id=company_serial_id)
             if uid_serial_qs.exists():
-                email_content = '序列号已占用当前数据库已绑定UID: {}'.format(serial)
+                email_content = '{}序列号已占用当前数据库已绑定UID: {}'.format(CONFIG_INFO, serial)
                 send_email.faEmail(email_content, 'servers@ansjer.com')
                 send_email.faEmail(email_content, 'antony@ansjer.com')
                 return {}
@@ -352,7 +363,7 @@ class SerialNumberView(View):
             response = requests.post("https://www.zositechc.cn/serialNumber/get-status",
                                      data={'serial_number': serial}, timeout=3)
             ip = CommonService.get_ip_address(request)
-            operation = '序列号占用:{}'.format(serial)
+            operation = '{}序列号占用:{}'.format(CONFIG_INFO, serial)
             log = {
                 'ip': ip,
                 'user_id': 1,
@@ -394,7 +405,7 @@ class SerialNumberView(View):
                     # 成功后 修改企业序列号状态为2(已分配)
                     CompanySerialModel.objects.filter(id=company_serial_id) \
                         .update(status=2, update_time=now_time)
-                    email_content = '序列号已占用已将国内UID数据同步完成: {}'.format(serial)
+                    email_content = '{}序列号已占用已将国内UID数据同步完成: {}'.format(CONFIG_INFO, serial)
                     send_email.faEmail(email_content, 'servers@ansjer.com')
                     send_email.faEmail(email_content, 'antony@ansjer.com')
                     operation += '同步成功'
@@ -441,7 +452,8 @@ class SerialNumberView(View):
         else:
             return response.json(444)
 
-    def do_detach_uid(self, request, request_dict, response):
+    @staticmethod
+    def do_detach_uid(request, request_dict, response):
         token = request_dict.get('token', None)
         time_stamp = request_dict.get('time_stamp', None)
         serial_number = request_dict.get('serial_number', None)
@@ -467,7 +479,12 @@ class SerialNumberView(View):
         if not uid_serial_qs.exists():
             return response.json(173)
         uid_serial = uid_serial_qs[0]
+        # 判断序列号是否刚绑定uid,刚绑定需要过1分钟才能解绑
         redisObj = RedisObject()
+        used_serial_redis_list = redisObj.lrange(USED_SERIAL_REDIS_LIST, 0, -1)
+        used_serial_redis_list = [str(i, 'utf-8') for i in used_serial_redis_list]
+        if serial in used_serial_redis_list:
+            return response.json(5)
         try:
             with transaction.atomic():
                 uid = uid_serial.uid.uid
@@ -497,25 +514,17 @@ class SerialNumberView(View):
                 ExperienceAiModel.objects.filter(uid=uid).delete()
                 AiService.objects.filter(uid=uid).delete()
 
-                if CONFIG_INFO != CONFIG_TEST:  # 不为测试服,则序列号写入redis列表
-                    redisObj.rpush(UNUSED_SERIAL_REDIS_LIST, serial)
+                # 写入未使用序列号redis列表
+                redisObj.rpush(UNUSED_SERIAL_REDIS_LIST, serial)
 
-                UIDModel.objects.filter(uid=uid).update(status=0, mac='')  # 重置uid的使用状态为未使用
-                uid_serial.delete()
-
-                # 重置region_id
+                # 重置region_id,不为美洲服,则写入redis列表
                 if CONFIG_INFO == CONFIG_US:
                     DeviceDomainRegionModel.objects.filter(serial_number=serial).update(region_id=0)
                 else:
-                    try:
-                        url = SERVER_DOMAIN_US + 'serialNumber/resetRegionId'
-                        data = {'serial_number': serial}
-                        r = requests.post(url, data, timeout=3)
-                        assert r.status_code == 200
-                        res = r.json()
-                        assert res['result_code'] == 0
-                    except (TimeoutError, AssertionError):
-                        return response.json(5)
+                    redisObj.rpush(RESET_REGION_ID_SERIAL_REDIS_LIST, serial)
+
+                UIDModel.objects.filter(uid=uid).update(status=0, mac='')  # 重置uid的使用状态为未使用
+                uid_serial.delete()
 
                 # 记录操作日志
                 ip = CommonService.get_ip_address(request)
@@ -532,8 +541,64 @@ class SerialNumberView(View):
                 LogModel.objects.create(**log)
             return response.json(0)
         except Exception as e:
-            djangoLogger = logging.getLogger('django')
-            djangoLogger.exception(repr(e))
+            # 记录操作日志
+            ip = CommonService.get_ip_address(request)
+            content = json.loads(json.dumps(request_dict))
+            log = {
+                'ip': ip,
+                'user_id': 1,
+                'status': 200,
+                'time': now_time,
+                'content': json.dumps(content) + '异常:{}'.format(repr(e)),
+                'url': 'serialNumber/detachUID',
+                'operation': '序列号{}解绑uid{}异常'.format(serial, uid),
+            }
+            LogModel.objects.create(**log)
+            return response.json(176, str(e))
+
+    def get_uid(self, request_dict, response, request):
+        """
+        app获取序列号
+        @param request_dict:
+        @param response:
+        @param request:
+        @return:
+        """
+        token = request_dict.get('token', None)
+        time_stamp = request_dict.get('time_stamp', None)
+        company_secret = request_dict.get('company_id', None)
+        serial_number = request_dict.get('serial_number', None)
+
+        if not all([token, time_stamp, company_secret, serial_number]):
+            return response.json(444)
+
+        # 时间戳token校验
+        if not CommonService.check_time_stamp_token(token, time_stamp):
+            return response.json(13)
+
+        now_time = int(time.time())
+        serial = serial_number[0:6]
+
+        # 判断序列号是否已和企业关联
+        company_serial_qs = CompanySerialModel.objects.filter(company__secret=company_secret, serial_number=serial)
+        if not company_serial_qs.exists():
+            return response.json(173)
+        company_serial = company_serial_qs[0]
+
+        try:
+            if company_serial.status == 0 or company_serial.status == 1:  # 未使用
+                return response.json(173)
+            elif company_serial.status == 2:  # 返回uid
+                res = self.get_uid_info_by_serial(company_serial.id)
+                return response.json(0, res)
+            elif company_serial.status == 3:  # 已占用
+                res = self.log_and_send_email(request, company_serial.id, serial_number, now_time)
+                if not res:
+                    return response.json(10042)
+                return response.json(0, self.get_uid_info_by_serial(company_serial.id))
+        except Exception as e:
+            error_logger = logging.getLogger('django')
+            error_logger.exception(repr(e))
             return response.json(176, str(e))
 
     @staticmethod
@@ -640,7 +705,7 @@ class SerialNumberView(View):
     @staticmethod
     def get_domain(request_dict, response):
         """
-        获取域名
+        设备获取域名
         @param request_dict: 请求参数
         @param response: 响应对象
         @request_dict serial_number: 序列号
@@ -665,9 +730,12 @@ class SerialNumberView(View):
             if not device_domain_region_qs.exists():
                 return response.json(173)
             region_id = device_domain_region_qs[0]['region_id']
-            region_qs = RegionModel.objects.filter(id=region_id).values('api')
+            region_qs = RegionModel.objects.filter(id=region_id).values('api', 'push_api')
+            if not region_qs.exists():
+                return response.json(173)
             res = {
-                'api': region_qs[0]['api']
+                'api': region_qs[0]['api'],
+                'push_api': region_qs[0]['push_api']
             }
             return response.json(0, res)
         except Exception as e:
@@ -691,3 +759,62 @@ class SerialNumberView(View):
             return response.json(0)
         except Exception as e:
             return response.json(500, repr(e))
+
+    @staticmethod
+    def get_uid_region(request_dict, response):
+        """
+        根据序列号获取uid地区
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @request_dict serial_number: 序列号
+        @return: response
+        """
+        serial_number = request_dict.get('serial_number', None)
+        if not serial_number:
+            return response(444)
+        try:
+            serial_number = serial_number[:6]
+            uid_company_serial_qs = UIDCompanySerialModel.objects.filter(
+                company_serial__serial_number=serial_number).values('uid__uid')
+            res = []
+            for item in uid_company_serial_qs:
+                res.append({'uid': item['uid__uid']})
+            return response.json(0, res)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_global_uid_region(request_dict, response):
+        """
+        获取序列号在全球服绑定uid的地区
+        @param request_dict: 请求参数
+        @param response: 响应对象
+        @request_dict serial_number: 序列号
+        @return: response
+        """
+        orders_domain_name_list = SERVER_DOMAIN_LIST
+        if SERVER_DOMAIN_TEST in orders_domain_name_list:
+            orders_domain_name_list.remove(SERVER_DOMAIN_TEST)
+        uid_list = []
+        try:
+            for orders_domain_name in orders_domain_name_list:
+                url = orders_domain_name + 'serialNumber/getUidRegion'
+                res = requests.post(url=url, data=request_dict)
+                result = res.json()
+                if result['result_code'] != 0:
+                    return response.json(result['result_code'])
+                if orders_domain_name == SERVER_DOMAIN_CN:
+                    for item in result['result']:
+                        item['region'] = 1
+                        uid_list.append(item)
+                elif orders_domain_name == SERVER_DOMAIN_US:
+                    for item in result['result']:
+                        item['region'] = 3
+                        uid_list.append(item)
+                elif orders_domain_name == SERVER_DOMAIN_EUR:
+                    for item in result['result']:
+                        item['region'] = 4
+                        uid_list.append(item)
+            return response.json(0, uid_list)
+        except Exception as e:
+            return response.json(500, repr(e))

+ 96 - 12
Controller/TestApi.py

@@ -47,7 +47,7 @@ from django.contrib.auth.hashers import make_password  # 对密码加密模块
 from Ansjer.config import OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET, AWS_ACCESS_KEY_ID, \
     AWS_SECRET_ACCESS_KEY, SERVER_TYPE, AWS_SES_ACCESS_REGION
 from Model.models import Order_Model, Store_Meal, DeviceLogModel, VodBucketModel, \
-    TestSerialRepetition, UIDCompanySerialModel, CompanySerialModel, LogModel
+    TestSerialRepetition, TestDeviceFindSerial, UIDCompanySerialModel, CompanySerialModel, LogModel
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -162,29 +162,41 @@ class testView(View):
             return self.generate_video(request_dict, response)
         elif operation == 'serial-repetition':  # 用与测试序列号重复接口
             response = ResponseObject('cn')
-            return self.serial_repetition_test(request_dict, response)
+            return response.json(475)
+        elif operation == 'v2/serial-repetition':  # 用与测试序列号重复接口
+            response = ResponseObject('cn')
+            return self.serial_repetition_test_v2(request_dict, response)
         elif operation == 'getSerialNumberInfo':  # 序列号信息查询
             return self.getSerialNumberInfo(request_dict, response)
         elif operation == 'get-serial-details':  # 序列号信息查询
             return self.get_serial_details(request_dict, response, request)
+        elif operation == 'find_device_serial':  # 查找设备序列号接口:306低功耗无Wi-Fi产品
+            return self.find_device_serial(request_dict, response)
         else:
             return 123
 
     @classmethod
-    def serial_repetition_test(cls, request_dict, response):
+    def serial_repetition_test_v2(cls, request_dict, response):
         try:
             serial_no = request_dict.get('serialNo', None)
+            phone_model = request_dict.get('phoneModel', None)
             if not serial_no:
                 return response.json(444)
             with transaction.atomic():
                 first_serial = serial_no[:6]
                 first_serial_qs = TestSerialRepetition.objects.filter(serial_number__icontains=first_serial)
                 if first_serial_qs.exists():
-                    return response.json(174)
+                    result = {'serialNumber': first_serial_qs.first().serial_number,
+                              'phoneModel': first_serial_qs.first().phone_model,
+                              'createdTime': first_serial_qs.first().created_time}
+                    return response.json(174, result)
+
                 serial_qs = TestSerialRepetition.objects.filter(serial_number=serial_no)
                 if not serial_qs.exists():
                     n_time = int(time.time())
                     params = {'serial_number': serial_no, 'created_time': n_time}
+                    if phone_model:
+                        params['phone_model'] = phone_model
                     TestSerialRepetition.objects.create(**params)
                     return response.json(0)
                 else:
@@ -193,6 +205,30 @@ class testView(View):
             logging.info('异常错误,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
             return response.json(178, e)
 
+    @classmethod
+    def serial_repetition_test(cls, request_dict, response):
+        return response.json()
+        # try:
+        #     serial_no = request_dict.get('serialNo', None)
+        #     if not serial_no:
+        #         return response.json(444)
+        #     with transaction.atomic():
+        #         first_serial = serial_no[:6]
+        #         first_serial_qs = TestSerialRepetition.objects.filter(serial_number__icontains=first_serial)
+        #         if first_serial_qs.exists():
+        #             return response.json(174)
+        #         serial_qs = TestSerialRepetition.objects.filter(serial_number=serial_no)
+        #         if not serial_qs.exists():
+        #             n_time = int(time.time())
+        #             params = {'serial_number': serial_no, 'created_time': n_time}
+        #             TestSerialRepetition.objects.create(**params)
+        #             return response.json(0)
+        #         else:
+        #             return response.json(174)
+        # except Exception as e:
+        #     logging.info('异常错误,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+        #     return response.json(178, e)
+
     @classmethod
     def generate_video(cls, request_dict, response):
         # 设计抽取图片规则通过消息随机还是时间随机,调试copy S3对象查询是否携带失效时间
@@ -896,7 +932,7 @@ class testView(View):
                 if company_serial_qs[0]['status'] == 1:
                     data['status'] = '已分配'
                 if company_serial_qs[0]['status'] == 2:
-                    data['status'] = '绑定uid'
+                    data['status'] = '绑定uid'
                 if company_serial_qs[0]['status'] == 3:
                     data['status'] = '已占用'
                 return response.json(0, data)
@@ -940,23 +976,27 @@ class testView(View):
             if not serial_number:
                 return response.json(0)
             results_data = []
-            if not CONFIG_INFO == 'cn':
+            if CONFIG_INFO != 'cn':
                 return response.json(0, results_data)
             local_response = cls.getSerialNumberInfo(request_dict, response)
             res = json.loads(local_response.content)
             res['result']['server'] = 1
+            res['result']['serverName'] = '中国服'
+            res['result']['domainName'] = 'https://www.zositechc.cn'
             results_data.append(res['result'])
             res1 = requests.post("http://www.dvema.com/testApi/getSerialNumberInfo",
                                  data={'serialNumber': serial_number}, timeout=3)
             results1 = json.loads(res1.text)
             results1['result']['server'] = 2
+            results1['result']['serverName'] = '美国服'
+            results1['result']['domainName'] = 'https://www.dvema.com'
             results_data.append(results1['result'])
-            res2 = requests.post("https://api.zositeche.com/testApi/getSerialNumberInfo",
-                                 data={'serialNumber': serial_number}, timeout=3)
-            results2 = json.loads(res2.text)
-            results2['result']['server'] = 3
-            results2['result']['status'] = '已分配'
-            results_data.append(results2['result'])
+            # res2 = requests.post("https://api.zositeche.com/testApi/getSerialNumberInfo",
+            #                      data={'serialNumber': serial_number}, timeout=5)
+            # results2 = {}
+            # results2['result']['server'] = 3
+            # results2['result']['status'] = '已分配'
+            # results_data.append(results2['result'])
             is_ok = True
             operation = ''
             status_log = ''
@@ -986,3 +1026,47 @@ class testView(View):
             LOGGER.info('异常详情,errLine:{}, errMsg:{}'
                         .format(e.__traceback__.tb_lineno, repr(e)))
             return response.json(500)
+
+    @classmethod
+    def find_device_serial(cls, request_dict, response):
+        try:
+            firmware_time_code_no = request_dict.get('firmwareTimeCode', None)
+            function_type_str = request_dict.get('functionType', None)
+            serial_no = request_dict.get('serialNo', None)
+            time_stamp = request_dict.get('timeStamp', None)
+            sign = request_dict.get('sign', None)
+            if not CommonService.check_time_stamp_token(sign, time_stamp):
+                return response.json(13)
+            if not function_type_str:
+                return response.json(444)
+            with transaction.atomic():
+                first_firmwares_qs = TestDeviceFindSerial.objects.filter(firmware_time_code=firmware_time_code_no)
+                if function_type_str == 'device_save_serial':  # 设备上报序列号绑定固件码  get_device_serial
+                    if not all([firmware_time_code_no, serial_no]):
+                        return response.json(444)
+                    if first_firmwares_qs.exists():
+                        return response.json(174)
+                    nowtime = int(time.time())
+                    params = {'firmware_time_code': firmware_time_code_no,
+                              'serial_number': serial_no,
+                              'created_time': nowtime}
+                    TestDeviceFindSerial.objects.create(**params)
+                    return response.json(0)
+                elif function_type_str == 'get_device-serial':  # 根据固件码获取序列号
+                    if not firmware_time_code_no:
+                        return response.json(444)
+                    if first_firmwares_qs.exists():
+                        result = {'Id': first_firmwares_qs.first().id,
+                                  'firmwareTimeCode': firmware_time_code_no,
+                                  'serialNumber': first_firmwares_qs.first().serial_number,
+                                  'createdTime': first_firmwares_qs.first().created_time}
+                        print('返回结果 : %s', result)
+                        return response.json(0, result)
+                    else:
+                        return response.json(173)
+                else:
+                    return response.json(444)
+
+        except Exception as e:
+            LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(178, e)

+ 0 - 4
Controller/UIDPreview.py

@@ -79,8 +79,6 @@ class UIDPreview(View):
             bucket = oss2.Bucket(auth, 'oss-cn-hongkong.aliyuncs.com', 'statres')
 
             dvqs = Device_Info.objects.filter(UID=uid, userID_id=userID)
-            # redisObj = RedisObject(db=8)
-            # redisObj.del_data(key='uid_qs_'+userID)
             upqs = UID_Preview.objects.filter(uid=uid, channel=channel)
             if dvqs.exists():
                 if upqs.exists():
@@ -147,8 +145,6 @@ class UIDPreview(View):
         own_perm = ModelService.check_perm(userID, 20)
         if own_perm is True:
             id = request_dict.get('id')
-            # redisObj = RedisObject(db=8)
-            # redisObj.del_data(key='uid_qs_' + userID)
             UID_Preview.objects.filter(id=id).delete()
             return response.json(0)
         else:

+ 0 - 2
Controller/UidSetController.py

@@ -132,8 +132,6 @@ class UidSetView(View):
         if own_perm is True:
             uid = request_dict.getlist('uid', None)
             id_list = request_dict.get('id_list', None)
-            # redisObj = RedisObject(db=8)
-            # redisObj.del_data(key='uid_qs_' + userID)
             # 删除回滚
             with transaction.atomic():  # 上下文格式,可以在python代码的任何位置使用
                 val = 1

+ 4 - 16
Controller/UserController.py

@@ -2326,18 +2326,6 @@ class InitInfoView(View):
         lang = request_dict.get('lang', '')  # 语言区域
         now_time = int(time.time())
         if all([token_val, push_type, appBundleId, userID]):
-            push_type = int(push_type)
-            if push_type == 0:
-                if appBundleId not in APNS_CONFIG.keys():
-                    return response.json(904)
-            elif push_type == 1:
-                if appBundleId not in FCM_CONFIG.keys():
-                    return response.json(904)
-            elif push_type == 2:
-                if appBundleId not in JPUSH_CONFIG.keys():
-                    return response.json(904)
-            else:
-                return response.json(444, 'push_type')
             self.save_push_config(userID, appBundleId, push_type, token_val, m_code, lang, tz)
             if m_code:
                 # 获取设备推送状态
@@ -3226,9 +3214,11 @@ class alexaUidView(TemplateView):
 
         if sid != 'admin' or sst != 'admin':
             return response.json(107)
-        uid_qs = Device_Info.objects.filter(userID_id=userID, isExist=1).values('UID', 'NickName', 'View_Password')
+        uid_qs = Device_Info.objects.filter(userID_id=userID, isExist=1).values('UID', 'NickName', 'View_Password',
+                                                                                'userID__region_country')
         if not uid_qs.exists():
             return response.json(107)
+        country_qs = CountryModel.objects.filter(id=uid_qs[0]['userID__region_country']).values('region__continent_code')
 
         try:
             uid_dict = {}
@@ -3249,9 +3239,7 @@ class alexaUidView(TemplateView):
                 uid = us['uid']
                 channel = us['channel']
                 # 设备alexa区域
-                region_alexa = us['region_alexa']
-                if region_alexa == '':
-                    region_alexa = 'EN'
+                region_alexa = country_qs[0]['region__continent_code'] if country_qs.exists() else 'EN'
 
                 # 多通道设备获取通道名
                 if channel > 1:

+ 1 - 1
Controller/shareUserPermission.py

@@ -103,7 +103,7 @@ class searchUserView(View):
                 device_user_count = qs.count()
                 device_user_res = qs[(page - 1) * line:page * line]
                 sqlDict = CommonService.qs_to_dict(device_user_res)
-                redisObj = RedisObject(db=3)
+                redisObj = RedisObject()
                 for k, v in enumerate(sqlDict["datas"]):
                     for val in device_user_res:
                         if v['pk'] == val.userID:

+ 140 - 3
Model/models.py

@@ -347,6 +347,7 @@ class EquipmentInfoMonday(models.Model):
                                                   u'702:摄像头休眠,703:摄像头唤醒,'
                                                   u'704:电量过低)')
     status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态(0,1)')
+    answer_status = models.BooleanField(default=False, verbose_name='接听状态')  # 0: 未接听,1: 已接听
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     event_time = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receive_time = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
@@ -378,6 +379,7 @@ class EquipmentInfoTuesday(models.Model):
                                                   u'702:摄像头休眠,703:摄像头唤醒,'
                                                   u'704:电量过低)')
     status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态(0,1)')
+    answer_status = models.BooleanField(default=False, verbose_name='接听状态')  # 0: 未接听,1: 已接听
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     event_time = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receive_time = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
@@ -409,6 +411,7 @@ class EquipmentInfoWednesday(models.Model):
                                                   u'702:摄像头休眠,703:摄像头唤醒,'
                                                   u'704:电量过低)')
     status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态(0,1)')
+    answer_status = models.BooleanField(default=False, verbose_name='接听状态')  # 0: 未接听,1: 已接听
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     event_time = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receive_time = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
@@ -440,6 +443,7 @@ class EquipmentInfoThursday(models.Model):
                                                   u'702:摄像头休眠,703:摄像头唤醒,'
                                                   u'704:电量过低)')
     status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态(0,1)')
+    answer_status = models.BooleanField(default=False, verbose_name='接听状态')  # 0: 未接听,1: 已接听
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     event_time = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receive_time = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
@@ -471,6 +475,7 @@ class EquipmentInfoFriday(models.Model):
                                                   u'702:摄像头休眠,703:摄像头唤醒,'
                                                   u'704:电量过低)')
     status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态(0,1)')
+    answer_status = models.BooleanField(default=False, verbose_name='接听状态')  # 0: 未接听,1: 已接听
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     event_time = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receive_time = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
@@ -502,6 +507,7 @@ class EquipmentInfoSaturday(models.Model):
                                                   u'702:摄像头休眠,703:摄像头唤醒,'
                                                   u'704:电量过低)')
     status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态(0,1)')
+    answer_status = models.BooleanField(default=False, verbose_name='接听状态')  # 0: 未接听,1: 已接听
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     event_time = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receive_time = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
@@ -533,6 +539,7 @@ class EquipmentInfoSunday(models.Model):
                                                   u'702:摄像头休眠,703:摄像头唤醒,'
                                                   u'704:电量过低)')
     status = models.BooleanField(blank=True, default=False, verbose_name=u'事件状态(0,1)')
+    answer_status = models.BooleanField(default=False, verbose_name='接听状态')  # 0: 未接听,1: 已接听
     alarm = models.CharField(blank=True, max_length=256, verbose_name=u'报警信息')
     event_time = models.CharField(blank=True, db_index=True, default='', max_length=16, verbose_name=u'设备报警时间')
     receive_time = models.CharField(blank=True, default='', max_length=16, verbose_name=u'接收到报警时间')
@@ -1377,7 +1384,8 @@ class UidPushModel(models.Model):
     uid_set = models.ForeignKey(UidSetModel, to_field='id', on_delete=models.CASCADE)
     appBundleId = models.CharField(blank=True, max_length=32, verbose_name=u'appID')
     app_type = models.IntegerField(default=0, verbose_name=u'app类型 1:ios,2:安卓')
-    push_type = models.IntegerField(default=0, verbose_name=u'推送类型')  # 0: apns, 1: 安卓gcm, 2: 极光, 3:华为, 4:小米, 5:vivo, 6:oppo, 7:魅族
+    push_type = models.IntegerField(default=0,
+                                    verbose_name=u'推送类型')  # 0: apns, 1: 安卓gcm, 2: 极光, 3:华为, 4:小米, 5:vivo, 6:oppo, 7:魅族
     token_val = models.CharField(default='', max_length=500, verbose_name=u'设备验证令牌')
     m_code = models.CharField(default='', max_length=64, verbose_name='手机唯一标识')
     addTime = models.IntegerField(verbose_name='添加时间', default=0)
@@ -1397,7 +1405,8 @@ class GatewayPush(models.Model):
     user_id = models.CharField(default='', max_length=32, db_index=True, verbose_name=u'用户id')
     app_bundle_id = models.CharField(default='', max_length=32, verbose_name=u'app包id')
     app_type = models.IntegerField(default=0, verbose_name=u'app类型')  # 1: ios, 2: 安卓
-    push_type = models.IntegerField(default=0, verbose_name=u'推送类型')  # 0: apns, 1: 安卓gcm, 2: 极光, 3:华为, 4:小米, 5:vivo, 6:oppo, 7:魅族
+    push_type = models.IntegerField(default=0,
+                                    verbose_name=u'推送类型')  # 0: apns, 1: 安卓gcm, 2: 极光, 3:华为, 4:小米, 5:vivo, 6:oppo, 7:魅族
     token_val = models.CharField(default='', max_length=500, verbose_name=u'设备验证令牌')
     m_code = models.CharField(default='', max_length=64, db_index=True, verbose_name='手机唯一标识')
     lang = models.CharField(default='en', max_length=8, verbose_name='推送语言')
@@ -1993,6 +2002,7 @@ class RegionModel(models.Model):
     api = models.CharField(max_length=50, default='', verbose_name='域名')
     zosi_api = models.CharField(max_length=50, default='', verbose_name='周视域名')
     loocam_api = models.CharField(max_length=50, default='', verbose_name='录看域名')
+    neutral_api = models.CharField(max_length=50, default='', verbose_name='中性域名')
     push_api = models.CharField(max_length=50, default='', verbose_name='推送域名')
 
     class Meta:
@@ -2132,6 +2142,7 @@ class CountryModel(models.Model):
     region = models.ForeignKey(RegionModel, to_field='id', on_delete=models.DO_NOTHING, verbose_name='关联区域表')
     country_code = models.CharField(max_length=2, default='', verbose_name='国家iso2代码')
     country_name = models.CharField(max_length=20, default='', verbose_name='国家名')
+    international_area_code = models.IntegerField(default=0, verbose_name='国际区号')
 
     class Meta:
         db_table = 'tb_country'
@@ -2994,12 +3005,63 @@ class UnicomFlowPush(models.Model):
         app_label = "PushModel"
 
 
+class DeviceAppScenario(models.Model):
+    id = models.AutoField(primary_key=True)
+    # 0:用作显示banner图使用,1:店铺,2:照看长辈,3:看护儿童,4:逗宠专属
+    type = models.SmallIntegerField(default=0, verbose_name='场景类型')
+    sort = models.SmallIntegerField(default=0, verbose_name=u'排序,越小越靠前')
+    cver_url = models.CharField(max_length=128, default='', verbose_name='封面图地址')
+    banner_url = models.CharField(max_length=128, default='', verbose_name='横幅图片地址')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='修改时间')
+
+    class Meta:
+        db_table = 'device_app_scenario'
+        verbose_name = '设备应用场景'
+        verbose_name_plural = verbose_name
+
+
+class DeviceScenarioLangInfo(models.Model):
+    id = models.AutoField(primary_key=True)
+    name = models.CharField(max_length=32, default='', verbose_name='场景内容')
+    content = models.CharField(max_length=100, default='', verbose_name='场景内容')
+    scenario_id = models.IntegerField(default=0, verbose_name=u'应用场景id')
+    lang = models.CharField(default='', max_length=20, db_index=True, verbose_name='语言/国家')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='修改时间')
+
+    class Meta:
+        db_table = 'device_scenario_lang_info'
+        verbose_name = '设备场景语言信息'
+        verbose_name_plural = verbose_name
+
+
+class DeviceAlgorithmScenario(models.Model):
+    id = models.AutoField(primary_key=True)
+    algorithm_id = models.IntegerField(default=0, db_index=True, verbose_name='算法id')
+    scenario_id = models.IntegerField(default=0, db_index=True, verbose_name='场景id')
+    sort = models.IntegerField(default=99, verbose_name=u'排序,越小越靠前')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='修改时间')
+
+    class Meta:
+        db_table = 'device_algorithm_scenario'
+        verbose_name = '设备算法关联应用场景'
+        verbose_name_plural = verbose_name
+
+
 class DeviceAlgorithmType(models.Model):
     id = models.AutoField(primary_key=True)
-    # 0:移动侦测,1:人形检测,2:挥手识别,3:人脸检测,4:异声感知,5:车辆检测,6:宠物检测,7:绊线入侵,8:离岗检测,9:徘徊检测
+    # 0:移动侦测,1:人形检测,2:挥手识别,3:人脸检测,4:异声感知,5:车辆检测,7:宠物检测,6:哭声检测,8:徘徊检测
+    # 9:区域闯入,10:区域闯出,11:长时间无人检测,12:往来检测,13:云相册
     type = models.SmallIntegerField(default=0, verbose_name='算法类型')
     memory = models.CharField(max_length=32, default='', verbose_name='所需内存')
     down_count = models.IntegerField(default=0, verbose_name='下载次数')
+    # 0:默认,1:HOT,2:Beta
+    tag = models.SmallIntegerField(default=0, verbose_name='标签')
+    # 0:免费,1:限时免费,2:付费
+    status = models.SmallIntegerField(default=0, verbose_name='算法使用状态')
+    expire_time = models.IntegerField(verbose_name='限时免费到期时间', default=0)
     sort = models.IntegerField(default=0, verbose_name=u'排序,越小越靠前')
     basic_function = models.TextField(blank=True, default='', verbose_name=u'基础功能(json格式)')
     image_url = models.CharField(max_length=255, default='', verbose_name='图片地址')
@@ -3034,6 +3096,7 @@ class DeviceAlgorithmExplain(models.Model):
                                        verbose_name=u'关联算法类型')
     title = models.CharField(max_length=32, default='', verbose_name='标题')
     subtitle = models.CharField(max_length=100, default='', verbose_name='副标题')
+    price = models.DecimalField(default=0, max_digits=10, decimal_places=2, verbose_name='价格')
     introduction = models.TextField(blank=True, default='', verbose_name='功能介绍')
     install_explain = models.TextField(blank=True, default='', verbose_name=u'安装说明')
     concerning = models.CharField(blank=True, max_length=64, default='', verbose_name=u'关于(文本标题)')
@@ -3366,9 +3429,83 @@ class TestSerialRepetition(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='自增id')
     serial_number = models.CharField(blank=True, unique=True, db_index=True, max_length=20, default='',
                                      verbose_name='序列号')
+    phone_model = models.CharField(max_length=64, default='', verbose_name='手机型号')
     created_time = models.IntegerField(default=0, verbose_name='创建时间')
 
     class Meta:
         db_table = 'test_serial_repetition'
         verbose_name = '测试序列号重复问题'
         verbose_name_plural = verbose_name
+
+
+class TestDeviceFindSerial(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    serial_number = models.CharField(blank=True, db_index=True, max_length=20, default='',
+                                     verbose_name='序列号')
+    firmware_time_code = models.CharField(max_length=128, unique=True, default='', verbose_name='PC固件码+时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'test_device_find_serial'
+        verbose_name = '查找设备序列号'
+        verbose_name_plural = verbose_name
+
+
+class SocketPowerStatistics(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    device_id = models.CharField(max_length=32, default='', verbose_name='设备id')
+    serial_number = models.CharField(db_index=True, max_length=20, default='',
+                                     verbose_name='序列号')
+    electricity = models.DecimalField(default=0, max_digits=10, decimal_places=6, verbose_name='设备当日用电KWh')
+    # 设备根据策略上报的w值,然后当日存在数据则累加
+    watt = models.DecimalField(default=0, max_digits=10, decimal_places=2, verbose_name='每分钟消耗功率(瓦)')
+    power = models.DecimalField(default=0, max_digits=10, decimal_places=2, verbose_name='负载功率w')
+    accumulated_time = models.SmallIntegerField(default=0, verbose_name='当天累计时长(分钟)')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 's_socket_power_statistics'
+        verbose_name = '插座电量统计'
+        verbose_name_plural = verbose_name
+
+
+class SocketInfo(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    device_id = models.CharField(max_length=32, default='', verbose_name='设备id')
+    serial_number = models.CharField(db_index=True, max_length=20,
+                                     verbose_name='序列号')
+    online = models.BooleanField(default=False, verbose_name='在线状态False:不在线,True:在线')
+    type_switch = models.SmallIntegerField(default=0,
+                                           verbose_name='开关类型 0:总开关,1:倒计时开关')
+    status = models.BooleanField(default=False, verbose_name='开关状态 0:关闭,1:开启')
+    start = models.BooleanField(default=False, verbose_name='倒计时状态 0:关闭,1:开启')
+    count_down_time = models.IntegerField(default=0, verbose_name='倒计时时间戳')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 's_socket_info'
+        verbose_name = '插座信息'
+        verbose_name_plural = verbose_name
+
+
+class SocketSchedule(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    device_id = models.CharField(max_length=32, default='', verbose_name='设备id')
+    serial_number = models.CharField(db_index=True, max_length=20, default='',
+                                     verbose_name='序列号')
+    time_type = models.SmallIntegerField(default=0, verbose_name='排查时间类型 1:按时间 2:按时间段划分')
+    switch_status = models.BooleanField(default=False, verbose_name='开关状态 0:关闭,1:开启')
+    task_status = models.BooleanField(default=False, verbose_name='任务状态状态 0:关闭,1:启动')
+    start_time = models.IntegerField(default=0, verbose_name='开始时间')
+    end_time = models.IntegerField(default=0, verbose_name='结束时间')
+    repeat = models.SmallIntegerField(default=0,
+                                      verbose_name='重复周期用数值表示 设备转二进制例127则二进制1111111')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 's_socket_schedule'
+        verbose_name = '插座排程'
+        verbose_name_plural = verbose_name

+ 47 - 0
Object/AWS/AWSIoTDataPlaneUtil.py

@@ -0,0 +1,47 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : AWSIoTDataPlaneUtil.py
+@Time    : 2023/4/13 16:43
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+@Document: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/iot-data.html#iotdataplane
+"""
+import json
+import logging
+
+import boto3
+
+LOGGER = logging.getLogger('info')
+
+
+class AWSIoTDataPlaneService:
+    def __init__(self, aws_access_key_id, secret_access_key, region_name):
+        self.client = boto3.client(
+            'iot-data',
+            aws_access_key_id=aws_access_key_id,
+            aws_secret_access_key=secret_access_key,
+            region_name=region_name
+        )
+
+    def update_thing_shadow(self, thing_name, data, shadow_name=None):
+        """
+        更新指定事物的影子
+        @param thing_name: 物品名称
+        @param data: 更新数据
+        @param shadow_name: 自定义影子名称(使用经典影子可不填)
+        @return: 更新状态
+        """
+        try:
+            params = {
+                'thingName': thing_name,
+                'payload': json.dumps(data)
+            }
+            if shadow_name:
+                params['shadowName'] = shadow_name
+            response = self.client.update_thing_shadow(**params)
+            assert response['ResponseMetadata']['HTTPStatusCode'] == 200
+            return True
+        except Exception as e:
+            LOGGER.info('更新设备影子异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False

+ 3 - 25
Object/RedisObject.py

@@ -1,34 +1,12 @@
-#!/usr/bin/env python3  
-# -*- coding: utf-8 -*-  
-"""
-@Copyright (C) ansjer cop Video Technology Co.,Ltd.All rights reserved.
-@AUTHOR: ASJRD018
-@NAME: AnsjerOA
-@software: PyCharm
-@DATE: 2018/8/8 17:00
-@Version: python3.6
-@MODIFY DECORD:ansjer dev
-@file: RedisObject.py
-@Contact: chanjunkai@163.com
-"""
 import redis
-
 from Ansjer.config import SERVER_HOST
-from Ansjer.config import SERVER_TYPE
-
-# SERVER_HOST = '192.168.136.45'
-
-'''
-db=3  -> 统计在线人数用
-'''
+# 本地调试把注释打开
+# SERVER_HOST = '127.0.0.1'
 
 
 class RedisObject:
 
-    def __init__(self, db=0,SERVER_HOST = SERVER_HOST):
-        # if db == 3:
-        #     if SERVER_TYPE != 'Ansjer.formal_settings':
-        #         db = 4
+    def __init__(self, db=0):
         self.POOL = redis.ConnectionPool(host=SERVER_HOST, port=6379, db=db)
         self.CONN = redis.Redis(connection_pool=self.POOL)
 

+ 4 - 2
Object/ResponseObject.py

@@ -1,5 +1,5 @@
-from django.shortcuts import HttpResponse
 import simplejson as json
+from django.shortcuts import HttpResponse
 
 
 class ResponseObject(object):
@@ -123,6 +123,7 @@ class ResponseObject(object):
             10058: 'Default family cannot be deleted',
             10059: 'Order deactivation failure',
             10060: 'This device has purchased foreign cloud storage package, so it cannot buy domestic cloud storage package',
+            10061: 'Add the limit reached',
         }
         data_cn = {
             0: '成功',
@@ -236,6 +237,7 @@ class ResponseObject(object):
             10058: '默认家庭不能删除',
             10059: '订单停用失败',
             10060: '此设备已购买过国外云存套餐,无法购买国内云存套餐',
+            10061: '添加已达到上限',
         }
 
         msg = data_cn if self.lang == 'cn' or self.lang == 'zh-Hans' or self.lang == 'zh-Hant' else data_en
@@ -258,4 +260,4 @@ class ResponseObject(object):
         if res is None:
             res = {}
         result = self.formal(code, res)
-        return HttpResponse(result, content_type='application/json,charset=utf-8')
+        return HttpResponse(result)

+ 29 - 0
Service/CommonService.py

@@ -645,6 +645,35 @@ GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
             time_list = [time_tuple]
         return time_list
 
+    @staticmethod
+    def cutting_time_stamp(start_time, end_time):
+        """
+        按天切割时间段
+        @param start_time: 开始时间
+        @param end_time: 结束时间
+        @return: time_list 切割后的时间列表
+        """
+
+        time_list = []
+        while True:
+            mid_time = datetime.datetime(start_time.year, start_time.month, start_time.day)+relativedelta(days=1)
+            if mid_time < end_time:
+                time_tuple = (CommonService.str_to_timestamp(start_time.strftime('%Y-%m-%d %H:%M:%S')),
+                              CommonService.str_to_timestamp(mid_time.strftime('%Y-%m-%d %H:%M:%S')))
+                time_list.append(time_tuple)
+                start_time = mid_time
+            else:
+                time_tuple = (CommonService.str_to_timestamp(start_time.strftime('%Y-%m-%d %H:%M:%S')),
+                              CommonService.str_to_timestamp(end_time.strftime('%Y-%m-%d %H:%M:%S')))
+                if time_tuple not in time_list:
+                    time_list.append(time_tuple)
+                break
+        if not time_list:
+            time_tuple = (CommonService.str_to_timestamp(start_time.strftime('%Y-%m-%d %H:%M:%S')),
+                          CommonService.str_to_timestamp(end_time.strftime('%Y-%m-%d %H:%M:%S')))
+            time_list = [time_tuple]
+        return time_list
+
     @staticmethod
     def get_domain_name():
         """

+ 4 - 3
Service/EquipmentInfoService.py

@@ -191,7 +191,7 @@ class EquipmentInfoService:
         @return: qs_page 遍历后的设备信息结果集
         """
         equipment_info_qs = equipment_info_qs.values('id', 'device_uid', 'device_nick_name', 'channel', 'event_type',
-                                                     'status', 'alarm',
+                                                     'status', 'answer_status', 'alarm',
                                                      'event_time', 'receive_time', 'is_st', 'add_time',
                                                      'storage_location', 'border_coords', 'tab_val')
 
@@ -319,6 +319,7 @@ class EquipmentInfoService:
         """
         获取设备算法组合类型
         51:移动侦测,52:传感器报警,53:影像遗失,54:PIR,55:门磁报警,56:外部发报,57:人型报警(提示:有人出现),58:车型,59:宠物,60:人脸,61:异响,
+        62:区域闯入,63:区域闯出,64:长时间无人检测,65:长时间无人检测
         0:代表空字符,702:摄像头休眠,703:摄像头唤醒,704:电量过低
         AWS AI识别 1:人形,2:车型,3:宠物,4:包裹。云端AI类型
         @param event_type:
@@ -329,7 +330,7 @@ class EquipmentInfoService:
             res_type = cls.is_type_exist(event_type)
             if res_type == 0:
                 return types
-            combo_types = [51, 57, 58, 60, 59, 61]
+            combo_types = [51, 57, 58, 60, 59, 61, 62, 63, 64, 65]
             event_type = str(event_type)
             len_type = len(event_type)
             for i in range(0, len_type):
@@ -364,7 +365,7 @@ class EquipmentInfoService:
         """
         arr_list = []
         event_arr = []
-        resource_list = [1, 2, 4, 8, 16, 32]
+        resource_list = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
         for i in range(2, len(resource_list) + 1):
             arr_list += list(itertools.combinations(resource_list, i))  # 表示从 [1,2,3,4] 中选出 3个元素的组合情况
         for i in arr_list:

+ 1 - 0
Service/TemplateService.py

@@ -8,6 +8,7 @@ class TemplateService:
             'paymentCycle/cancelPayCycle',
             'payCycle/paypalCycleNotify',
             'payCycle/paypalCycleReturn',
+            'account/oneClickLogin',
         ]
         return api_list
 

+ 3 - 1
Service/VodHlsService.py

@@ -90,13 +90,15 @@ class SplitVodHlsObject:
             vod_hls_sun = VodHlsSun.objects.filter(pk=-1)
             start_time = datetime.datetime.fromtimestamp(int(start_time))
             end_time = datetime.datetime.fromtimestamp(int(end_time))
-            time_list = CommonService.cutting_time(start_time, end_time, 'day')
+            time_list = CommonService.cutting_time_stamp(start_time, end_time)
             day_list = []
+            type_list = kwargs.get('type_list')
             for time_item in time_list:
                 week = datetime.datetime.fromtimestamp(int(time_item[0])).isoweekday()
                 if week not in day_list:
                     day_list.append(week)
             for week in day_list:
+                kwargs['type_list'] = type_list
                 if week == 1:
                     kwargs = self.vod_query_param(week, **kwargs)
                     vod_hls_mon = VodHlsMon.objects.filter(**kwargs)